diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java index ca1908328e1..0d800084e15 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java @@ -30,6 +30,7 @@ import ca.uhn.fhir.util.UrlUtil; import com.google.common.base.Charsets; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.hl7.fhir.instance.model.api.*; @@ -908,11 +909,11 @@ public abstract class BaseParser implements IParser { } else { if (myDontEncodeElements != null) { String resourceName = myContext.getResourceDefinition(theResource).getName(); - if (myDontEncodeElements.stream().anyMatch(t -> t.startsWithPath(resourceName + ".id"))) { + if (myDontEncodeElements.stream().anyMatch(t -> t.equalsPath(resourceName + ".id"))) { retVal = false; - } else if (myDontEncodeElements.stream().anyMatch(t -> t.startsWithPath("*.id"))) { + } else if (myDontEncodeElements.stream().anyMatch(t -> t.equalsPath("*.id"))) { retVal = false; - } else if (theEncodeContext.getResourcePath().size() == 1 && myDontEncodeElements.stream().anyMatch(t -> t.startsWithPath("id"))) { + } else if (theEncodeContext.getResourcePath().size() == 1 && myDontEncodeElements.stream().anyMatch(t -> t.equalsPath("id"))) { retVal = false; } } @@ -924,12 +925,19 @@ public abstract class BaseParser implements IParser { * Used for DSTU2 only */ protected boolean shouldEncodeResourceMeta(IResource theResource) { + return shouldEncodePath(theResource, "meta"); + } + + /** + * Used for DSTU2 only + */ + protected boolean shouldEncodePath(IResource theResource, String thePath) { if (myDontEncodeElements != null) { String resourceName = myContext.getResourceDefinition(theResource).getName(); - if (myDontEncodeElements.stream().anyMatch(t -> t.startsWithPath(resourceName + ".meta"))) { + if (myDontEncodeElements.stream().anyMatch(t -> t.equalsPath(resourceName + "." + thePath))) { + return false; + } else if (myDontEncodeElements.stream().anyMatch(t -> t.equalsPath("*."+ thePath))) { return false; - } else { - return myDontEncodeElements.stream().anyMatch(t -> t.startsWithPath("*.meta")); } } return true; @@ -1207,8 +1215,9 @@ public abstract class BaseParser implements IParser { return true; } - public boolean startsWithPath(String thePath) { - return startsWith(new ElementsPath(thePath)); + public boolean equalsPath(String thePath) { + ElementsPath parsedPath = new ElementsPath(thePath); + return getPath().equals(parsedPath.getPath()); } } @@ -1289,6 +1298,24 @@ public abstract class BaseParser implements IParser { return false; } + @Override + public boolean equals(Object theO) { + if (this == theO) { + return true; + } + + if (theO == null || getClass() != theO.getClass()) { + return false; + } + + EncodeContextPathElement that = (EncodeContextPathElement) theO; + + return new EqualsBuilder() + .append(myResource, that.myResource) + .append(myName, that.myName) + .isEquals(); + } + @Override public int hashCode() { return new HashCodeBuilder(17, 37) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java index 1a209457805..4c6e3ea532b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java @@ -649,8 +649,13 @@ public class JsonParser extends BaseParser implements IJsonLikeParser { if (super.shouldEncodeResourceMeta(resource) && (ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles) == false) || !extensionMetadataKeys.isEmpty()) { beginObject(theEventWriter, "meta"); - writeOptionalTagWithTextNode(theEventWriter, "versionId", versionIdPart); - writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", updated); + + if (shouldEncodePath(resource, "meta.versionId")) { + writeOptionalTagWithTextNode(theEventWriter, "versionId", versionIdPart); + } + if (shouldEncodePath(resource, "meta.lastUpdated")) { + writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", updated); + } if (profiles != null && profiles.isEmpty() == false) { beginArray(theEventWriter, "profile"); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java index 3d7670151f2..636cfd5ca9e 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java @@ -526,9 +526,13 @@ public class XmlParser extends BaseParser /* implements IParser */ { if (super.shouldEncodeResourceMeta(resource) && ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles) == false) { theEventWriter.writeStartElement("meta"); - writeOptionalTagWithValue(theEventWriter, "versionId", versionIdPart); + if (shouldEncodePath(resource, "meta.versionId")) { + writeOptionalTagWithValue(theEventWriter, "versionId", versionIdPart); + } if (updated != null) { - writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString()); + if (shouldEncodePath(resource, "meta.lastUpdated")) { + writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString()); + } } for (IIdType profile : profiles) { 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 cba11dc0a9a..4cb94a109b2 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 @@ -38,6 +38,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.*; import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -72,6 +73,29 @@ public class JsonParserDstu2Test { } + @Test + public void testSetDontEncodeResourcesWithMetaSubPath() { + Patient p = new Patient(); + ResourceMetadataKeyEnum.VERSION.put(p, "BBB"); + p.setId("AAA"); + p.getMeta().setVersionId("BBB"); + p.getMeta().setLastUpdated(new InstantDt("2011-01-01T00:00:00.000Z").getValue()); + p.getMeta().addTag().setSystem("SYS").setCode("CODE"); + p.addName().addFamily("FAMILY"); + + IParser parser = ourCtx.newJsonParser(); + parser.setDontEncodeElements(Sets.newHashSet("id", "*.meta.versionId", "*.meta.lastUpdated")); + String output = parser.encodeResourceToString(p); + + assertThat(output, containsString("FAMILY")); + assertThat(output, containsString("SYS")); + assertThat(output, containsString("CODE")); + assertThat(output, not(containsString("AAA"))); + assertThat(output, not(containsString("BBB"))); + assertThat(output, not(containsString("2011"))); + } + + @Test public void testBaseUrlFooResourceCorrectlySerializedInExtensionValueReference() { String refVal = "http://my.org/FooBar"; diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java index 4a3ee35ff36..f42ad461da9 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java @@ -1,6 +1,7 @@ package ca.uhn.fhir.parser; import static org.hamcrest.Matchers.*; +import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; @@ -189,6 +190,29 @@ public class XmlParserDstu2Test { parser.parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, string); } + @Test + public void testSetDontEncodeResourcesWithMetaSubPath() { + Patient p = new Patient(); + ResourceMetadataKeyEnum.VERSION.put(p, "BBB"); + p.setId("AAA"); + p.getMeta().setVersionId("BBB"); + p.getMeta().setLastUpdated(new InstantDt("2011-01-01T00:00:00.000Z").getValue()); + p.getMeta().addTag().setSystem("SYS").setCode("CODE"); + p.addName().addFamily("FAMILY"); + + IParser parser = ourCtx.newXmlParser(); + parser.setDontEncodeElements(Sets.newHashSet("id", "*.meta.versionId", "*.meta.lastUpdated")); + String output = parser.encodeResourceToString(p); + + assertThat(output, containsString("FAMILY")); + assertThat(output, containsString("SYS")); + assertThat(output, containsString("CODE")); + assertThat(output, not(containsString("AAA"))); + assertThat(output, not(containsString("BBB"))); + assertThat(output, not(containsString("2011"))); + } + + @Test() public void testContainedResourceWithNoIdLenient() throws IOException { String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_contained_with_no_id.xml"), StandardCharsets.UTF_8); diff --git a/osgi/hapi-fhir-karaf-integration-tests/src/test/java/ca/uhn/fhir/tests/integration/karaf/r4/R4JsonParserTest.java b/osgi/hapi-fhir-karaf-integration-tests/src/test/java/ca/uhn/fhir/tests/integration/karaf/r4/R4JsonParserTest.java index 766e900904a..8dc714c8e6e 100644 --- a/osgi/hapi-fhir-karaf-integration-tests/src/test/java/ca/uhn/fhir/tests/integration/karaf/r4/R4JsonParserTest.java +++ b/osgi/hapi-fhir-karaf-integration-tests/src/test/java/ca/uhn/fhir/tests/integration/karaf/r4/R4JsonParserTest.java @@ -8,14 +8,7 @@ import ca.uhn.fhir.parser.IParser; import com.google.common.collect.Sets; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; -import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Extension; -import org.hl7.fhir.r4.model.Medication; -import org.hl7.fhir.r4.model.MedicationDispense; -import org.hl7.fhir.r4.model.MedicationRequest; -import org.hl7.fhir.r4.model.Patient; -import org.hl7.fhir.r4.model.Reference; -import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.*; import org.junit.Test; import org.junit.runner.RunWith; import org.ops4j.pax.exam.Configuration; @@ -32,6 +25,7 @@ import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.contains; import static org.ops4j.pax.exam.CoreOptions.mavenBundle; import static org.ops4j.pax.exam.CoreOptions.options; import static org.ops4j.pax.exam.CoreOptions.when; @@ -166,6 +160,28 @@ public class R4JsonParserTest { assertThat(encoded, containsString(longString)); } + + @Test + public void testSetDontEncodeResourcesWithMetaSubPath() { + Patient p = new Patient(); + p.setId("AAA"); + p.getMeta().setVersionId("BBB"); + p.getMeta().setLastUpdatedElement(new InstantType("2011-01-01T00:00:00.000Z")); + p.getMeta().addTag().setSystem("SYS").setCode("CODE"); + p.addName().setFamily("FAMILY"); + + IParser parser = ourCtx.newJsonParser(); + parser.setDontEncodeElements(Sets.newHashSet("id", "*.meta.versionId", "*.meta.lastUpdated")); + String output = parser.encodeResourceToString(p); + + assertThat(output, containsString("FAMILY")); + assertThat(output, containsString("SYS")); + assertThat(output, containsString("CODE")); + assertThat(output, not(containsString("AAA"))); + assertThat(output, not(containsString("BBB"))); + assertThat(output, not(containsString("2011"))); + } + @Test public void testParseAndEncodeExtensionWithValueWithExtension() { String input = "{\n" +