1. Introduction
Fhlintstone is a Java code generator to support HL7 FHIR developers using the popular HAPI FHIR framework. Based on one or multiple NPM Packages containing the various definitions, it can be used to
-
generate Java enums for ValueSets
-
generate Java classes to implement custom resource and extension classes for StructureDefinitions and
-
facilitate handling profiles and extensions by providing builders tailored to the specific FHIR adaptations described by the package contents.
If you are a Java developer tasked with developing a HL7 FHIR application that is based on HAPI FHIR (or you are considering HAPI FHIR as a base of your implementation), Fhlintstone might be able to save you a lot of time by automating the rather tedious task of generating Java enums and classes that correspond to the Implementation Guide you probably have to adhere to and the profiles contained within.
2. Prerequisites
In order to use Fhlintstone, you need one or more FHIR NPM Packages that contain the definitions of the objects you want to generate code for. Not only that, but you also need to understand the contents of the package and possibly the relations to other packages. Fhlintstone is a sophisticated tool in some ways, but it is not intelligent - it requires clear directions in the form of a configuration that you have to provide. Fhlintstone is not designed to support the interactive exploration of FHIR NPM package contents - there are other tools out there that are much more suitable for this.
Note that you currently have to provide NPM packages that contain Snapshot statements. Fhlintstone is currently not able to work with packages that only contain Differential statements (see also Limitations).
You also will need to provide all relevant dependencies of the NPM packages, up to and including the HL7 base package. Fhlintstone will check the NPM package manifests and warn you about missing packages, but it currently will not attempt to download these packages automatically. Also note that not all dependencies are stated explicitly: It is not uncommon not to add a dependency to a package that contains a CodeSystem that is being referred to. You will have to resolve these dependencies manually in order for Fhlintstone to be able to work with the package contents, although Fhlintstone will at least notify you about the missing resources.
You can either use Fhlintstone from the command line or integrate it into your Maven build process. You will need a Java Runtime Enviroment version 21 or higher to run Fhlintstone. The Maven integration has been tested with version 3.9.
Please check the list of limitations to ensure that you won’t be surprised by one of Fhlintstone’s current (or maybe even permanent) limitations.
3. Usage
3.1. General Principles
Fhlintstone uses a common configuration structure for both the Maven integration and the command line interface. The configuration consists of the following sections:
-
general settings,
-
a list of one or multiple FHIR NPM Package files,
-
a list of ValueSet mappings and
-
a list of StructureDefinition mappings.
Either (or both) of the mapping lists may be empty, i.e. it is possible to generate only ValueSet enums or only StructureDefinition classes. Each mapping entry specifies both the source object (i.e. the ValueSet or the StructureDefinition) and the name of the target type (enum or class). Fhlintstone will not attempt to automatically generate Java type names from the FHIR definitions since that will usually lead to some near-illegible type names.
3.1.1. General Settings
The general section provides the following options:
| Option | Description | Required | Values |
|---|---|---|---|
|
The FHIR version (or release) to use. |
yes |
R4, R4B, R5 (see Limitations) |
|
The path to write the generated sources to. |
yes |
|
|
The Java namespace (package name) that will be used for all generated objects that do not have an individual namespace assigned. |
no |
3.1.2. NPM Package Files
The NPM package files are listed by name only; currently there are no further package-level configuration options.
| Option | Description | Required | Values |
|---|---|---|---|
|
The name (and optional path) to the NPM package file. |
yes |
3.1.3. ValueSet Settings
To generate a Java enum type for a ValueSet, an entry with the following options must be added to the configuration:
| Option | Description | Required | Values |
|---|---|---|---|
|
The URI identifying the ValueSet. |
yes |
|
|
The Java namespace (package name) that will be used for the enum. If not specified, the |
no |
|
|
The name of the Java type to generate. |
yes |
3.2. StructureDefinition Settings
To generate a Java class type for a StructureDefinition, an entry with the following options must be added to the configuration:
| Option | Description | Required | Values |
|---|---|---|---|
|
The URI identifying the StructureDefinition. |
yes |
|
|
The Java namespace (package name) that will be used for the class. If not specified, the |
no |
|
|
The name of the Java type to generate. |
yes |
|
|
The way in which the generated class can be instantiated. |
yes |
abstract, default, builder |
Additionally, you can specify a mapping of nested classes for each StructureDefinition. These are commonly used when a FHIR StructureDefinition contains an anonymous type that is mapped to a nested class in the HAPI structures.
| Option | Description | Required | Values |
|---|---|---|---|
|
The full ID of the element for which the nested class is generated (e.g. |
yes |
|
|
The name of the nested class to generate. |
yes |
|
|
The name of the superclass the nested class is derived from. |
yes |
|
|
The way in which the generated class can be instantiated. |
yes |
abstract, default, builder |
The instantiation mode controls how the class or nested class is generated:
-
abstract will generate an abstract class that cannot be instantiated. This is useful if you have to include intermediary StructureDefinitions that you’re not planning on using yourself.
-
default will generate a standard implementation class as described by the HAPI FHIR documentation. Note that these classes contain the structural components defined by the package contents, but do not contain provisions to handle slices or fixed values.
-
builder will (eventually) supply a builder for each class that will provide additional measures to ensure that the generated resource complies with the package contents. It will, for example, set fixed values and ensure that cardinality constraints are met. Note that this option is not yet implemented (see Limitations).
3.3. Maven Integration
To use Fhlintstone in your Maven build, add a plugin to your POM:
<plugin>
<groupId>de.fhlintstone</groupId>
<artifactId>fhlintstone-maven-plugin</artifactId>
<version>x.y.z</version>
<configuration>
<fhirVersion>R4</fhirVersion>
<outputPath>${project.basedir}/src/gen/java</outputPath>
<defaultNamespace>org.myApp.fhir</defaultNamespace>
<packageSources>
<packageSource>
<sourceFile>src/main/resources/hl7.fhir.r4.core-4.0.1.tgz</sourceFile>
</packageSource>
<packageSource>
<sourceFile>src/main/resources/my-profile.1.2.3.tgz</sourceFile>
</packageSource>
</packageSources>
<valueSetEnums>
<valueSetEnum>
<valueSet>http://sample.org/demo/ValueSet/MyValueSet</valueSet>
<enumName>MyValueSet</enumName>
</valueSetEnum>
</valueSetEnums>
<structureDefinitionClasses>
<structureDefinitionClass>
<structureDefinition>http://sample.org/demo/StructureDefinition/GeneralPatient</structureDefinition>
<className>GeneralPatient</className>
<instantiation>abstract</instantiation>
</structureDefinitionClass>
<structureDefinitionClass>
<structureDefinition>http://sample.org/demo/StructureDefinition/SpecializedPatient</structureDefinition>
<className>SpecializedPatient</className>
<instantiation>builder</instantiation>
<nestedClasses>
<nestedClass>
<elementId>Patient.link:mySlice</elementId>
<superClass>
org.hl7.fhir.r4.model.Patient.PatientLinkComponent</superClass>
<className>MyLinkComponent</className>
</nestedClass>
</nestedClasses>
</structureDefinitionClass>
</structureDefinitionClasses>
</configuration>
<executions>
<execution>
<goals>
<goal>generate-code</goal>
</goals>
</execution>
</executions>
</plugin>
3.4. Command Line Interface
TODO: document the command line interface
4. Limitations
HL7 FHIR is a very powerful framework that allows for the definition of complex structures. Not all of the options provided by FHIR are currently available when using Fhlintstone. You may want to check the list of known issues. You should be especially aware of the following limtations:
4.1. General Limitations
-
Currently only FHIR release R4 is fully supported. Support for Releases R4B and R5 is mostly implemented, but incomplete. (issue #15)
4.2. StructureDefinition Class Generation
-
StructureDefinitions that only contain Differential statements are not supported at the moment. The package has to contain a Snapshot statement. (issue #17)
-
Generation of Builders is not yet implemented. (issue #36)
-
While it is possible to generate Java enums for ValueSets, the enums are currently not used in the generated classes. (issue #73)
-
Typed references like
Reference(Organization|Practitioner|PractitionerRole)are not yet fully supported. (issue #50, issue #72)
4.3. ValueSet Enum Generation
-
Support for filter specifications in ValueSets is limited:
-
Currently only String and Integer are supported as data types for value set filter. (issue #44)
-
The semantics for the filter "=" with values of type integer, dateTime and decimal are not implemented. (issue #34)
-
Designations for the filters "=" and "regex" are not implemented. (issue #33)
-
ValueSets that use exclusions are currently not supported. (issue #18)
-
For StructureDefinitions, not all attributes of the
@Childannotation are generated. (issue #39) -
Currently, the enum values can only be generated based on the code. (issue #9)
-
The enum values are missing Javadoc comments. This is a limitation of the underlying code generator. (issue #5)
5. Further Information
TODO: assemble further information
6. Glossary
| Term | Definition | Links |
|---|---|---|
The CodeSystem resource is used to declare the existence of and describe a code system or code system supplement and its key properties, and optionally define a part or all of its content. Code systems define which codes (symbols and/or expressions) exist, and how they are understood. |
||
Differential statements are one of two ways to describe the inner structure of a StructureDefinition. Differential statements describe only the differences that they make relative to the base structure definition. In order to properly understand a differential structure, it must be applied to the structure definition on which it is based. |
||
Every element in a Resource can have extension child elements to represent additional information that is not part of the basic definition of the resource. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone. To make the use of extensions safe and managable, there is strict governance applied to the definition and use of extensions. Although any implementer can define and use extensions, there is a set of requirements that must be met as part of their use and definition. |
||
A set of Resources bundled as a machine-readable archive file. Not to be confused with FHIR Package. |
||
In the context of Profiling, a group of related adaptations that are published as a group within an Implementation Guide. Not to be confused with FHIR NPM Package. |
||
A set of constraints on a Resource represented as a StructureDefinition. |
||
The HAPI FHIR library is an implementation of the HL7 FHIR specification for Java. |
||
Fast Healthcare Interopatbility Resources (FHIR) are a standard for health care data exchange, published by HL7®. |
||
A coherent and bounded set of adaptations that are published as a single unit. Validation occurs within the context of the Implementation Guide. |
||
JavaPoet is a Java API for generating |
||
Mockito is a mocking framework that provides a clean & simple API, resulting in readable tests and clean verification errors. |
||
A resource is an entity that has a known identity by which it can be addressed, identifies itself as one of the types of resource defined in the HL7 FHIR specification, contains a set of structured data items as described by the definition of the resource type and has an identified version that changes if the contents of the resource change. |
||
Snapshot statements are one of two ways to describe the inner structure of a StructureDefinition. Snapshot statements are a fully calculated form of the structure that is not dependent on any other structure. |
||
A definition of a FHIR structure. This resource is used to describe the underlying resources, data types defined in FHIR, and also for describing extensions and constraints on resources and data types. |
||
A ValueSet resource instance specifies a set of codes drawn from one or more code systems, intended for use in a particular context. ValueSets link between CodeSystems definitions and their use in coded elements. |