Unable to save composition using EHRBase SDK

Hi…I’m new to openEHR implementation. I’m able to work with compositions using Flat format and REST APIs.

Now I’m trying to work with EHRBase SDK.

I’m able to successfully do the following from the OPT file using the SDK’s generator:

a) Generate the java entity objects .
b) Create a template (using the REST API Endpoint)
c) Create empty EHR (that returns ehrid)
d) Populate the java entity objects with data from the client application.

However, I’m facing issues while trying to create/save a composition to the EHRBase db using the composition.java that was generated by the SDK.

I see that any property that has a complex datatype (such as TemporalAmount, TemporalAccess, Category, PartyProxy etc is not recognized while working with the Default Restrictions Client endpoints.

Is it a limitation that can be overcome by writing our own mappers to deserialize or is there a better approach to work with them?

I’m working with May’21 release of SDK.

Thanks,
Anupama

Hi Anupama,

just for my better understanding: are you sending anything through a custom REST API or are you only using the DTO classes generated by the SDK inside Java? When deserializing from REST, there can be cases that require some custom processing. Have you seen the example application? https://github.com/ehrbase/angular-sdk-example

In doubt, please try with the latest version and it would be great if you can also give more details about your case. Feel also encouraged to open a detailed issue on the GitHub page.

Thanks for the reply @birger.haarbrandt
I’m only using the SDK Generated DTO classes to save the composition.

I’ll look into the angular-sdk example you’ve shared. I have been using v1.4 of SDK. I see that another new release is now available. I’ll try with that too.

I’ve attached the OPT used for generating the DTO and Composition.

Thanks,
Anupama

gdl_template_4.en.v0.opt (76.2 KB)

Hi,I also have the same problem to save the composition in ehr.I converted template into java code in that code there are lots of new classes like TemporalAmount, TemporalAccess, Category, PartyProxy etc I didn’t know how to set value for this classes when I save composition with random values for that objects it throws exception.I am tried very hard to save the composition in ehr but its very complex for me can you please briefly explain about that and I am working on rest api.

Hi Guna,

Can you share the .opt template file you are using?

Are you using an existing java generator like the Ehrbase SDK , or hand-rolling your own?

Category is part of the COMPOSITION class and you can set it to one of (with ‘openehr’ as the terminology ID)

431|persistent| - of potential life-time validity;
451|episodic| - valid over the life of a care episode;
433|event| - valid at the time of recording (long-term validity requires subsequent clinical assessment).

Most compositions are ‘event’

PARTY_PROXY is an abstract class and needs to be made concrete. This is used in a few places but is mandatory in COMPOSITION.composer (where it is normally sub-classed to PARTY_IDENTIFIED) and in ENTRY.subject where it is normally PARTY_SELF.

At composition level

     <category>
            <value>event</value>
            <defining_code>
                <terminology_id>
                    <value>openehr</value>
                </terminology_id>
                <code_string>433</code_string>
            </defining_code>
        </category>
   
     <composer xsi:type="PARTY_IDENTIFIED">
            <name>Ian McNicoll</name>
        </composer>

and for each ENTRY

            <items xsi:type="OBSERVATION" archetype_node_id="openEHR-EHR-OBSERVATION.height.v2">
                <name>
                    <value>Height</value>
                </name>
              <!! - SNIPPED !!/>
              <subject xsi:type="PARTY_SELF"/>

Temporal Amount and TemporalAccess are internal Ehrbase constructs that should nat appear in the composition.

One thing you might find helpful is to use an example composition generator (based on a .opt) - either the Ehrsacpe API examples which create FLAT JSON but can then be committed and retrieved as Canonical JSON or XML, or something like https://toolkit.cabolabs.com/

Just for info, I used the Cabolabs openEHR Toolkit to generate a sample composition based on Anupama’s uploaded .opt. THis should give some ideas about how to populate the Java objects.

Here is a snippet

 "category": {
      "value": "event",
      "defining_code": {
         "terminology_id": {
            "_type": "TERMINOLOGY_ID",
            "value": "openehr"
         },
         "code_string": "433"
      }
   },
   "composer": {
      "_type": "PARTY_IDENTIFIED",
      "external_ref": {
         "id": {
            "_type": "HIER_OBJECT_ID",
            "value": "db0c4b94-126d-4ebc-a49d-5c21c7f2b5db"
         },
         "namespace": "DEMOGRAPHIC",
         "type": "PERSON"
      },
      "name": "Dr. Yamamoto"
   },
   "context": {
      "start_time": {
         "value": "2022-07-24T11:20:07.601Z"
      },
      "setting": {
         "value": "primary medical care",
         "defining_code": {
            "terminology_id": {
               "_type": "TERMINOLOGY_ID",
               "value": "openehr"
            },
            "code_string": "228"
         }
      }
   },

and at Entry level

  "content": [
      {
         "_type": "OBSERVATION",
         "name": {
            "_type": "DV_TEXT",
            "value": "TNM Clinical Primary Tumor Category"
         },
         "archetype_details": {
            "archetype_id": {
               "_type": "ARCHETYPE_ID",
               "value": "openEHR-EHR-OBSERVATION.tnm_clinical_primary_tumor_category_.v0"
            },
            "template_id": {
               "_type": "TEMPLATE_ID",
               "value": "gdl_template_4.en.v0"
            },
            "rm_version": "1.0.2"
         },
         "archetype_node_id": "openEHR-EHR-OBSERVATION.tnm_clinical_primary_tumor_category_.v0",
         "language": {
            "terminology_id": {
               "_type": "TERMINOLOGY_ID",
               "value": "ISO_639-1"
            },
            "code_string": "en"
         },
         "encoding": {
            "terminology_id": {
               "_type": "TERMINOLOGY_ID",
               "value": "IANA_character-sets"
            },
            "code_string": "UTF-8"
         },
         "subject": {
            "_type": "PARTY_SELF"
         },

sample openEHR.json (23.9 KB)

thanks for replying
This is my entity class that are converted by template to java code using ehrbase sdk
package com.openehr.api.symptomcomposition;

import com.nedap.archie.rm.archetyped.FeederAudit;
import com.nedap.archie.rm.datastructures.Cluster;
import com.nedap.archie.rm.generic.Participation;
import com.nedap.archie.rm.generic.PartyIdentified;
import com.nedap.archie.rm.generic.PartyProxy;
import com.openehr.api.symptomcomposition.definition.InfectiousDiseaseSummaryEvaluation;
import com.openehr.api.symptomcomposition.definition.SymptomSignObservation;
import java.lang.String;
import java.time.temporal.TemporalAccessor;
import java.util.List;
import javax.annotation.processing.Generated;
import org.ehrbase.client.annotations.Archetype;
import org.ehrbase.client.annotations.Entity;
import org.ehrbase.client.annotations.Id;
import org.ehrbase.client.annotations.Path;
import org.ehrbase.client.annotations.Template;
import org.ehrbase.client.classgenerator.interfaces.CompositionEntity;
import org.ehrbase.client.classgenerator.shareddefinition.Category;
import org.ehrbase.client.classgenerator.shareddefinition.Language;
import org.ehrbase.client.classgenerator.shareddefinition.Setting;
import org.ehrbase.client.classgenerator.shareddefinition.Territory;
import org.ehrbase.client.openehrclient.VersionUid;

@Entity
@Archetype(“openEHR-EHR-COMPOSITION.encounter.v1”)
@Generated(
value = “org.ehrbase.client.classgenerator.ClassGenerator”,
date = “2022-07-23T11:51:28.303654100+05:30”,
comments = “https://github.com/ehrbase/openEHR_SDK Version: 1.20.0-SNAPSHOT”
)
@Template(“symptom”)
public class SymptomComposition implements CompositionEntity {
/**

  • Path: symptom/category
    */
    @Path("/category|defining_code")
    private Category categoryDefiningCode;

/**

  • Path: symptom/context/Extension
  • Description: Additional information required to capture local context or to align with other reference models/formalisms.
  • Comment: e.g. Local hospital departmental infomation or additional metadata to align with FHIR or CIMI equivalents.
    */
    @Path("/context/other_context[at0001]/items[at0002]")
    private List extension;

/**

  • Path: symptom/context/start_time
    */
    @Path("/context/start_time|value")
    private TemporalAccessor startTimeValue;

/**

  • Path: symptom/context/participations
    */
    @Path("/context/participations")
    private List participations;

/**

  • Path: symptom/context/end_time
    */
    @Path("/context/end_time|value")
    private TemporalAccessor endTimeValue;

/**

  • Path: symptom/context/location
    */
    @Path("/context/location")
    private String location;

/**

  • Path: symptom/context/health_care_facility
    */
    @Path("/context/health_care_facility")
    private PartyIdentified healthCareFacility;

/**

  • Path: symptom/context/setting
    */
    @Path("/context/setting|defining_code")
    private Setting settingDefiningCode;

/**

  • Path: symptom/vitals/Symptom/Sign
  • Description: Reported observation of a physical or mental disturbance in an individual.
    */
    @Path("/content[openEHR-EHR-SECTION.adhoc.v1 and name/value=‘vitals’]/items[openEHR-EHR-OBSERVATION.symptom_sign.v0]")
    private SymptomSignObservation symptomSign;

/**

  • Path: symptom/vitals/Infectious disease summary
  • Description: Summary details about an infectious disease and factors related to assessment of immunity.
    */
    @Path("/content[openEHR-EHR-SECTION.adhoc.v1 and name/value=‘vitals’]/items[openEHR-EHR-EVALUATION.infectious_disease_summary.v0]")
    private InfectiousDiseaseSummaryEvaluation infectiousDiseaseSummary;

/**

  • Path: symptom/composer
    */
    @Path("/composer")
    private PartyProxy composer;

/**

  • Path: symptom/language
    */
    @Path("/language")
    private Language language;

/**

  • Path: symptom/feeder_audit
    */
    @Path("/feeder_audit")
    private FeederAudit feederAudit;

/**

  • Path: symptom/territory
    */
    @Path("/territory")
    private Territory territory;

@Id
private VersionUid versionUid;

public void setCategoryDefiningCode(Category categoryDefiningCode) {
this.categoryDefiningCode = categoryDefiningCode;
}

public Category getCategoryDefiningCode() {
return this.categoryDefiningCode ;
}

public void setExtension(List extension) {
this.extension = extension;
}

public List getExtension() {
return this.extension ;
}

public void setStartTimeValue(TemporalAccessor startTimeValue) {
this.startTimeValue = startTimeValue;
}

public TemporalAccessor getStartTimeValue() {
return this.startTimeValue ;
}

public void setParticipations(List participations) {
this.participations = participations;
}

public List getParticipations() {
return this.participations ;
}

public void setEndTimeValue(TemporalAccessor endTimeValue) {
this.endTimeValue = endTimeValue;
}

public TemporalAccessor getEndTimeValue() {
return this.endTimeValue ;
}

public void setLocation(String location) {
this.location = location;
}

public String getLocation() {
return this.location ;
}

public void setHealthCareFacility(PartyIdentified healthCareFacility) {
this.healthCareFacility = healthCareFacility;
}

public PartyIdentified getHealthCareFacility() {
return this.healthCareFacility ;
}

public void setSettingDefiningCode(Setting settingDefiningCode) {
this.settingDefiningCode = settingDefiningCode;
}

public Setting getSettingDefiningCode() {
return this.settingDefiningCode ;
}

public void setSymptomSign(SymptomSignObservation symptomSign) {
this.symptomSign = symptomSign;
}

public SymptomSignObservation getSymptomSign() {
return this.symptomSign ;
}

public void setInfectiousDiseaseSummary(
InfectiousDiseaseSummaryEvaluation infectiousDiseaseSummary) {
this.infectiousDiseaseSummary = infectiousDiseaseSummary;
}

public InfectiousDiseaseSummaryEvaluation getInfectiousDiseaseSummary() {
return this.infectiousDiseaseSummary ;
}

public void setComposer(PartyProxy composer) {
this.composer = composer;
}

public PartyProxy getComposer() {
return this.composer ;
}

public void setLanguage(Language language) {
this.language = language;
}

public Language getLanguage() {
return this.language ;
}

public void setFeederAudit(FeederAudit feederAudit) {
this.feederAudit = feederAudit;
}

public FeederAudit getFeederAudit() {
return this.feederAudit ;
}

public void setTerritory(Territory territory) {
this.territory = territory;
}

public Territory getTerritory() {
return this.territory ;
}

public VersionUid getVersionUid() {
return this.versionUid ;
}

public void setVersionUid(VersionUid versionUid) {
this.versionUid = versionUid;
}
}

I don’t no which attributes are need to set values If i map the values and Postmapping in rest api it shows exception like bad request.can you please set the values for that class I was stucked in that for 1 week

symptom.opt (75.8 KB)