Issues Extending FHIR Resources in HAPI-FHIR

49 views
Skip to first unread message

John Doe

unread,
Apr 4, 2025, 10:49:41 AM4/4/25
to HAPI FHIR

Hi everyone,

I am new to FHIR resources and encountering difficulties in getting started. Any guidance would be greatly appreciated, as I may be approaching this incorrectly by manually writing Java classes after failing to find a method to generate them from the resource definitions.


In Germany, "Gematik" has defined FHIR resources and profiles that I need to parse (both ways). While parsing global resources works without issues, I am encountering problems wherever Gematik has introduced extensions or modifications.

To extend resources, I followed the example/tutorial provided here:
https://hapifhir.io/hapi-fhir/docs/model/custom_structures.html

Initially, this seemed straightforward, but I have encountered two major issues that I cannot resolve:


  1. I am unable to override existing fields in my extending classes to modify attributes such as cardinality or the Java type (e.g., changing MessageDestinationComponent to MyDestination). If I attempt to override the fields, I receive the following exception when parsing:

Exception in thread "main" ca.uhn.fhir.context.ConfigurationException: HAPI-1705: Detected duplicate field name 'destination' in type 'de.carecloud.app.fhir.MessageHeaderAppTransport'

at ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition.scanCompositeElementForChildren(BaseRuntimeElementCompositeDefinition.java:367)

at ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition.scanCompositeElementForChildren(BaseRuntimeElementCompositeDefinition.java:206)

at ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition.sealAndInitialize(BaseRuntimeElementCompositeDefinition.java:557)

at ca.uhn.fhir.context.RuntimeResourceDefinition.sealAndInitialize(RuntimeResourceDefinition.java:199)

at ca.uhn.fhir.context.ModelScanner.init(ModelScanner.java:163)

at ca.uhn.fhir.context.ModelScanner.<init>(ModelScanner.java:98)

at ca.uhn.fhir.context.FhirContext.scanResourceTypes(FhirContext.java:1095)

at ca.uhn.fhir.context.FhirContext.validateInitialized(FhirContext.java:1213)

at ca.uhn.fhir.context.FhirContext.getResourceDefinition(FhirContext.java:498)

at ca.uhn.fhir.parser.BaseParser.parseResource(BaseParser.java:646)

at ca.uhn.fhir.parser.BaseParser.parseResource(BaseParser.java:722)

at de.carecloud.app.fhir.FhirPlayground.parsePrescriptionRequestToPrescriberCopy(FhirPlayground.java:574)

at de.carecloud.app.fhir.FhirPlayground.main(FhirPlayground.java:596)


  1. If I avoid overriding fields and proceed with the existing structure, I encounter the following exception:

Exception in thread "main" ca.uhn.fhir.parser.DataFormatException: HAPI-1851: DataFormatException at [[row,col {unknown-source}]: [51,13]]: HAPI-1814: Incorrect resource type found, expected "ErpServiceRequestRequestHeader" but found "MessageHeader"

at ca.uhn.fhir.parser.XmlParser.doXmlLoop(XmlParser.java:262)

at ca.uhn.fhir.parser.XmlParser.parseResource(XmlParser.java:999)

at ca.uhn.fhir.parser.XmlParser.doParseResource(XmlParser.java:171)

at ca.uhn.fhir.parser.BaseParser.parseResource(BaseParser.java:653)

at ca.uhn.fhir.parser.BaseParser.parseResource(BaseParser.java:722)

at de.carecloud.app.fhir.FhirPlayground.parsePrescriptionRequestToPrescriberCopy(FhirPlayground.java:575)

at de.carecloud.app.fhir.FhirPlayground.main(FhirPlayground.java:597)

Caused by: ca.uhn.fhir.parser.DataFormatException: HAPI-1814: Incorrect resource type found, expected "ErpServiceRequestRequestHeader" but found "MessageHeader"

at ca.uhn.fhir.parser.ParserState$BasePreResourceState.enteringNewElement(ParserState.java:1074)

at ca.uhn.fhir.parser.ParserState.enteringNewElement(ParserState.java:137)

at ca.uhn.fhir.parser.JsonParser.doParseResource(JsonParser.java:261)

at ca.uhn.fhir.parser.JsonParser.doParseResource(JsonParser.java:243)

