Skip to main contentIBM® FHIR® Server

FHIR Model Guide

Overview

The FHIR model component provides Java APIs for parsing, building, generating and validating FHIR resources. Java model classes that represent FHIR resources and data types are generated directly from the structure definitions distributed with the spec. All model objects are thread-safe and immutable. Each model class implements the Java builder pattern (Effective Java, Joshua Bloch) and the visitor pattern (GoF). The classes also implement Java equals, hashCode and toString methods. All date/time processing is done using the Java 8 time library.

Many of the data type classes include additional factory methods to facilitate object construction for common use cases. The model includes generated Javadoc comments complete with excerpts taken directly from the specification. Model classes also include Java annotations for constraints (@Constraint), required elements (@Required), choice element types (@Choice) and value set bindings (@Binding). Value set bindings are implemented using Code subclasses with constant fields and nested enumerations. Backbone elements are implemented as Java nested classes to keep them organized.

All schema-level (structure, cardinality, value domain) and global (empty resource, empty element) constraint validation is happens during object construction. This means that it is virtually impossible to build a schema invalid FHIR resource using the APIs. Additional constraint validation (invariants, profile, terminology) is performed using the FHIRValidator class. FHIRParser and FHIRGenerator classes are used to parse and generate both JSON and XML formats. FHIRPathEvaluator is a FHIRPath evaluation engine built on an ANTLR4 generated parser. It implements are large portion of the FHIRPath specification and is used for validation and search parameter value extraction.

Building a Resource using the FHIR Model API

The FHIR model API implements the Builder pattern for constructing Resource instances.

Observation bodyWeight = Observation.builder()
.meta(Meta.builder()
.profile(Canonical.of("http://hl7.org/fhir/StructureDefinition/bodyweight"))
.build())
.status(ObservationStatus.FINAL)
.effective(DateTime.builder()
.value("2019-01-01")
.build())
.category(CodeableConcept.builder()

In the example above, a number of different builder classes are used:

  • Observation.Builder
  • DateTime.Builder
  • CodeableConcept.Builder
  • Quantity.Builder

Every type in the model that represents a FHIR resource or element has a corresponding nested, static Builder class used for constructing thread-safe, immutable instances.

Several static factory / utility methods are also used:

  • Canonical.of(...)
  • Uri.of(...)
  • Code.of(...)
  • String.string(...) (via static import)

Many of the primitive data types contain this type of “helper” method.

Fields from an immutable model object may be copied back into a builder object using the toBuilder() method:

bodyWeight = bodyWeight.toBuilder()
.value(bodyWeight.getValue().as(Quantity.class).toBuilder()
.value(Decimal.of(210))
.build())
.build();

Parsing a Resource from an InputStream or Reader

// Parse from InputStream
InputStream in = getInputStream("JSON/bodyweight.json");
Observation observation = FHIRParser.parser(Format.JSON).parse(in);
// Parse from Reader
Reader reader = getReader("JSON/bodyweight.json");
Observation observation = FHIRParser.parser(Format.JSON).parse(reader);

Generating JSON and XML formats from a Resource instance

// Generate JSON format
FHIRGenerator.generator(Format.JSON).generate(bodyWeight, System.out);
// Generate XML format
FHIRGenerator.generator(Format.XML).generate(bodyWeight, System.out);

The FHIRGenerator interface has a separate factory method that takes boolean prettyPrinting as a parameter:

// Generate JSON format (with pretty printing)
FHIRGenerator.generator(Format.JSON, true).generate(bodyWeight, System.out);

Validating a Resource instance

Schema-level validation occurs during object construction. This includes validation of cardinality constraints and value domains. Additional validation of constraints specified in the model is performed using the FHIRValidator class.

Observation observation = getObservation();
List<Issue> issues = FHIRValidator.validator().validate(observation);
for (Issue issue : issues) {
if (IssueSeverity.ERROR.equals(issue.getSeverity())) {
// handle error
}
}

Evaluating FHIRPath expressions on a Resource instance

EvaluationContext evaluationContext = new EvaluationContext(bodyWeight);
Collection<FHIRPathNode> result = FHIRPathEvaluator.evaluator().evaluate(evaluationContext, "Observation.value.as(Quantity).value >= 200");
assert(FHIRPathUtil.isTrue(result));

The EvaluationContext class builds a FHIRPathTree from a FHIR resource or element. A FHIRPathTree is a tree of labeled nodes that wrap FHIR elements and are used by the FHIRPath evaluation engine (FHIRPathEvaluator).