Fix #113 - Handle contained resources with non-local IDs

This commit is contained in:
James Agnew 2015-03-19 11:49:25 +01:00
parent c3877c1da9
commit 95d5503a9a
4 changed files with 182 additions and 6 deletions

View File

@ -20,7 +20,7 @@ package ca.uhn.fhir.parser;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.io.IOException;
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.BaseRuntimeDeclaredChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeChildChoiceDefinition;
@ -62,6 +61,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
public abstract class BaseParser implements IParser {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseParser.class);
private ContainedResources myContainedResources;
private FhirContext myContext;
private boolean mySuppressNarratives;
@ -80,6 +80,9 @@ public abstract class BaseParser implements IParser {
for (IResource next : containedResources) {
String nextId = next.getId().getValue();
if (StringUtils.isNotBlank(nextId)) {
if (!nextId.startsWith("#")) {
nextId = '#' + nextId;
}
allIds.add(nextId);
if (existingIdToContainedResource == null) {
existingIdToContainedResource = new HashMap<String, IBaseResource>();
@ -119,7 +122,7 @@ public abstract class BaseParser implements IParser {
if (existingIdToContainedResource != null) {
IBaseResource potentialTarget = existingIdToContainedResource.remove(next.getReference().getValue());
if (potentialTarget != null) {
theContained.addContained(potentialTarget);
theContained.addContained(next.getReference(), potentialTarget);
containResourcesForEncoding(theContained, potentialTarget, theTarget);
}
}
@ -387,6 +390,11 @@ public abstract class BaseParser implements IParser {
myResources.add(theResource);
}
public void addContained(IdDt theId, IBaseResource theResource) {
myResourceToId.put(theResource, theId);
myResources.add(theResource);
}
public List<IBaseResource> getContainedResources() {
return myResources;
}

View File

@ -104,6 +104,10 @@ import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.util.ElementUtil;
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 {
private static final Set<String> BUNDLE_TEXTNODE_CHILDREN_DSTU1;

View File

@ -20,14 +20,15 @@ package ca.uhn.fhir.parser;
* #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.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
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.IBaseResource;
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.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseExtension;
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.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 {
static final String ATOM_NS = "http://www.w3.org/2005/Atom";
static final String FHIR_NS = "http://hl7.org/fhir";
static final String OPENSEARCH_NS = "http://a9.com/-/spec/opensearch/1.1/";

View File

@ -20,11 +20,14 @@ import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
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.Tag;
import ca.uhn.fhir.model.api.TagList;
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.ContainedDt;
import ca.uhn.fhir.model.dstu2.composite.DurationDt;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
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.Composition;
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.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
@ -53,6 +57,160 @@ public class XmlParserTest {
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
public void testEncodeAndParseSecurityLabels() {
Patient p = new Patient();