at ca.uhn.fhir.parser.BaseParser.parseResource(BaseParser.java:653)

at ca.uhn.fhir.parser.BaseParser.parseResource(BaseParser.java:722)

at ca.uhn.fhir.parser.ParserState$BasePreResourceState.postProcess(ParserState.java:1162)

at ca.uhn.fhir.parser.ParserState$BasePreResourceState.wereBack(ParserState.java:1255)

at ca.uhn.fhir.parser.ParserState$PreResourceStateHl7Org.wereBack(ParserState.java:1333)

at ca.uhn.fhir.parser.ParserState.pop(ParserState.java:169)

at ca.uhn.fhir.parser.ParserState$ElementCompositeState.endingElement(ParserState.java:598)

at ca.uhn.fhir.parser.ParserState.endingElement(ParserState.java:133)

at ca.uhn.fhir.parser.XmlParser.doXmlLoop(XmlParser.java:242)

... 6 more



Minimal Code Example

My implementation is as follows (all imports are based on the R4 model, as Gematik builds upon it):


@ResourceDef(name = "MessageHeaderAppTransport", profile = "https://gematik.de/fhir/atf/StructureDefinition/message-header-app-transport")

public class MessageHeaderAppTransport extends MessageHeader {


    @Child(name = "destination", min = 1, max = Child.MAX_UNLIMITED, type = { MessageDestinationComponent.class })

    @Description(shortDefinition = "Angaben zum Empfänger der Nachricht", formalDefinition = "Angaben zum Empfänger der Nachricht")

    @MustSupport(value = true)

    private List<MessageDestinationComponent> destination;

}


@Block()

 public static class MessageDestinationComponent extends MessageHeader.MessageDestinationComponent {

      // TODO: Make Changes done by Gematik

}


@ResourceDef(name = "ErpServiceRequestRequestHeader", profile = "https://gematik.de/fhir/erp-servicerequest/StructureDefinition/erp-service-request-request-header")

public class ErpServiceRequestRequestHeader extends MessageHeaderAppTransport {

}



@ResourceDef(name = "Bundle", profile = "https://gematik.de/fhir/erp-servicerequest/StructureDefinition/erp-service-request-message-container")

public class ErpServiceRequestMessageContainer extends Bundle {

}




I then call the parser like this:

Note: The parsed xml is an example provided by Gematik here: https://simplifier.net/erezept-servicerequest/UC3-1-Prescription-Request-To-Prescriber-COPY/~xml


    FhirContext ctx = FhirContext.forR4();

    ctx.registerCustomType(ErpServiceRequestRequestHeader.class);

    ctx.registerCustomType(ErpServiceRequestMessageContainer.class);

    ctx.registerCustomType(MessageHeaderAppTransport.class);

    ctx.registerCustomType(MessageHeaderAppTransport.MessageDestinationComponent.class);

    ctx.setDefaultTypeForProfile("https://gematik.de/fhir/erp-servicerequest/StructureDefinition/erp-service-request-request-header", ErpServiceRequestRequestHeader.class);

    ctx.setDefaultTypeForProfile("https://gematik.de/fhir/atf/StructureDefinition/message-header-app-transport", MessageHeaderAppTransport.class);

    ctx.setDefaultTypeForProfile("https://gematik.de/fhir/erp-servicerequest/StructureDefinition/erp-service-request-message-container", ErpServiceRequestMessageContainer.class);

    IParser parser = ctx.newXmlParser().setPrettyPrint(true);

    var parsed = parser.parseResource(ErpServiceRequestMessageContainer.class, UC31PrescritiionRequestToPrescriberCopyEXAMPLE.xmlExample);

John Doe

unread,
Apr 4, 2025, 6:28:02 PM4/4/25
to HAPI FHIR
Update:
Resolved issue 2 (had the annotation of the "ErpServiceRequestRequestHeader" wrong).

Issue 1 isnt a blocker right now, since most of the time the Gematik seems to have changed only cardinalities, which doesnt affect me as much, but I'd still like to understand how its done properly.

A new issue which I cant resolve yet (besides checking System-Strings "by hand") is the following: how can you register classes that extend from "identifier" to the parser? I would like to get them parsed too.

Thanks & Kind Regards!



Reply all
Reply to author
Forward
0 new messages