diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java index c522ca07364..1caed6e3f59 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java @@ -67,6 +67,34 @@ public class JsonParserDstu2Test { private static FhirContext ourCtx = FhirContext.forDstu2(); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserDstu2Test.class); + /** + * See #544 + */ + @Test + public void testBundleStitchReferencesByUuid() throws Exception { + ca.uhn.fhir.model.dstu2.resource.Bundle bundle = new ca.uhn.fhir.model.dstu2.resource.Bundle(); + + DocumentManifest dm = new DocumentManifest(); + dm.getSubject().setReference("urn:uuid:96e85cca-9797-45d6-834a-c4eb27f331d3"); + bundle.addEntry().setResource(dm); + + Patient patient = new Patient(); + patient.addName().addFamily("FAMILY"); + bundle.addEntry().setResource(patient).setFullUrl("urn:uuid:96e85cca-9797-45d6-834a-c4eb27f331d3"); + + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle); + ourLog.info(encoded); + + bundle = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, encoded); + dm = (DocumentManifest) bundle.getEntry().get(0).getResource(); + + assertEquals("urn:uuid:96e85cca-9797-45d6-834a-c4eb27f331d3", dm.getSubject().getReference()); + + Patient subject = (Patient) dm.getSubject().getResource(); + assertNotNull(subject); + assertEquals("FAMILY", subject.getNameFirstRep().getFamilyAsSingleString()); + } + @Test public void testContainedResourceInExtensionUndeclared() { Patient p = new Patient(); diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java index 5a5983090a7..662c25e92a7 100644 --- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java @@ -34,52 +34,16 @@ import java.util.UUID; import org.apache.commons.io.IOUtils; import org.hamcrest.Matchers; import org.hamcrest.core.StringContains; +import org.hl7.fhir.dstu3.model.*; import org.hl7.fhir.dstu3.model.Address.AddressUse; import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory; -import org.hl7.fhir.dstu3.model.Attachment; -import org.hl7.fhir.dstu3.model.AuditEvent; -import org.hl7.fhir.dstu3.model.Basic; -import org.hl7.fhir.dstu3.model.Binary; -import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleType; -import org.hl7.fhir.dstu3.model.Claim; -import org.hl7.fhir.dstu3.model.Coding; -import org.hl7.fhir.dstu3.model.Communication; -import org.hl7.fhir.dstu3.model.Condition; import org.hl7.fhir.dstu3.model.Condition.ConditionVerificationStatus; -import org.hl7.fhir.dstu3.model.Conformance; import org.hl7.fhir.dstu3.model.Conformance.UnknownContentCode; -import org.hl7.fhir.dstu3.model.Coverage; -import org.hl7.fhir.dstu3.model.DateTimeType; -import org.hl7.fhir.dstu3.model.DateType; -import org.hl7.fhir.dstu3.model.DecimalType; -import org.hl7.fhir.dstu3.model.DiagnosticReport; -import org.hl7.fhir.dstu3.model.EnumFactory; -import org.hl7.fhir.dstu3.model.Enumeration; import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender; -import org.hl7.fhir.dstu3.model.ExplanationOfBenefit; -import org.hl7.fhir.dstu3.model.Extension; -import org.hl7.fhir.dstu3.model.HumanName; -import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse; -import org.hl7.fhir.dstu3.model.Linkage; -import org.hl7.fhir.dstu3.model.Medication; -import org.hl7.fhir.dstu3.model.MedicationRequest; -import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.Observation.ObservationStatus; -import org.hl7.fhir.dstu3.model.Parameters; -import org.hl7.fhir.dstu3.model.Patient; -import org.hl7.fhir.dstu3.model.PrimitiveType; -import org.hl7.fhir.dstu3.model.Quantity; -import org.hl7.fhir.dstu3.model.QuestionnaireResponse; -import org.hl7.fhir.dstu3.model.Reference; -import org.hl7.fhir.dstu3.model.RelatedPerson; -import org.hl7.fhir.dstu3.model.SampledData; -import org.hl7.fhir.dstu3.model.SimpleQuantity; -import org.hl7.fhir.dstu3.model.StringType; -import org.hl7.fhir.dstu3.model.UriType; -import org.hl7.fhir.dstu3.model.ValueSet; import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.junit.After; import org.junit.AfterClass; @@ -115,6 +79,35 @@ public class JsonParserDstu3Test { ourCtx.setNarrativeGenerator(null); } + /** + * See #544 + */ + @Test + public void testBundleStitchReferencesByUuid() throws Exception { + Bundle bundle = new Bundle(); + + DocumentManifest dm = new DocumentManifest(); + dm.getSubject().setReference("urn:uuid:96e85cca-9797-45d6-834a-c4eb27f331d3"); + bundle.addEntry().setResource(dm); + + Patient patient = new Patient(); + patient.addName().setFamily("FAMILY"); + bundle.addEntry().setResource(patient).setFullUrl("urn:uuid:96e85cca-9797-45d6-834a-c4eb27f331d3"); + + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle); + ourLog.info(encoded); + + bundle = ourCtx.newJsonParser().parseResource(Bundle.class, encoded); + dm = (DocumentManifest) bundle.getEntry().get(0).getResource(); + + assertEquals("urn:uuid:96e85cca-9797-45d6-834a-c4eb27f331d3", dm.getSubject().getReference()); + + Patient subject = (Patient) dm.getSubject().getResource(); + assertNotNull(subject); + assertEquals("FAMILY", subject.getNameFirstRep().getFamily()); + } + + @Test public void testIncorrectJsonTypesIdAndArray() { diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java index 79a189d58e3..32921ead1ca 100644 --- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java @@ -81,167 +81,29 @@ public class XmlParserDstu3Test { */ @Test public void testBundleStitchReferencesByUuid() throws Exception { - String body = IOUtils.toString(XmlParserDstu3Test.class.getResourceAsStream("/bundle_ref_by_uuid_544.xml"), StandardCharsets.UTF_8); - Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, body); + Bundle bundle = new Bundle(); - DocumentManifest dm = (DocumentManifest) bundle.getEntry().get(0).getResource(); + DocumentManifest dm = new DocumentManifest(); + dm.getSubject().setReference("urn:uuid:96e85cca-9797-45d6-834a-c4eb27f331d3"); + bundle.addEntry().setResource(dm); + + Patient patient = new Patient(); + patient.addName().setFamily("FAMILY"); + bundle.addEntry().setResource(patient).setFullUrl("urn:uuid:96e85cca-9797-45d6-834a-c4eb27f331d3"); + + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle); + ourLog.info(encoded); + + bundle = ourCtx.newXmlParser().parseResource(Bundle.class, encoded); + dm = (DocumentManifest) bundle.getEntry().get(0).getResource(); assertEquals("urn:uuid:96e85cca-9797-45d6-834a-c4eb27f331d3", dm.getSubject().getReference()); Patient subject = (Patient) dm.getSubject().getResource(); assertNotNull(subject); + assertEquals("FAMILY", subject.getNameFirstRep().getFamily()); } - /** - * See #414 - */ - @Test - public void testParseXmlExtensionWithoutUrl() { - //@formatter:off - String input = "\n" + - " \n" + - " \n" + - " \n" + - ""; - //@formatter:on - - IParser parser = ourCtx.newXmlParser(); - parser.setParserErrorHandler(new LenientErrorHandler()); - Patient parsed = (Patient) parser.parseResource(input); - assertEquals(1, parsed.getExtension().size()); - assertEquals(null, parsed.getExtension().get(0).getUrl()); - assertEquals("2011-01-02T11:13:15", parsed.getExtension().get(0).getValueAsPrimitive().getValueAsString()); - - try { - parser = ourCtx.newXmlParser(); - parser.setParserErrorHandler(new StrictErrorHandler()); - parser.parseResource(input); - fail(); - } catch (DataFormatException e) { - assertEquals("Resource is missing required element 'url' in parent element 'extension'", e.getCause().getMessage()); - } - - } - - - /** - * See #414 - */ - @Test - public void testParseXmlModifierExtensionWithoutUrl() { - //@formatter:off - String input = "\n" + - " \n" + - " \n" + - " \n" + - ""; - //@formatter:on - - IParser parser = ourCtx.newXmlParser(); - parser.setParserErrorHandler(new LenientErrorHandler()); - Patient parsed = (Patient) parser.parseResource(input); - assertEquals(1, parsed.getModifierExtension().size()); - assertEquals(null, parsed.getModifierExtension().get(0).getUrl()); - assertEquals("2011-01-02T11:13:15", parsed.getModifierExtension().get(0).getValueAsPrimitive().getValueAsString()); - - try { - parser = ourCtx.newXmlParser(); - parser.setParserErrorHandler(new StrictErrorHandler()); - parser.parseResource(input); - fail(); - } catch (DataFormatException e) { - assertEquals("Resource is missing required element 'url' in parent element 'modifierExtension'", e.getCause().getMessage()); - } - - } - - @Test - public void testEncodeChainedContainedResourcer() { - Organization gp = new Organization(); - gp.setName("grandparent"); - - Organization parent = new Organization(); - parent.setName("parent"); - parent.getPartOf().setResource(gp); - - Organization child = new Organization(); - child.setName("child"); - child.getPartOf().setResource(parent); - - Patient patient = new Patient(); - patient.getManagingOrganization().setResource(child); - - String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); - ourLog.info(encoded); - - patient = ourCtx.newXmlParser().parseResource(Patient.class, encoded); - - child = (Organization) patient.getManagingOrganization().getResource(); - assertEquals("child", child.getName()); - - parent = (Organization) child.getPartOf().getResource(); - assertEquals("parent", parent.getName()); - - gp = (Organization) parent.getPartOf().getResource(); - assertEquals("grandparent", gp.getName()); - } - - /** - * If a contained resource refers to a contained resource that comes after it, it should still be successfully - * woven together. - */ - @Test - public void testParseWovenContainedResources() throws IOException { - String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_woven_obs.xml"), StandardCharsets.UTF_8); - - IParser parser = ourCtx.newXmlParser(); - parser.setParserErrorHandler(new StrictErrorHandler()); - org.hl7.fhir.dstu3.model.Bundle bundle = parser.parseResource(Bundle.class, string); - - DiagnosticReport resource = (DiagnosticReport) bundle.getEntry().get(0).getResource(); - Observation obs = (Observation) resource.getResult().get(1).getResource(); - assertEquals("#2", obs.getId()); - Reference performerFirstRep = obs.getPerformerFirstRep(); - Practitioner performer = (Practitioner) performerFirstRep.getResource(); - assertEquals("#3", performer.getId()); - } - - @Test(expected = DataFormatException.class) - public void testContainedResourceWithNoId() throws IOException { - String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_contained_with_no_id.xml"), StandardCharsets.UTF_8); - - IParser parser = ourCtx.newXmlParser(); - parser.setParserErrorHandler(new StrictErrorHandler()); - parser.parseResource(Bundle.class, string); - } - - @Test() - public void testContainedResourceWithNoIdLenient() throws IOException { - String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_contained_with_no_id.xml"), StandardCharsets.UTF_8); - - IParser parser = ourCtx.newXmlParser(); - parser.setParserErrorHandler(new LenientErrorHandler()); - parser.parseResource(Bundle.class, string); - } - - @Test(expected = DataFormatException.class) - public void testParseWithInvalidLocalRef() throws IOException { - String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_invalid_contained_ref.xml"), StandardCharsets.UTF_8); - - IParser parser = ourCtx.newXmlParser(); - parser.setParserErrorHandler(new StrictErrorHandler()); - parser.parseResource(Bundle.class, string); - } - - @Test() - public void testParseWithInvalidLocalRefLenient() throws IOException { - String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_invalid_contained_ref.xml"), StandardCharsets.UTF_8); - - IParser parser = ourCtx.newXmlParser(); - parser.setParserErrorHandler(new LenientErrorHandler()); - parser.parseResource(Bundle.class, string); - } - @Test public void testBundleWithBinary() { //@formatter:off @@ -273,6 +135,7 @@ public class XmlParserDstu3Test { } + @Test public void testContainedResourceInExtensionUndeclared() { Patient p = new Patient(); @@ -295,6 +158,24 @@ public class XmlParserDstu3Test { assertEquals("ORG", o.getName()); } + @Test(expected = DataFormatException.class) + public void testContainedResourceWithNoId() throws IOException { + String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_contained_with_no_id.xml"), StandardCharsets.UTF_8); + + IParser parser = ourCtx.newXmlParser(); + parser.setParserErrorHandler(new StrictErrorHandler()); + parser.parseResource(Bundle.class, string); + } + + @Test() + public void testContainedResourceWithNoIdLenient() throws IOException { + String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_contained_with_no_id.xml"), StandardCharsets.UTF_8); + + IParser parser = ourCtx.newXmlParser(); + parser.setParserErrorHandler(new LenientErrorHandler()); + parser.parseResource(Bundle.class, string); + } + @Test public void testDuration() { Encounter enc = new Encounter(); @@ -1039,6 +920,37 @@ public class XmlParserDstu3Test { assertThat(encoded, not(stringContainsInOrder("
John SMITH ")); } - - @Test public void testMoreExtensions() throws Exception { @@ -2192,6 +2102,8 @@ public class XmlParserDstu3Test { } + + @Test public void testParseAndEncodeCommentsOnExtensions() { //@formatter:off @@ -3121,6 +3033,106 @@ public class XmlParserDstu3Test { } } + @Test(expected = DataFormatException.class) + public void testParseWithInvalidLocalRef() throws IOException { + String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_invalid_contained_ref.xml"), StandardCharsets.UTF_8); + + IParser parser = ourCtx.newXmlParser(); + parser.setParserErrorHandler(new StrictErrorHandler()); + parser.parseResource(Bundle.class, string); + } + + @Test() + public void testParseWithInvalidLocalRefLenient() throws IOException { + String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_invalid_contained_ref.xml"), StandardCharsets.UTF_8); + + IParser parser = ourCtx.newXmlParser(); + parser.setParserErrorHandler(new LenientErrorHandler()); + parser.parseResource(Bundle.class, string); + } + + /** + * If a contained resource refers to a contained resource that comes after it, it should still be successfully + * woven together. + */ + @Test + public void testParseWovenContainedResources() throws IOException { + String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_woven_obs.xml"), StandardCharsets.UTF_8); + + IParser parser = ourCtx.newXmlParser(); + parser.setParserErrorHandler(new StrictErrorHandler()); + org.hl7.fhir.dstu3.model.Bundle bundle = parser.parseResource(Bundle.class, string); + + DiagnosticReport resource = (DiagnosticReport) bundle.getEntry().get(0).getResource(); + Observation obs = (Observation) resource.getResult().get(1).getResource(); + assertEquals("#2", obs.getId()); + Reference performerFirstRep = obs.getPerformerFirstRep(); + Practitioner performer = (Practitioner) performerFirstRep.getResource(); + assertEquals("#3", performer.getId()); + } + + /** + * See #414 + */ + @Test + public void testParseXmlExtensionWithoutUrl() { + //@formatter:off + String input = "\n" + + " \n" + + " \n" + + " \n" + + ""; + //@formatter:on + + IParser parser = ourCtx.newXmlParser(); + parser.setParserErrorHandler(new LenientErrorHandler()); + Patient parsed = (Patient) parser.parseResource(input); + assertEquals(1, parsed.getExtension().size()); + assertEquals(null, parsed.getExtension().get(0).getUrl()); + assertEquals("2011-01-02T11:13:15", parsed.getExtension().get(0).getValueAsPrimitive().getValueAsString()); + + try { + parser = ourCtx.newXmlParser(); + parser.setParserErrorHandler(new StrictErrorHandler()); + parser.parseResource(input); + fail(); + } catch (DataFormatException e) { + assertEquals("Resource is missing required element 'url' in parent element 'extension'", e.getCause().getMessage()); + } + + } + + /** + * See #414 + */ + @Test + public void testParseXmlModifierExtensionWithoutUrl() { + //@formatter:off + String input = "\n" + + " \n" + + " \n" + + " \n" + + ""; + //@formatter:on + + IParser parser = ourCtx.newXmlParser(); + parser.setParserErrorHandler(new LenientErrorHandler()); + Patient parsed = (Patient) parser.parseResource(input); + assertEquals(1, parsed.getModifierExtension().size()); + assertEquals(null, parsed.getModifierExtension().get(0).getUrl()); + assertEquals("2011-01-02T11:13:15", parsed.getModifierExtension().get(0).getValueAsPrimitive().getValueAsString()); + + try { + parser = ourCtx.newXmlParser(); + parser.setParserErrorHandler(new StrictErrorHandler()); + parser.parseResource(input); + fail(); + } catch (DataFormatException e) { + assertEquals("Resource is missing required element 'url' in parent element 'modifierExtension'", e.getCause().getMessage()); + } + + } + /** * See #339 * diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 1aed599ba27..2451ef541d2 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -222,6 +222,17 @@ return an HTTP 404 and not a 400, per the HTTP spec. Thanks to GitHub user @CarthageKing for the pull request! + + When parsing a Bundle containing placeholder fullUrls and references + (e.g. "urn:uuid:0000-0000") the resource reference targets did not get + populated with the given resources. Note that as a part of this + change, IdType and IdDt]]> have been modified + so that when parsing a placeholder ID, the complete placeholder including the + "urn:uuid:" or "urn:oid:" prefix will be placed into the ID part. Previously, + the prefix was treated as the base URL, which led to strange behaviour + like the placeholder being treated as a real IDs. Thanks to GitHub + user @jodue for reporting! +