mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-02-19 19:35:42 +00:00
Fix #113 - Handle contained resources with non-local IDs
This commit is contained in:
parent
c3877c1da9
commit
95d5503a9a
@ -20,7 +20,7 @@ package ca.uhn.fhir.parser;
|
|||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.*;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
@ -47,7 +47,6 @@ import org.hl7.fhir.instance.model.api.IReference;
|
|||||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeChildChoiceDefinition;
|
import ca.uhn.fhir.context.RuntimeChildChoiceDefinition;
|
||||||
@ -62,6 +61,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
|
|||||||
|
|
||||||
public abstract class BaseParser implements IParser {
|
public abstract class BaseParser implements IParser {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseParser.class);
|
||||||
private ContainedResources myContainedResources;
|
private ContainedResources myContainedResources;
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
private boolean mySuppressNarratives;
|
private boolean mySuppressNarratives;
|
||||||
@ -80,6 +80,9 @@ public abstract class BaseParser implements IParser {
|
|||||||
for (IResource next : containedResources) {
|
for (IResource next : containedResources) {
|
||||||
String nextId = next.getId().getValue();
|
String nextId = next.getId().getValue();
|
||||||
if (StringUtils.isNotBlank(nextId)) {
|
if (StringUtils.isNotBlank(nextId)) {
|
||||||
|
if (!nextId.startsWith("#")) {
|
||||||
|
nextId = '#' + nextId;
|
||||||
|
}
|
||||||
allIds.add(nextId);
|
allIds.add(nextId);
|
||||||
if (existingIdToContainedResource == null) {
|
if (existingIdToContainedResource == null) {
|
||||||
existingIdToContainedResource = new HashMap<String, IBaseResource>();
|
existingIdToContainedResource = new HashMap<String, IBaseResource>();
|
||||||
@ -119,7 +122,7 @@ public abstract class BaseParser implements IParser {
|
|||||||
if (existingIdToContainedResource != null) {
|
if (existingIdToContainedResource != null) {
|
||||||
IBaseResource potentialTarget = existingIdToContainedResource.remove(next.getReference().getValue());
|
IBaseResource potentialTarget = existingIdToContainedResource.remove(next.getReference().getValue());
|
||||||
if (potentialTarget != null) {
|
if (potentialTarget != null) {
|
||||||
theContained.addContained(potentialTarget);
|
theContained.addContained(next.getReference(), potentialTarget);
|
||||||
containResourcesForEncoding(theContained, potentialTarget, theTarget);
|
containResourcesForEncoding(theContained, potentialTarget, theTarget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -387,6 +390,11 @@ public abstract class BaseParser implements IParser {
|
|||||||
myResources.add(theResource);
|
myResources.add(theResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addContained(IdDt theId, IBaseResource theResource) {
|
||||||
|
myResourceToId.put(theResource, theId);
|
||||||
|
myResources.add(theResource);
|
||||||
|
}
|
||||||
|
|
||||||
public List<IBaseResource> getContainedResources() {
|
public List<IBaseResource> getContainedResources() {
|
||||||
return myResources;
|
return myResources;
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,10 @@ import ca.uhn.fhir.narrative.INarrativeGenerator;
|
|||||||
import ca.uhn.fhir.util.ElementUtil;
|
import ca.uhn.fhir.util.ElementUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is the FHIR JSON parser/encoder. Users should not interact with this
|
||||||
|
* class directly, but should use {@link FhirContext#newJsonParser()} to get an instance.
|
||||||
|
*/
|
||||||
public class JsonParser extends BaseParser implements IParser {
|
public class JsonParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
private static final Set<String> BUNDLE_TEXTNODE_CHILDREN_DSTU1;
|
private static final Set<String> BUNDLE_TEXTNODE_CHILDREN_DSTU1;
|
||||||
|
@ -20,14 +20,15 @@ package ca.uhn.fhir.parser;
|
|||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.*;
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -49,8 +50,8 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.hl7.fhir.instance.model.IBase;
|
import org.hl7.fhir.instance.model.IBase;
|
||||||
import org.hl7.fhir.instance.model.IBaseResource;
|
import org.hl7.fhir.instance.model.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.IPrimitiveType;
|
import org.hl7.fhir.instance.model.IPrimitiveType;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
||||||
@ -91,7 +92,12 @@ import ca.uhn.fhir.util.NonPrettyPrintWriterWrapper;
|
|||||||
import ca.uhn.fhir.util.PrettyPrintWriterWrapper;
|
import ca.uhn.fhir.util.PrettyPrintWriterWrapper;
|
||||||
import ca.uhn.fhir.util.XmlUtil;
|
import ca.uhn.fhir.util.XmlUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is the FHIR XML parser/encoder. Users should not interact with this
|
||||||
|
* class directly, but should use {@link FhirContext#newXmlParser()} to get an instance.
|
||||||
|
*/
|
||||||
public class XmlParser extends BaseParser implements IParser {
|
public class XmlParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
static final String ATOM_NS = "http://www.w3.org/2005/Atom";
|
static final String ATOM_NS = "http://www.w3.org/2005/Atom";
|
||||||
static final String FHIR_NS = "http://hl7.org/fhir";
|
static final String FHIR_NS = "http://hl7.org/fhir";
|
||||||
static final String OPENSEARCH_NS = "http://a9.com/-/spec/opensearch/1.1/";
|
static final String OPENSEARCH_NS = "http://a9.com/-/spec/opensearch/1.1/";
|
||||||
|
@ -20,11 +20,14 @@ import org.junit.Test;
|
|||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.Bundle;
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||||
import ca.uhn.fhir.model.api.Tag;
|
import ca.uhn.fhir.model.api.Tag;
|
||||||
import ca.uhn.fhir.model.api.TagList;
|
import ca.uhn.fhir.model.api.TagList;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.ContainedDt;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.DurationDt;
|
import ca.uhn.fhir.model.dstu2.composite.DurationDt;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
|
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
|
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
|
||||||
@ -32,6 +35,7 @@ import ca.uhn.fhir.model.dstu2.resource.AllergyIntolerance;
|
|||||||
import ca.uhn.fhir.model.dstu2.resource.Binary;
|
import ca.uhn.fhir.model.dstu2.resource.Binary;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Composition;
|
import ca.uhn.fhir.model.dstu2.resource.Composition;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Encounter;
|
import ca.uhn.fhir.model.dstu2.resource.Encounter;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Medication;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.MedicationPrescription;
|
import ca.uhn.fhir.model.dstu2.resource.MedicationPrescription;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Organization;
|
import ca.uhn.fhir.model.dstu2.resource.Organization;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
@ -53,6 +57,160 @@ public class XmlParserTest {
|
|||||||
XMLUnit.setIgnoreWhitespace(true);
|
XMLUnit.setIgnoreWhitespace(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See #113
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEncodeContainedResources() {
|
||||||
|
|
||||||
|
MedicationPrescription medicationPrescript = new MedicationPrescription();
|
||||||
|
|
||||||
|
String medId = "123";
|
||||||
|
CodeableConceptDt codeDt = new CodeableConceptDt("urn:sys", "code1");
|
||||||
|
|
||||||
|
// Adding medication to Contained.
|
||||||
|
Medication medResource = new Medication();
|
||||||
|
medResource.setCode(codeDt);
|
||||||
|
medResource.setId("#" + String.valueOf(medId));
|
||||||
|
ArrayList<IResource> medResList = new ArrayList<IResource>();
|
||||||
|
medResList.add(medResource);
|
||||||
|
ContainedDt medContainedDt = new ContainedDt();
|
||||||
|
medContainedDt.setContainedResources(medResList);
|
||||||
|
medicationPrescript.setContained(medContainedDt);
|
||||||
|
|
||||||
|
// Medication reference. This should point to the contained resource.
|
||||||
|
ResourceReferenceDt medRefDt = new ResourceReferenceDt("#" + medId);
|
||||||
|
medRefDt.setDisplay("MedRef");
|
||||||
|
medicationPrescript.setMedication(medRefDt);
|
||||||
|
|
||||||
|
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||||
|
String encoded = p.encodeResourceToString(medicationPrescript);
|
||||||
|
ourLog.info(encoded);
|
||||||
|
|
||||||
|
//@formatter:on
|
||||||
|
assertThat(encoded, stringContainsInOrder(
|
||||||
|
"<MedicationPrescription xmlns=\"http://hl7.org/fhir\">",
|
||||||
|
"<contained>",
|
||||||
|
"<Medication xmlns=\"http://hl7.org/fhir\">",
|
||||||
|
"<id value=\"123\"/>",
|
||||||
|
"<code>",
|
||||||
|
"<coding>",
|
||||||
|
"<system value=\"urn:sys\"/>",
|
||||||
|
"<code value=\"code1\"/>",
|
||||||
|
"</coding>",
|
||||||
|
"</code>",
|
||||||
|
"</Medication>",
|
||||||
|
"</contained>",
|
||||||
|
"<medication>",
|
||||||
|
"<reference value=\"#123\"/>",
|
||||||
|
"<display value=\"MedRef\"/>",
|
||||||
|
"</medication>",
|
||||||
|
"</MedicationPrescription>"));
|
||||||
|
//@formatter:off
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See #113
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEncodeContainedResourcesManualContainUsingNonLocalId() {
|
||||||
|
|
||||||
|
MedicationPrescription medicationPrescript = new MedicationPrescription();
|
||||||
|
|
||||||
|
String medId = "123";
|
||||||
|
CodeableConceptDt codeDt = new CodeableConceptDt("urn:sys", "code1");
|
||||||
|
|
||||||
|
// Adding medication to Contained.
|
||||||
|
Medication medResource = new Medication();
|
||||||
|
medResource.setCode(codeDt);
|
||||||
|
medResource.setId(String.valueOf(medId)); // ID does not start with '#'
|
||||||
|
ArrayList<IResource> medResList = new ArrayList<IResource>();
|
||||||
|
medResList.add(medResource);
|
||||||
|
ContainedDt medContainedDt = new ContainedDt();
|
||||||
|
medContainedDt.setContainedResources(medResList);
|
||||||
|
medicationPrescript.setContained(medContainedDt);
|
||||||
|
|
||||||
|
// Medication reference. This should point to the contained resource.
|
||||||
|
ResourceReferenceDt medRefDt = new ResourceReferenceDt("#" + medId);
|
||||||
|
medRefDt.setDisplay("MedRef");
|
||||||
|
medicationPrescript.setMedication(medRefDt);
|
||||||
|
|
||||||
|
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||||
|
String encoded = p.encodeResourceToString(medicationPrescript);
|
||||||
|
ourLog.info(encoded);
|
||||||
|
|
||||||
|
//@formatter:on
|
||||||
|
assertThat(encoded, stringContainsInOrder(
|
||||||
|
"<MedicationPrescription xmlns=\"http://hl7.org/fhir\">",
|
||||||
|
"<contained>",
|
||||||
|
"<Medication xmlns=\"http://hl7.org/fhir\">",
|
||||||
|
"<id value=\"123\"/>",
|
||||||
|
"<code>",
|
||||||
|
"<coding>",
|
||||||
|
"<system value=\"urn:sys\"/>",
|
||||||
|
"<code value=\"code1\"/>",
|
||||||
|
"</coding>",
|
||||||
|
"</code>",
|
||||||
|
"</Medication>",
|
||||||
|
"</contained>",
|
||||||
|
"<medication>",
|
||||||
|
"<reference value=\"#123\"/>",
|
||||||
|
"<display value=\"MedRef\"/>",
|
||||||
|
"</medication>",
|
||||||
|
"</MedicationPrescription>"));
|
||||||
|
//@formatter:off
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See #113
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEncodeContainedResourcesAutomatic() {
|
||||||
|
|
||||||
|
MedicationPrescription medicationPrescript = new MedicationPrescription();
|
||||||
|
String nameDisp = "MedRef";
|
||||||
|
CodeableConceptDt codeDt = new CodeableConceptDt("urn:sys", "code1");
|
||||||
|
|
||||||
|
// Adding medication to Contained.
|
||||||
|
Medication medResource = new Medication();
|
||||||
|
// No ID set
|
||||||
|
medResource.setCode(codeDt);
|
||||||
|
|
||||||
|
// Medication reference. This should point to the contained resource.
|
||||||
|
ResourceReferenceDt medRefDt = new ResourceReferenceDt();
|
||||||
|
medRefDt.setDisplay(nameDisp);
|
||||||
|
// Resource reference set, but no ID
|
||||||
|
medRefDt.setResource(medResource);
|
||||||
|
medicationPrescript.setMedication(medRefDt);
|
||||||
|
|
||||||
|
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||||
|
String encoded = p.encodeResourceToString(medicationPrescript);
|
||||||
|
ourLog.info(encoded);
|
||||||
|
|
||||||
|
//@formatter:on
|
||||||
|
assertThat(encoded, stringContainsInOrder(
|
||||||
|
"<MedicationPrescription xmlns=\"http://hl7.org/fhir\">",
|
||||||
|
"<contained>",
|
||||||
|
"<Medication xmlns=\"http://hl7.org/fhir\">",
|
||||||
|
"<id value=\"1\"/>",
|
||||||
|
"<code>",
|
||||||
|
"<coding>",
|
||||||
|
"<system value=\"urn:sys\"/>",
|
||||||
|
"<code value=\"code1\"/>",
|
||||||
|
"</coding>",
|
||||||
|
"</code>",
|
||||||
|
"</Medication>",
|
||||||
|
"</contained>",
|
||||||
|
"<medication>",
|
||||||
|
"<reference value=\"#1\"/>",
|
||||||
|
"<display value=\"MedRef\"/>",
|
||||||
|
"</medication>",
|
||||||
|
"</MedicationPrescription>"));
|
||||||
|
//@formatter:off
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeAndParseSecurityLabels() {
|
public void testEncodeAndParseSecurityLabels() {
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user