Fix regression when parsing contained resources

This commit is contained in:
James Agnew 2016-08-05 18:01:44 -04:00
parent 4ff25b093f
commit 74950a4efc
9 changed files with 320 additions and 85 deletions

View File

@ -1395,10 +1395,10 @@ class ParserState<T> {
if (res.getId() == null || res.getId().isEmpty()) {
ourLog.debug("Discarding contained resource with no ID!");
} else {
getPreResourceState().getContainedResources().put(res.getId().getValueAsString(), res);
if (!res.getId().isLocal()) {
res.setId(new IdDt('#' + res.getId().getIdPart()));
}
getPreResourceState().getContainedResources().put(res.getId().getValueAsString(), res);
}
IResource preResCurrentElement = (IResource) getPreResourceState().getCurrentElement();
@ -1435,10 +1435,10 @@ class ParserState<T> {
if (res.getIdElement() == null || res.getIdElement().isEmpty()) {
ourLog.debug("Discarding contained resource with no ID!");
} else {
getPreResourceState().getContainedResources().put(res.getIdElement().getValue(), res);
if (!res.getIdElement().isLocal()) {
res.getIdElement().setValue('#' + res.getIdElement().getIdPart());
}
getPreResourceState().getContainedResources().put(res.getIdElement().getValue(), res);
}
IBaseResource preResCurrentElement = getPreResourceState().getCurrentElement();
@ -2121,7 +2121,7 @@ class ParserState<T> {
String ref = nextRef.getReference().getValue();
if (isNotBlank(ref)) {
if (ref.startsWith("#")) {
IResource target = (IResource) myContainedResources.get(ref.substring(1));
IResource target = (IResource) myContainedResources.get(ref);
if (target != null) {
nextRef.setResource(target);
} else {
@ -2134,7 +2134,7 @@ class ParserState<T> {
String ref = nextRef.getReferenceElement().getValue();
if (isNotBlank(ref)) {
if (ref.startsWith("#")) {
IBaseResource target = myContainedResources.get(ref.substring(1));
IBaseResource target = myContainedResources.get(ref);
if (target != null) {
nextRef.setResource(target);
} else {

View File

@ -0,0 +1,13 @@
package ca.uhn.fhir.parser;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
@ResourceDef(name = "DiagnosticReport", profile = CustomDiagnosticReportDstu2.PROFILE)
public class CustomDiagnosticReportDstu2 extends DiagnosticReport {
public static final String PROFILE = "http://custom_DiagnosticReport";
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,13 @@
package ca.uhn.fhir.parser;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu2.resource.Observation;
@ResourceDef(name = "Observation", profile = CustomObservationDstu2.PROFILE)
public class CustomObservationDstu2 extends Observation {
public static final String PROFILE = "http://custom_Observation";
private static final long serialVersionUID = 1L;
}

View File

@ -20,12 +20,7 @@ import static org.mockito.Mockito.verify;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import java.util.*;
import org.apache.commons.io.IOUtils;
import org.custommonkey.xmlunit.Diff;
@ -35,6 +30,7 @@ import org.hamcrest.core.StringContains;
import org.hamcrest.text.StringContainsInOrder;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@ -43,60 +39,18 @@ import org.mockito.internal.stubbing.answers.ThrowsException;
import com.google.common.collect.Sets;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.*;
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.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu2.composite.AnnotationDt;
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.ElementDefinitionDt;
import ca.uhn.fhir.model.dstu2.composite.*;
import ca.uhn.fhir.model.dstu2.composite.ElementDefinitionDt.Binding;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.composite.SimpleQuantityDt;
import ca.uhn.fhir.model.dstu2.resource.AllergyIntolerance;
import ca.uhn.fhir.model.dstu2.resource.Binary;
import ca.uhn.fhir.model.dstu2.resource.*;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Link;
import ca.uhn.fhir.model.dstu2.resource.Composition;
import ca.uhn.fhir.model.dstu2.resource.Condition;
import ca.uhn.fhir.model.dstu2.resource.DataElement;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Encounter;
import ca.uhn.fhir.model.dstu2.resource.Medication;
import ca.uhn.fhir.model.dstu2.resource.MedicationOrder;
import ca.uhn.fhir.model.dstu2.resource.MedicationStatement;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.AddressUseEnum;
import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum;
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
import ca.uhn.fhir.model.dstu2.valueset.ContactPointSystemEnum;
import ca.uhn.fhir.model.dstu2.valueset.DocumentReferenceStatusEnum;
import ca.uhn.fhir.model.dstu2.valueset.IdentifierTypeCodesEnum;
import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum;
import ca.uhn.fhir.model.dstu2.valueset.MaritalStatusCodesEnum;
import ca.uhn.fhir.model.dstu2.valueset.NameUseEnum;
import ca.uhn.fhir.model.dstu2.valueset.ObservationRelationshipTypeEnum;
import ca.uhn.fhir.model.dstu2.valueset.ObservationStatusEnum;
import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.MarkdownDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.dstu2.valueset.*;
import ca.uhn.fhir.model.primitive.*;
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.server.Constants;
@ -106,6 +60,13 @@ public class XmlParserDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu2Test.class);
@Before
public void before() {
if (ourCtx == null) {
ourCtx = FhirContext.forDstu2();
}
}
@Test
public void testBundleWithBinary() {
//@formatter:off
@ -157,7 +118,7 @@ public class XmlParserDstu2Test {
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parsed);
assertThat(encoded, containsString("<valueMarkdown value=\"THIS IS MARKDOWN\"/>"));
}
@Test
public void testChoiceTypeWithProfiledType2() {
Parameters par = new Parameters();
@ -175,6 +136,7 @@ public class XmlParserDstu2Test {
assertEquals(MarkdownDt.class, par.getParameter().get(1).getValue().getClass());
}
@Test
public void testContainedResourceInExtensionUndeclared() {
Patient p = new Patient();
@ -349,6 +311,108 @@ public class XmlParserDstu2Test {
}
@Test
public void testEncodeAndParseContainedCustomTypes() {
ourCtx = FhirContext.forDstu2();
ourCtx.setDefaultTypeForProfile(CustomObservationDstu2.PROFILE, CustomObservationDstu2.class);
ourCtx.setDefaultTypeForProfile(CustomDiagnosticReportDstu2.PROFILE, CustomDiagnosticReportDstu2.class);
CustomObservationDstu2 obs = new CustomObservationDstu2();
obs.setStatus(ObservationStatusEnum.FINAL);
CustomDiagnosticReportDstu2 dr = new CustomDiagnosticReportDstu2();
dr.setStatus(DiagnosticReportStatusEnum.FINAL);
dr.addResult().setResource(obs);
IParser parser = ourCtx.newXmlParser();
parser.setPrettyPrint(true);
String output = parser.encodeResourceToString(dr);
ourLog.info(output);
//@formatter:off
assertThat(output,stringContainsInOrder(
"<DiagnosticReport xmlns=\"http://hl7.org/fhir\">",
"<meta>",
"<profile value=\"http://custom_DiagnosticReport\"/>",
"</meta>",
"<contained>",
"<Observation xmlns=\"http://hl7.org/fhir\">",
"<id value=\"1\"/>",
"<meta>",
"<profile value=\"http://custom_Observation\"/>",
"</meta>",
"<status value=\"final\"/>",
"</Observation>",
"</contained>",
"<status value=\"final\"/>",
"<result>",
"<reference value=\"#1\"/>",
"</result>",
"</DiagnosticReport>"));
//@formatter:on
/*
* Now PARSE!
*/
dr = (CustomDiagnosticReportDstu2) parser.parseResource(output);
assertEquals(DiagnosticReportStatusEnum.FINAL, dr.getStatusElement().getValueAsEnum());
assertEquals("#1", dr.getResult().get(0).getReference().getValueAsString());
obs = (CustomObservationDstu2) dr.getResult().get(0).getResource();
assertEquals(ObservationStatusEnum.FINAL, obs.getStatusElement().getValueAsEnum());
ourCtx = null;
}
@Test
public void testEncodeAndParseContainedNonCustomTypes() {
ourCtx = FhirContext.forDstu2();
Observation obs = new Observation();
obs.setStatus(ObservationStatusEnum.FINAL);
DiagnosticReport dr = new DiagnosticReport();
dr.setStatus(DiagnosticReportStatusEnum.FINAL);
dr.addResult().setResource(obs);
IParser parser = ourCtx.newXmlParser();
parser.setPrettyPrint(true);
String output = parser.encodeResourceToString(dr);
ourLog.info(output);
//@formatter:off
assertThat(output,stringContainsInOrder(
"<DiagnosticReport xmlns=\"http://hl7.org/fhir\">",
"<contained>",
"<Observation xmlns=\"http://hl7.org/fhir\">",
"<id value=\"1\"/>",
"<status value=\"final\"/>",
"</Observation>",
"</contained>",
"<status value=\"final\"/>",
"<result>",
"<reference value=\"#1\"/>",
"</result>",
"</DiagnosticReport>"));
//@formatter:on
/*
* Now PARSE!
*/
dr = (DiagnosticReport) parser.parseResource(output);
assertEquals(DiagnosticReportStatusEnum.FINAL, dr.getStatusElement().getValueAsEnum());
assertEquals("#1", dr.getResult().get(0).getReference().getValueAsString());
obs = (Observation) dr.getResult().get(0).getResource();
assertEquals(ObservationStatusEnum.FINAL, obs.getStatusElement().getValueAsEnum());
ourCtx = null;
}
/**
* See #350
*/
@ -1040,28 +1104,6 @@ public class XmlParserDstu2Test {
}
/**
* Make sure whitespace is preserved for pre tags
*/
@Test
public void testEncodeDivWithPrePrettyPrint() {
Patient p = new Patient();
p.getText().setDiv("<div>\n\n<p>A P TAG</p><p><pre>line1\nline2\nline3 <b>BOLD</b></pre></p></div>");
String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(output);
//@formatter:off
assertThat(output, stringContainsInOrder(
" <text>",
" <div",
" <pre>line1\nline2\nline3 <b>BOLD</b></pre>"
));
//@formatter:on
}
/**
* Make sure whitespace is preserved for pre tags
*/
@ -1084,6 +1126,28 @@ public class XmlParserDstu2Test {
}
/**
* Make sure whitespace is preserved for pre tags
*/
@Test
public void testEncodeDivWithPrePrettyPrint() {
Patient p = new Patient();
p.getText().setDiv("<div>\n\n<p>A P TAG</p><p><pre>line1\nline2\nline3 <b>BOLD</b></pre></p></div>");
String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(output);
//@formatter:off
assertThat(output, stringContainsInOrder(
" <text>",
" <div",
" <pre>line1\nline2\nline3 <b>BOLD</b></pre>"
));
//@formatter:on
}
@Test
public void testEncodeDoesntIncludeUuidId() {
Patient p = new Patient();

View File

@ -0,0 +1,14 @@
package ca.uhn.fhir.parser;
import org.hl7.fhir.dstu3.model.DiagnosticReport;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
@ResourceDef(name = "DiagnosticReport", profile = CustomDiagnosticReport.PROFILE)
public class CustomDiagnosticReport extends DiagnosticReport {
public static final String PROFILE = "http://custom_DiagnosticReport";
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,14 @@
package ca.uhn.fhir.parser;
import org.hl7.fhir.dstu3.model.Observation;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
@ResourceDef(name = "Observation", profile = CustomObservation.PROFILE)
public class CustomObservation extends Observation {
public static final String PROFILE = "http://custom_Observation";
private static final long serialVersionUID = 1L;
}

View File

@ -57,6 +57,7 @@ import org.hl7.fhir.dstu3.model.DataElement;
import org.hl7.fhir.dstu3.model.DateTimeType;
import org.hl7.fhir.dstu3.model.DateType;
import org.hl7.fhir.dstu3.model.DiagnosticReport;
import org.hl7.fhir.dstu3.model.DiagnosticReport.DiagnosticReportStatus;
import org.hl7.fhir.dstu3.model.DocumentManifest;
import org.hl7.fhir.dstu3.model.Duration;
import org.hl7.fhir.dstu3.model.ElementDefinition;
@ -119,9 +120,114 @@ public class XmlParserDstu3Test {
@After
public void after() {
if (ourCtx == null) {
ourCtx = FhirContext.forDstu3();
}
ourCtx.setNarrativeGenerator(null);
}
@Test
public void testEncodeAndParseContainedCustomTypes() {
ourCtx = FhirContext.forDstu3();
ourCtx.setDefaultTypeForProfile(CustomObservation.PROFILE, CustomObservation.class);
ourCtx.setDefaultTypeForProfile(CustomDiagnosticReport.PROFILE, CustomDiagnosticReport.class);
CustomObservation obs = new CustomObservation();
obs.setStatus(ObservationStatus.FINAL);
CustomDiagnosticReport dr = new CustomDiagnosticReport();
dr.setStatus(DiagnosticReportStatus.FINAL);
dr.addResult().setResource(obs);
IParser parser = ourCtx.newXmlParser();
parser.setPrettyPrint(true);
String output = parser.encodeResourceToString(dr);
ourLog.info(output);
//@formatter:off
assertThat(output,stringContainsInOrder(
"<DiagnosticReport xmlns=\"http://hl7.org/fhir\">",
"<meta>",
"<profile value=\"http://custom_DiagnosticReport\"/>",
"</meta>",
"<contained>",
"<Observation xmlns=\"http://hl7.org/fhir\">",
"<id value=\"1\"/>",
"<meta>",
"<profile value=\"http://custom_Observation\"/>",
"</meta>",
"<status value=\"final\"/>",
"</Observation>",
"</contained>",
"<status value=\"final\"/>",
"<result>",
"<reference value=\"#1\"/>",
"</result>",
"</DiagnosticReport>"));
//@formatter:on
/*
* Now PARSE!
*/
dr = (CustomDiagnosticReport) parser.parseResource(output);
assertEquals(DiagnosticReportStatus.FINAL, dr.getStatus());
assertEquals("#1", dr.getResult().get(0).getReference());
obs = (CustomObservation) dr.getResult().get(0).getResource();
assertEquals(ObservationStatus.FINAL, obs.getStatus());
ourCtx = null;
}
@Test
public void testEncodeAndParseContainedNonCustomTypes() {
ourCtx = FhirContext.forDstu3();
Observation obs = new Observation();
obs.setStatus(ObservationStatus.FINAL);
DiagnosticReport dr = new DiagnosticReport();
dr.setStatus(DiagnosticReportStatus.FINAL);
dr.addResult().setResource(obs);
IParser parser = ourCtx.newXmlParser();
parser.setPrettyPrint(true);
String output = parser.encodeResourceToString(dr);
ourLog.info(output);
//@formatter:off
assertThat(output,stringContainsInOrder(
"<DiagnosticReport xmlns=\"http://hl7.org/fhir\">",
"<contained>",
"<Observation xmlns=\"http://hl7.org/fhir\">",
"<id value=\"1\"/>",
"<status value=\"final\"/>",
"</Observation>",
"</contained>",
"<status value=\"final\"/>",
"<result>",
"<reference value=\"#1\"/>",
"</result>",
"</DiagnosticReport>"));
//@formatter:on
/*
* Now PARSE!
*/
dr = (DiagnosticReport) parser.parseResource(output);
assertEquals(DiagnosticReportStatus.FINAL, dr.getStatus());
assertEquals("#1", dr.getResult().get(0).getReference());
obs = (Observation) dr.getResult().get(0).getResource();
assertEquals(ObservationStatus.FINAL, obs.getStatus());
ourCtx = null;
}
@Test
public void testEncodeHistoryEncodeVersionsAtPath3() {
ourCtx = FhirContext.forDstu3();

View File

@ -29,6 +29,10 @@
</ul>
]]>
</action>
<action type="add">
STU3 structure definitions have been updated to the
STU3 ballot candidate versions (1.5.0 - SVN 9395)
</action>
<action type="add">
Both client and server now support the new Content Types decided in
<![CDATA[<a href="http://gforge.hl7.org/gf/project/fhir/tracker/?action=TrackerItemEdit&tracker_id=677&tracker_item_id=10199">FHIR #10199</a>]]>.
@ -140,6 +144,13 @@
could also be useful in other places too.
Thanks to Matt Clarke of Orion Health for the contribution!
</action>
<action type="fix">
Fix a regression when parsing resources that have contained
resources, where the reference in the outer resource which
links to the contained resource sometimes did does not get
populated with the actual target resource instance. Thanks to
Neal Acharya for reporting!
</action>
</release>
<release version="1.6" date="2016-07-07">
<action type="fix">

View File

@ -52,19 +52,19 @@
<tr>
<td rowspan="4">hapi-fhir-structures-dstu3</td>
<td>1.4</td>
<td><a href="http://hl7-fhir.github.io/">DSTU3 1.3.0 Snapshot</a> (SVN 7602)</td>
<td><a href="http://hl7-fhir.github.io/">STU3 1.3.0 Snapshot</a> (SVN 7602)</td>
</tr>
<tr>
<td>1.5</td>
<td><a href="http://hl7-fhir.github.io/">DSTU3 1.4.0 Snapshot</a> (SVN 8138)</td>
<td><a href="http://hl7-fhir.github.io/">STU3 1.4.0 Snapshot</a> (SVN 8138)</td>
</tr>
<tr>
<td>1.6</td>
<td><a href="http://hl7-fhir.github.io/">DSTU3 1.4.0 Snapshot</a> (SVN 8636)</td>
<td><a href="http://hl7-fhir.github.io/">STU3 1.4.0 Snapshot</a> (SVN 8636)</td>
</tr>
<tr>
<td>1.6.1</td>
<td><a href="http://hl7-fhir.github.io/">DSTU3 1.5.0 Snapshot</a> (SVN 8856)</td>
<td>2.0</td>
<td><a href="http://hl7-fhir.github.io/">STU3 1.5.0 Snapshot</a> (SVN 9395)</td>
</tr>
</tbody>
</table>