From cac44c736ce5a33b3dabec783f3f82bd93232b81 Mon Sep 17 00:00:00 2001 From: Sebastien Riviere Date: Thu, 19 Jan 2017 14:54:17 +0100 Subject: [PATCH 1/4] Add the possibility to use the serverBaseUrl to generate the url of extension, if %BASE_SERVER_URL% is found --- .../java/ca/uhn/fhir/parser/BaseParser.java | 4 +++ .../java/ca/uhn/fhir/parser/JsonParser.java | 10 +++---- .../java/ca/uhn/fhir/parser/XmlParser.java | 8 ++--- .../uhn/fhir/parser/CustomPatientDstu2.java | 29 +++++++++++++++++++ .../uhn/fhir/parser/JsonParserDstu2Test.java | 20 ++++++++++++- .../uhn/fhir/parser/XmlParserDstu2Test.java | 17 +++++++++++ .../uhn/fhir/parser/CustomPatientDstu3.java | 29 +++++++++++++++++++ .../uhn/fhir/parser/JsonParserDstu3Test.java | 18 ++++++++++++ .../uhn/fhir/parser/XmlParserDstu3Test.java | 17 +++++++++++ 9 files changed, 142 insertions(+), 10 deletions(-) create mode 100644 hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu2.java create mode 100644 hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu3.java 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 3c764c9d313..d0cc5b81dd8 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 @@ -931,6 +931,10 @@ public abstract class BaseParser implements IParser { return retVal; } + protected String getExtensionUrl(final String extensionUrl) { + return StringUtils.isNotBlank(extensionUrl) && StringUtils.isNotBlank(myServerBaseUrl) ? extensionUrl.replace("%BASE_SERVER_URL%", myServerBaseUrl) : extensionUrl; + } + /** * Used for DSTU2 only */ 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 6f8868c4f02..8ea6378b91b 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 @@ -1405,7 +1405,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser { getErrorHandler().missingRequiredElement(new ParseLocation(parentElementName), "url"); url = null; } else { - url = jsonElement.getAsString(); + url = getExtensionUrl(jsonElement.getAsString()); } theState.enteringNewElementExtension(null, url, theIsModifier); for (String next : nextExtObj.keySet()) { @@ -1758,8 +1758,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser { public int compareTo(HeldExtension theArg0) { String url1 = myDef != null ? myDef.getExtensionUrl() : myUndeclaredExtension.getUrl(); String url2 = theArg0.myDef != null ? theArg0.myDef.getExtensionUrl() : theArg0.myUndeclaredExtension.getUrl(); - url1 = defaultString(url1); - url2 = defaultString(url2); + url1 = defaultString(getExtensionUrl(url1)); + url2 = defaultString(getExtensionUrl(url2)); return url1.compareTo(url2); } @@ -1771,7 +1771,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser { writeCommentsPreAndPost(myValue, theEventWriter); - JsonParser.write(theEventWriter, "url", myDef.getExtensionUrl()); + JsonParser.write(theEventWriter, "url", getExtensionUrl(myDef.getExtensionUrl())); /* * This makes sure that even if the extension contains a reference to a contained @@ -1797,7 +1797,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser { private void writeUndeclaredExtension(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, IBaseExtension ext) throws IOException { IBase value = ext.getValue(); - String extensionUrl = ext.getUrl(); + final String extensionUrl = getExtensionUrl(ext.getUrl()); theEventWriter.beginObject(); 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 a0fbff92853..f1835e905bd 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 @@ -655,11 +655,11 @@ public class XmlParser extends BaseParser implements IParser { String childName = childNameAndDef.getChildName(); BaseRuntimeElementDefinition childDef = childNameAndDef.getChildDef(); - String extensionUrl = nextChild.getExtensionUrl(); + String extensionUrl = getExtensionUrl(nextChild.getExtensionUrl()); if (nextValue instanceof IBaseExtension && myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) { // This is called for the Query resource in DSTU1 only - extensionUrl = ((IBaseExtension) nextValue).getUrl(); + extensionUrl = getExtensionUrl(((IBaseExtension) nextValue).getUrl()); encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theContainedResource, nextChildElem); } else if (extensionUrl != null && childName.equals("extension") == false) { @@ -671,7 +671,7 @@ public class XmlParser extends BaseParser implements IParser { continue; } } - encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extension.getUrl(), theContainedResource, nextChildElem); + encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, getExtensionUrl(extension.getUrl()), theContainedResource, nextChildElem); } else if (nextChild instanceof RuntimeChildNarrativeDefinition && theContainedResource) { // suppress narratives from contained resources } else { @@ -902,7 +902,7 @@ public class XmlParser extends BaseParser implements IParser { theEventWriter.writeAttribute("id", elementId); } - String url = next.getUrl(); + String url = getExtensionUrl(next.getUrl()); theEventWriter.writeAttribute("url", url); if (next.getValue() != null) { diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu2.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu2.java new file mode 100644 index 00000000000..89a0e4a0ba0 --- /dev/null +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu2.java @@ -0,0 +1,29 @@ +package ca.uhn.fhir.parser; + +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.Extension; +import ca.uhn.fhir.model.api.annotation.ResourceDef; +import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.primitive.BooleanDt; + +@ResourceDef(name = "Patient", profile = "Patient") +public class CustomPatientDstu2 extends Patient { + + + private static final long serialVersionUID = 1L; + + @Child(name = "homeless", order = 1) + @Extension(url = "%BASE_SERVER_URL%/StructureDefinition/homeless", definedLocally = true, isModifier = false) + @Description(shortDefinition = "The patient being homeless, true if homeless") + private BooleanDt homeless; + + + public BooleanDt getHomeless() { + return homeless; + } + + public void setHomeless(final BooleanDt homeless) { + this.homeless = homeless; + } +} \ No newline at end of file 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 567b6c4fc89..456796e10a0 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 @@ -9,6 +9,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -48,6 +49,7 @@ import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum; import ca.uhn.fhir.model.dstu2.valueset.MaritalStatusCodesEnum; import ca.uhn.fhir.model.dstu2.valueset.ObservationStatusEnum; import ca.uhn.fhir.model.dstu2.valueset.UnknownContentCodeEnum; +import ca.uhn.fhir.model.primitive.BooleanDt; import ca.uhn.fhir.model.primitive.CodeDt; import ca.uhn.fhir.model.primitive.DateDt; import ca.uhn.fhir.model.primitive.DateTimeDt; @@ -1871,5 +1873,21 @@ public class JsonParserDstu2Test { assertEquals("2011-01-01", condition.getDateRecordedElement().getValueAsString()); } - + + /** + * Test for the url generated based on the server config + */ + @Test + public void testGeneratedUrls() { + final IParser jsonParser = ourCtx.newJsonParser().setPrettyPrint(true); + jsonParser.setServerBaseUrl("http://myserver.com"); + + final CustomPatientDstu2 patient = new CustomPatientDstu2(); + patient.setHomeless(new BooleanDt(true)); + + final String parsedPatient = jsonParser.encodeResourceToString(patient); + + assertTrue(parsedPatient.contains("http://myserver.com/StructureDefinition/Patient")); + assertTrue(parsedPatient.contains("http://myserver.com/StructureDefinition/homeless")); + } } 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 441acc63334..b2f2419959b 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 @@ -2726,6 +2726,23 @@ public class XmlParserDstu2Test { assertEquals("Patient", reincarnatedPatient.getId().getResourceType()); } + /** + * Test for the url generated based on the server config + */ + @Test + public void testGeneratedUrls() { + final IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + xmlParser.setServerBaseUrl("http://myserver.com"); + + final CustomPatientDstu2 patient = new CustomPatientDstu2(); + patient.setHomeless(new BooleanDt(true)); + + final String parsedPatient = xmlParser.encodeResourceToString(patient); + + assertTrue(parsedPatient.contains("")); + assertTrue(parsedPatient.contains("")); + } + @AfterClass public static void afterClassClearContext() { TestUtil.clearAllStaticFieldsForUnitTest(); diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu3.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu3.java new file mode 100644 index 00000000000..66812ad51e2 --- /dev/null +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu3.java @@ -0,0 +1,29 @@ +package ca.uhn.fhir.parser; + +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.Extension; +import ca.uhn.fhir.model.api.annotation.ResourceDef; +import org.hl7.fhir.dstu3.model.BooleanType; +import org.hl7.fhir.dstu3.model.Patient; + +@ResourceDef(name = "Patient", profile = "Patient") +public class CustomPatientDstu3 extends Patient { + + + private static final long serialVersionUID = 1L; + + @Child(name = "homeless", order = 1) + @Extension(url = "%BASE_SERVER_URL%/StructureDefinition/homeless", definedLocally = true, isModifier = false) + @Description(shortDefinition = "The patient being homeless, true if homeless") + private BooleanType homeless; + + + public BooleanType getHomeless() { + return homeless; + } + + public void setHomeless(final BooleanType homeless) { + this.homeless = homeless; + } +} \ No newline at end of file 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 bc5ac21e26f..e587cfcca0d 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 @@ -40,6 +40,7 @@ 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.BooleanType; import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleType; @@ -2176,6 +2177,23 @@ public class JsonParserDstu3Test { assertTrue(result.isSuccessful()); } + /** + * Test for the url generated based on the server config + */ + @Test + public void testGeneratedUrls() { + final IParser jsonParser = ourCtx.newJsonParser().setPrettyPrint(true); + jsonParser.setServerBaseUrl("http://myserver.com"); + + final CustomPatientDstu3 patient = new CustomPatientDstu3(); + patient.setHomeless(new BooleanType(true)); + + final String parsedPatient = jsonParser.encodeResourceToString(patient); + + assertTrue(parsedPatient.contains("http://myserver.com/StructureDefinition/Patient")); + assertTrue(parsedPatient.contains("http://myserver.com/StructureDefinition/homeless")); + } + @AfterClass public static void afterClassClearContext() { TestUtil.clearAllStaticFieldsForUnitTest(); 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 1b00e00eca8..2668d5d5073 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 @@ -3139,6 +3139,23 @@ public class XmlParserDstu3Test { } + /** + * Test for the url generated based on the server config + */ + @Test + public void testGeneratedUrls() { + final IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + xmlParser.setServerBaseUrl("http://myserver.com"); + + final CustomPatientDstu3 patient = new CustomPatientDstu3(); + patient.setHomeless(new BooleanType(true)); + + final String parsedPatient = xmlParser.encodeResourceToString(patient); + + assertTrue(parsedPatient.contains("")); + assertTrue(parsedPatient.contains("")); + } + @AfterClass public static void afterClassClearContext() { TestUtil.clearAllStaticFieldsForUnitTest(); From 13646168f0eeacb04c807194739da5c63552fe1d Mon Sep 17 00:00:00 2001 From: Sebastien Riviere Date: Thu, 19 Jan 2017 14:55:42 +0100 Subject: [PATCH 2/4] Use the profile of the datatype if available, intead of the default hl7.org url --- .../hl7/fhir/dstu3/elementmodel/Property.java | 9 ++++++- .../validation/InstanceValidator.java | 25 ++++++++++++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/elementmodel/Property.java b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/elementmodel/Property.java index 0c5a2510b81..62ade417214 100644 --- a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/elementmodel/Property.java +++ b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/elementmodel/Property.java @@ -3,6 +3,7 @@ package org.hl7.fhir.dstu3.elementmodel; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.dstu3.conformance.ProfileUtilities; import org.hl7.fhir.dstu3.context.IWorkerContext; import org.hl7.fhir.dstu3.formats.FormatUtilities; @@ -240,7 +241,13 @@ public class Property { } } if (!"xhtml".equals(t)) { - sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+t); + final String url; + if (StringUtils.isNotBlank(ed.getType().get(0).getProfile())) { + url = ed.getType().get(0).getProfile(); + } else { + url = "http://hl7.org/fhir/StructureDefinition/" + t; + } + sd = context.fetchResource(StructureDefinition.class, url); if (sd == null) throw new DefinitionException("Unable to find class '"+t+"' for name '"+elementName+"' on property "+definition.getPath()); children = ProfileUtilities.getChildMap(sd, sd.getSnapshot().getElement().get(0)); diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/validation/InstanceValidator.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/validation/InstanceValidator.java index 8c453d9900c..5a323ca47ff 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/validation/InstanceValidator.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/validation/InstanceValidator.java @@ -993,8 +993,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return null; } - private StructureDefinition getProfileForType(String type) throws Exception { - return context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + type); + private StructureDefinition getProfileForType(ElementDefinition ed, String type) throws Exception { + //return context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + type); + final String url; + if (!"Reference".equals(type) && ed.getType().get(0).hasProfile()) { + url = ed.getType().get(0).getProfile().get(0).getValue(); + } else { + url = "http://hl7.org/fhir/StructureDefinition/" + type; + } + return context.fetchResource(StructureDefinition.class, url); } private Element getValueForDiscriminator(WrapperElement element, String discriminator, ElementDefinition criteria) { @@ -1182,8 +1189,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return context.fetchResource(StructureDefinition.class, pr); } - private ElementDefinition resolveType(String type) throws EOperationOutcome, Exception { - String url = "http://hl7.org/fhir/StructureDefinition/" + type; + private ElementDefinition resolveType(ElementDefinition ed, String type) throws EOperationOutcome, Exception { + final String url; + if (ed.getType().get(0).hasProfile()) { + url = ed.getType().get(0).getProfile().get(0).getValue(); + } else { + url = "http://hl7.org/fhir/StructureDefinition/" + type; + } + StructureDefinition sd = context.fetchResource(StructureDefinition.class, url); if (sd == null || !sd.hasSnapshot()) return null; @@ -1803,7 +1816,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat type = null; } } - NodeStack localStack = stack.push(ei.element, ei.count, ei.definition, type == null ? typeDefn : resolveType(type)); + NodeStack localStack = stack.push(ei.element, ei.count, ei.definition, type == null ? typeDefn : resolveType(ei.definition, type)); String localStackLiterapPath = localStack.getLiteralPath(); String eiPath = ei.path; assert(eiPath.equals(localStackLiterapPath)) : "ei.path: " + ei.path + " - localStack.getLiterapPath: " + localStackLiterapPath; @@ -1828,7 +1841,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat validateContains(errors, ei.path, ei.definition, definition, ei.element, localStack, !isBundleEntry(ei.path) && !isParametersEntry(ei.path)); // if // (str.matches(".*([.,/])work\\1$")) else { - StructureDefinition p = getProfileForType(type); + StructureDefinition p = getProfileForType(ei.definition, type); if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.path, p != null, "Unknown type " + type)) { validateElement(errors, p, p.getSnapshot().getElement().get(0), profile, ei.definition, ei.element, type, localStack); } From 6cc7eeb45c9ac41a514c0ad44ffc2499805dadad Mon Sep 17 00:00:00 2001 From: Sebastien Riviere Date: Thu, 19 Jan 2017 14:57:14 +0100 Subject: [PATCH 3/4] Generate CapabilityStatement for DSTU3 conformance, Enable @Validate for Jax-rs server --- .../AbstractJaxRsConformanceProvider.java | 19 ++++++++------- .../jaxrs/server/AbstractJaxRsProvider.java | 4 +++- .../server/AbstractJaxRsResourceProvider.java | 6 +++++ ...bstractJaxRsResourceProviderDstu3Test.java | 24 ++++++++++++++++--- .../AbstractJaxRsResourceProviderTest.java | 20 +++++++++++++++- .../TestJaxRsMockPatientRestProvider.java | 9 +++++++ ...TestJaxRsMockPatientRestProviderDstu3.java | 9 +++++++ 7 files changed, 78 insertions(+), 13 deletions(-) diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java index f3648c2c667..95bffc90f88 100644 --- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java @@ -41,8 +41,10 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.commons.lang3.StringUtils; -import org.hl7.fhir.dstu3.hapi.rest.server.ServerConformanceProvider; -import org.hl7.fhir.dstu3.model.Conformance; +import org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider; +import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider; +import org.hl7.fhir.dstu3.model.CapabilityStatement; +import ca.uhn.fhir.model.dstu2.resource.Conformance; import org.hl7.fhir.instance.model.api.IBaseResource; import org.slf4j.LoggerFactory; @@ -83,8 +85,8 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv private RestulfulServerConfiguration serverConfiguration = new RestulfulServerConfiguration(); /** the conformance. It is created once during startup */ - private Conformance myDstu3Conformance; - private ca.uhn.fhir.model.dstu2.resource.Conformance myDstu2Conformance; + private CapabilityStatement myDstu3Conformance; + private Conformance myDstu2Conformance; /** * Constructor allowing the description, servername and server to be set @@ -142,11 +144,12 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv hardcodedServerAddressStrategy.setValue(getBaseForServer()); serverConfiguration.setServerAddressStrategy(hardcodedServerAddressStrategy); if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) { - ServerConformanceProvider serverConformanceProvider = new ServerConformanceProvider(serverConfiguration); + // ServerConformanceProvider serverConformanceProvider = new ServerConformanceProvider(serverConfiguration); + final ServerCapabilityStatementProvider serverConformanceProvider = new ServerCapabilityStatementProvider((serverConfiguration)); serverConformanceProvider.initializeOperations(); myDstu3Conformance = serverConformanceProvider.getServerConformance(null); } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) { - ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider serverConformanceProvider = new ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider(serverConfiguration); + ServerConformanceProvider serverConformanceProvider = new ServerConformanceProvider(serverConfiguration); serverConformanceProvider.initializeOperations(); myDstu2Conformance = serverConformanceProvider.getServerConformance(null); } @@ -275,9 +278,9 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv @Override public Class getResourceType() { if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) { - return Class.class.cast(Conformance.class); + return Class.class.cast(CapabilityStatement.class); } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) { - return Class.class.cast(ca.uhn.fhir.model.dstu2.resource.Conformance.class); + return Class.class.cast(Conformance.class); } return null; } diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java index d1faa8eaae5..35e4a378cbb 100644 --- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java @@ -32,6 +32,7 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; @@ -125,7 +126,8 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults { * @return the ascii string for the server base */ public String getBaseForServer() { - return getUriInfo().getBaseUri().toASCIIString(); + final String url = getUriInfo().getBaseUri().toASCIIString(); + return StringUtils.isNotBlank(url) && url.endsWith("/") ? url.substring(0, url.length() - 1) : url; } /** diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java index 6d4cee89274..8b1a86ccb4c 100644 --- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java @@ -286,6 +286,12 @@ implements IRestfulServer, IResourceProvider { return execute(theRequest, compartment); } + @POST + @Path("/$validate") + public Response validate(final String resource) throws IOException { + return customOperation(resource, RequestTypeEnum.POST, null, "$validate", RestOperationTypeEnum.EXTENDED_OPERATION_TYPE); + } + /** * Execute the method described by the requestBuilder and methodKey * diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderDstu3Test.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderDstu3Test.java index efb8508273c..ebdfbbe1b61 100644 --- a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderDstu3Test.java +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderDstu3Test.java @@ -1,7 +1,9 @@ package ca.uhn.fhir.jaxrs.server; import static org.junit.Assert.assertEquals; + import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -24,10 +26,11 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; -import org.hl7.fhir.dstu3.model.Conformance; +import org.hl7.fhir.dstu3.model.CapabilityStatement; import org.hl7.fhir.dstu3.model.DateType; import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.Identifier; +import org.hl7.fhir.dstu3.model.OperationOutcome; import org.hl7.fhir.dstu3.model.Parameters; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Resource; @@ -154,7 +157,7 @@ public class AbstractJaxRsResourceProviderDstu3Test { toCreate.getIdentifier().add(new Identifier().setValue("myIdentifier")); outcome.setResource(toCreate); - when(mock.create(patientCaptor.capture(), eq("Patient?_format=json&identifier=2"))).thenReturn(outcome); + when(mock.create(patientCaptor.capture(), eq("/Patient?_format=json&identifier=2"))).thenReturn(outcome); client.setEncoding(EncodingEnum.JSON); MethodOutcome response = client.create().resource(toCreate).conditional() @@ -168,7 +171,7 @@ public class AbstractJaxRsResourceProviderDstu3Test { /** Conformance - Server */ @Test public void testConformance() { - final Conformance conf = client.fetchConformance().ofType(Conformance.class).execute(); + final CapabilityStatement conf = client.fetchConformance().ofType(CapabilityStatement.class).execute(); assertEquals(conf.getRest().get(0).getResource().get(0).getType().toString(), "Patient"); } @@ -426,6 +429,21 @@ public class AbstractJaxRsResourceProviderDstu3Test { assertTrue(e.getMessage().contains("999955541264")); } } + + @Test + public void testValidate() { + // prepare mock + final OperationOutcome oo = new OperationOutcome(); + final Patient patient = new Patient(); + patient.addIdentifier((new Identifier().setValue("1"))); + //invoke + final Parameters inParams = new Parameters(); + inParams.addParameter().setResource(patient); + + final MethodOutcome mO = client.validate().resource(patient).execute(); + //verify + assertNotNull(mO.getOperationOutcome()); + } @BeforeClass public static void setUpClass() throws Exception { diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderTest.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderTest.java index 837f2509963..7bd8fdf928d 100644 --- a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderTest.java +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderTest.java @@ -1,6 +1,7 @@ package ca.uhn.fhir.jaxrs.server; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -44,9 +45,11 @@ import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProvider; import ca.uhn.fhir.model.api.BundleEntry; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.base.resource.BaseOperationOutcome; +import ca.uhn.fhir.model.dstu2.composite.IdentifierDt; import ca.uhn.fhir.model.dstu2.resource.Bundle; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Conformance; +import ca.uhn.fhir.model.dstu2.resource.OperationOutcome; import ca.uhn.fhir.model.dstu2.resource.Parameters; import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.model.primitive.BoundCodeDt; @@ -152,7 +155,7 @@ public class AbstractJaxRsResourceProviderTest { toCreate.getIdentifierFirstRep().setValue("myIdentifier"); outcome.setResource(toCreate); - when(mock.create(patientCaptor.capture(), eq("Patient?_format=json&identifier=2"))).thenReturn(outcome); + when(mock.create(patientCaptor.capture(), eq("/Patient?_format=json&identifier=2"))).thenReturn(outcome); client.setEncoding(EncodingEnum.JSON); MethodOutcome response = client.create().resource(toCreate).conditional() @@ -411,6 +414,21 @@ public class AbstractJaxRsResourceProviderTest { } } + @Test + public void testValidate() { + // prepare mock + final OperationOutcome oo = new OperationOutcome(); + final Patient patient = new Patient(); + patient.addIdentifier((new IdentifierDt().setValue("1"))); + //invoke + final Parameters inParams = new Parameters(); + inParams.addParameter().setResource(patient); + + final MethodOutcome mO = client.validate().resource(patient).execute(); + //verify + assertNotNull(mO.getOperationOutcome()); + } + private T withId(final T id) { return argThat(new BaseMatcher() { @Override diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProvider.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProvider.java index 8181857cf1b..aae7f63c4df 100644 --- a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProvider.java @@ -17,6 +17,7 @@ import org.mockito.Mockito; import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider; import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor; import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu2.resource.OperationOutcome; import ca.uhn.fhir.model.dstu2.resource.Parameters; import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.model.primitive.IdDt; @@ -32,6 +33,7 @@ import ca.uhn.fhir.rest.annotation.RequiredParam; import ca.uhn.fhir.rest.annotation.ResourceParam; import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.annotation.Validate; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; @@ -125,6 +127,13 @@ public class TestJaxRsMockPatientRestProvider extends AbstractJaxRsResourceProvi public Parameters someCustomOperation(@IdParam IdDt myId, @OperationParam(name = "dummy") StringDt dummyInput) { return mock.someCustomOperation(myId, dummyInput); } + + @Validate() + public MethodOutcome validate(@ResourceParam final Patient resource) { + final MethodOutcome mO = new MethodOutcome(); + mO.setOperationOutcome(new OperationOutcome()); + return mO; + } @Override public Class getResourceType() { diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu3.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu3.java index c36a5a1d6bf..6ebfa89393c 100644 --- a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu3.java +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu3.java @@ -13,6 +13,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.OperationOutcome; import org.hl7.fhir.dstu3.model.Parameters; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.StringType; @@ -34,6 +35,7 @@ import ca.uhn.fhir.rest.annotation.RequiredParam; import ca.uhn.fhir.rest.annotation.ResourceParam; import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.annotation.Validate; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; @@ -128,6 +130,13 @@ public class TestJaxRsMockPatientRestProviderDstu3 extends AbstractJaxRsResource return mock.someCustomOperation(myId, dummyInput); } + @Validate() + public MethodOutcome validate(@ResourceParam final Patient resource) { + MethodOutcome mO = new MethodOutcome(); + mO.setOperationOutcome(new OperationOutcome()); + return mO; + } + @Override public Class getResourceType() { return Patient.class; From c3447c3b4de9e39004be90035b266c31bd092115 Mon Sep 17 00:00:00 2001 From: Sebastien Riviere Date: Wed, 8 Feb 2017 11:14:19 +0100 Subject: [PATCH 4/4] Remove substitution string to use relative url, Fix client parser and custom extension. --- .../context/BaseRuntimeElementDefinition.java | 15 ++++- .../ca/uhn/fhir/model/view/ViewGenerator.java | 2 +- .../java/ca/uhn/fhir/parser/BaseParser.java | 11 ++- .../java/ca/uhn/fhir/parser/JsonParser.java | 2 +- .../java/ca/uhn/fhir/parser/ParserState.java | 18 ++--- .../java/ca/uhn/fhir/parser/XmlParser.java | 4 +- .../ca/uhn/fhir/rest/client/BaseClient.java | 1 + .../fhir/rest/param/ResourceParameter.java | 2 +- .../fhir/context/ModelScannerDstu1Test.java | 6 +- .../ca/uhn/fhir/parser/JsonParserTest.java | 63 +++++++++++++++++ .../MyPatientWithCustomUrlExtension.java | 38 +++++++++++ .../ca/uhn/fhir/parser/XmlParserTest.java | 63 +++++++++++++++++ .../uhn/fhir/parser/CustomPatientDstu2.java | 2 +- .../uhn/fhir/parser/JsonParserDstu2Test.java | 67 +++++++++++++++++++ .../MyPatientWithCustomUrlExtension.java | 33 +++++++++ .../uhn/fhir/parser/XmlParserDstu2Test.java | 66 ++++++++++++++++++ .../fhir/context/ModelScannerDstu3Test.java | 6 +- .../uhn/fhir/parser/CustomPatientDstu3.java | 2 +- .../uhn/fhir/parser/JsonParserDstu3Test.java | 67 +++++++++++++++++++ .../MyPatientWithCustomUrlExtension.java | 33 +++++++++ .../uhn/fhir/parser/XmlParserDstu3Test.java | 66 ++++++++++++++++++ 21 files changed, 542 insertions(+), 25 deletions(-) create mode 100644 hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java create mode 100644 hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java create mode 100644 hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeElementDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeElementDefinition.java index e4107a028c0..0e89ff019ae 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeElementDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeElementDefinition.java @@ -22,6 +22,7 @@ package ca.uhn.fhir.context; import java.lang.reflect.Constructor; import java.util.*; +import ca.uhn.fhir.util.UrlUtil; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IBase; @@ -100,9 +101,19 @@ public abstract class BaseRuntimeElementDefinition { /** * @return Returns null if none */ - public RuntimeChildDeclaredExtensionDefinition getDeclaredExtension(String theExtensionUrl) { + public RuntimeChildDeclaredExtensionDefinition getDeclaredExtension(String theExtensionUrl, final String serverBaseUrl) { validateSealed(); - return myUrlToExtension.get(theExtensionUrl); + RuntimeChildDeclaredExtensionDefinition definition = myUrlToExtension.get(theExtensionUrl); + if (definition == null && StringUtils.isNotBlank(serverBaseUrl)) { + for (final Map.Entry entry : myUrlToExtension.entrySet()) { + final String key = (!UrlUtil.isValid(entry.getKey()) && StringUtils.isNotBlank(serverBaseUrl)) ? serverBaseUrl + entry.getKey() : entry.getKey(); + if (key.equals(theExtensionUrl)) { + definition = entry.getValue(); + break; + } + } + } + return definition; } public List getExtensions() { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/view/ViewGenerator.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/view/ViewGenerator.java index d235d0bac98..14ff5cdfe04 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/view/ViewGenerator.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/view/ViewGenerator.java @@ -115,7 +115,7 @@ public class ViewGenerator { } private void addExtension(BaseRuntimeElementCompositeDefinition theSourceDef, BaseElement theSource, BaseElement theTarget, RuntimeChildDeclaredExtensionDefinition nextExt, String url) { - RuntimeChildDeclaredExtensionDefinition sourceDeclaredExt = theSourceDef.getDeclaredExtension(url); + RuntimeChildDeclaredExtensionDefinition sourceDeclaredExt = theSourceDef.getDeclaredExtension(url, ""); if (sourceDeclaredExt == null) { for (ExtensionDt next : theSource.getAllUndeclaredExtensions()) { 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 d0cc5b81dd8..a38f5aadac1 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 @@ -77,6 +77,7 @@ import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.util.UrlUtil; public abstract class BaseParser implements IParser { @@ -932,9 +933,17 @@ public abstract class BaseParser implements IParser { } protected String getExtensionUrl(final String extensionUrl) { - return StringUtils.isNotBlank(extensionUrl) && StringUtils.isNotBlank(myServerBaseUrl) ? extensionUrl.replace("%BASE_SERVER_URL%", myServerBaseUrl) : extensionUrl; + String url = extensionUrl; + if (StringUtils.isNotBlank(extensionUrl) && StringUtils.isNotBlank(myServerBaseUrl)) { + url = !UrlUtil.isValid(extensionUrl) && extensionUrl.startsWith("/") ? myServerBaseUrl + extensionUrl : extensionUrl; + } + return url; } + protected String getServerBaseUrl() { + return myServerBaseUrl; + } + /** * Used for DSTU2 only */ 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 abbbb1640b9..a71eeddb317 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 @@ -1407,7 +1407,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser { } else { url = getExtensionUrl(jsonElement.getAsString()); } - theState.enteringNewElementExtension(null, url, theIsModifier); + theState.enteringNewElementExtension(null, url, theIsModifier, getServerBaseUrl()); for (String next : nextExtObj.keySet()) { if ("url".equals(next)) { continue; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java index 9750f68f511..8def4b14b7f 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java @@ -98,8 +98,8 @@ class ParserState { myState.enteringNewElement(theNamespaceUri, theName); } - public void enteringNewElementExtension(StartElement theElem, String theUrlAttr, boolean theIsModifier) { - myState.enteringNewElementExtension(theElem, theUrlAttr, theIsModifier); + public void enteringNewElementExtension(StartElement theElem, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) { + myState.enteringNewElementExtension(theElem, theUrlAttr, theIsModifier, baseServerUrl); } public T getObject() { @@ -791,7 +791,7 @@ class ParserState { * Default implementation just handles undeclared extensions */ @SuppressWarnings("unused") - public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier) { + public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) { if (myPreResourceState != null && getCurrentElement() instanceof ISupportsUndeclaredExtensions) { ExtensionDt newExtension = new ExtensionDt(theIsModifier); newExtension.setUrl(theUrlAttr); @@ -1483,7 +1483,7 @@ class ParserState { } @Override - public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier) { + public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) { RuntimeChildDeclaredExtensionDefinition declaredExtension = myDefinition.getChildExtensionForUrl(theUrlAttr); if (declaredExtension != null) { if (myChildInstance == null) { @@ -1493,7 +1493,7 @@ class ParserState { BaseState newState = new DeclaredExtensionState(getPreResourceState(), declaredExtension, myChildInstance); push(newState); } else { - super.enteringNewElementExtension(theElement, theUrlAttr, theIsModifier); + super.enteringNewElementExtension(theElement, theUrlAttr, theIsModifier, baseServerUrl); } } @@ -1664,13 +1664,13 @@ class ParserState { } @Override - public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier) { - RuntimeChildDeclaredExtensionDefinition declaredExtension = myDefinition.getDeclaredExtension(theUrlAttr); + public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) { + RuntimeChildDeclaredExtensionDefinition declaredExtension = myDefinition.getDeclaredExtension(theUrlAttr, baseServerUrl); if (declaredExtension != null) { BaseState newState = new DeclaredExtensionState(getPreResourceState(), declaredExtension, myInstance); push(newState); } else { - super.enteringNewElementExtension(theElement, theUrlAttr, theIsModifier); + super.enteringNewElementExtension(theElement, theUrlAttr, theIsModifier, baseServerUrl); } } @@ -2466,7 +2466,7 @@ class ParserState { } @Override - public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier) { + public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) { myDepth++; } 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 65e961d621e..422af681a48 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 @@ -213,7 +213,7 @@ public class XmlParser extends BaseParser implements IParser { } else { url = urlAttr.getValue(); } - parserState.enteringNewElementExtension(elem, url, false); + parserState.enteringNewElementExtension(elem, url, false, getServerBaseUrl()); } else if ("modifierExtension".equals(elem.getName().getLocalPart())) { Attribute urlAttr = elem.getAttributeByName(new QName("url")); String url; @@ -223,7 +223,7 @@ public class XmlParser extends BaseParser implements IParser { } else { url = urlAttr.getValue(); } - parserState.enteringNewElementExtension(elem, url, true); + parserState.enteringNewElementExtension(elem, url, true, getServerBaseUrl()); } else { String elementName = elem.getName().getLocalPart(); parserState.enteringNewElement(namespaceURI, elementName); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java index 0cb93da1a37..9b68352f05d 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java @@ -482,6 +482,7 @@ public abstract class BaseClient implements IRestfulClient { throw NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader); } IParser parser = respType.newParser(getFhirContext()); + parser.setServerBaseUrl(getUrlBase()); if (myPreferResponseTypes != null) { parser.setPreferTypes(myPreferResponseTypes); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java index be68f9a766a..8e63a2d11cb 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java @@ -179,7 +179,7 @@ public class ResourceParameter implements IParameter { } IParser parser = encoding.newParser(ctx); - + parser.setServerBaseUrl(theRequest.getFhirServerBase()); T retVal; try { if (theResourceType != null) { diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ModelScannerDstu1Test.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ModelScannerDstu1Test.java index c74ebbc0c9c..c9e3da34244 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ModelScannerDstu1Test.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ModelScannerDstu1Test.java @@ -56,17 +56,17 @@ public class ModelScannerDstu1Test { assertEquals(RuntimeChildCompositeDatatypeDefinition.class, def.getChildByNameOrThrowDataFormatException("identifier").getClass()); - RuntimeChildDeclaredExtensionDefinition ext = def.getDeclaredExtension("http://foo/#f1"); + RuntimeChildDeclaredExtensionDefinition ext = def.getDeclaredExtension("http://foo/#f1", ""); assertNotNull(ext); BaseRuntimeElementDefinition valueString = ext.getChildByName("valueString"); assertNotNull(valueString); - ext = def.getDeclaredExtension("http://foo/#f2"); + ext = def.getDeclaredExtension("http://foo/#f2", ""); assertNotNull(ext); valueString = ext.getChildByName("valueString"); assertNotNull(valueString); - ext = def.getDeclaredExtension("http://bar/#b1"); + ext = def.getDeclaredExtension("http://bar/#b1", ""); assertNotNull(ext); RuntimeChildDeclaredExtensionDefinition childExt = ext.getChildExtensionForUrl("http://bar/#b1/1"); assertNotNull(childExt); diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java index 00968104c63..9e3d081e806 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java @@ -1445,6 +1445,69 @@ public class JsonParserTest { } + @Test + public void testCustomUrlExtension() { + final String expected = "{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://www.example.com/petname\",\"valueString\":\"myName\"}]}"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringDt("myName")); + + final IParser jsonParser = ourCtx.newJsonParser(); + jsonParser.setServerBaseUrl("http://www.example.com"); + + final String parsedPatient = jsonParser.encodeResourceToString(patient); + System.out.println(parsedPatient); + assertEquals(expected, parsedPatient); + + // Parse with string + MyPatientWithCustomUrlExtension newPatient = jsonParser.parseResource(MyPatientWithCustomUrlExtension.class, parsedPatient); + assertEquals("myName", newPatient.getPetName().getValue()); + + // Parse with stream + newPatient = jsonParser.parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertEquals("myName", newPatient.getPetName().getValue()); + + //Check no NPE if base server not configure + newPatient = ourCtx.newJsonParser().parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertNull("myName", newPatient.getPetName()); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + } + + @Test + public void testCustomUrlExtensioninBundle() { + final String expected = "{\"resourceType\":\"Bundle\",\"entry\":[{\"id\":null,\"content\":{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://www.example.com/petname\",\"valueString\":\"myName\"}]}}]}"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringDt("myName")); + + final Bundle bundle = new Bundle(); + final BundleEntry entry = new BundleEntry(); + entry.setResource(patient); + bundle.addEntry(entry); + + final IParser jsonParser = ourCtx.newJsonParser(); + jsonParser.setServerBaseUrl("http://www.example.com"); + + final String parsedBundle = jsonParser.encodeBundleToString(bundle); + System.out.println(parsedBundle); + assertEquals(expected, parsedBundle); + + // Parse with string + Bundle newBundle = jsonParser.parseBundle(parsedBundle); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntries().size()); + Patient newPatient = (Patient) newBundle.getEntries().get(0).getResource(); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + // Parse with stream + newBundle = jsonParser.parseBundle(new StringReader(parsedBundle)); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntries().size()); + newPatient = (Patient) newBundle.getEntries().get(0).getResource(); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + } + @BeforeClass public static void beforeClass() { ourCtx = FhirContext.forDstu1(); diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java new file mode 100644 index 00000000000..cfb5f30e234 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java @@ -0,0 +1,38 @@ +package ca.uhn.fhir.parser; + +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.Extension; +import ca.uhn.fhir.model.api.annotation.ResourceDef; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.StringDt; + +import java.util.ArrayList; +import java.util.List; + +@ResourceDef() +public class MyPatientWithCustomUrlExtension extends Patient { + + private static final long serialVersionUID = 1L; + + @Child(name = "petName") + @Extension(url = "/petname", definedLocally = false, isModifier = false) + @Description(shortDefinition = "The name of the patient's favourite pet") + private StringDt myPetName; + + public StringDt getPetName() { + return myPetName; + } + + @Override + public boolean isEmpty() { + return super.isEmpty() && myPetName.isEmpty(); + } + + public void setPetName(StringDt thePetName) { + myPetName = thePetName; + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java index 12d87c133b6..5a9b3e1df20 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java @@ -1997,6 +1997,69 @@ public class XmlParserTest { assertEquals(15, bundleR.getTotalResults().getValue().intValue()); } + @Test + public void testCustomUrlExtension() { + final String expected = ""; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringDt("myName")); + + final IParser xmlParser = ourCtx.newXmlParser(); + xmlParser.setServerBaseUrl("http://www.example.com"); + + final String parsedPatient = xmlParser.encodeResourceToString(patient); + System.out.println(parsedPatient); + assertEquals(expected, parsedPatient); + + // Parse with string + MyPatientWithCustomUrlExtension newPatient = xmlParser.parseResource(MyPatientWithCustomUrlExtension.class, parsedPatient); + assertEquals("myName", newPatient.getPetName().getValue()); + + // Parse with stream + newPatient = xmlParser.parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertEquals("myName", newPatient.getPetName().getValue()); + + //Check no NPE if base server not configure + newPatient = ourCtx.newXmlParser().parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertNull("myName", newPatient.getPetName()); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + } + + @Test + public void testCustomUrlExtensioninBundle() { + final String expected = "<id/><entry><id/><content type=\"text/xml\"><Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://www.example.com/petname\"><valueString value=\"myName\"/></extension></Patient></content></entry></feed>"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringDt("myName")); + + final Bundle bundle = new Bundle(); + final BundleEntry entry = new BundleEntry(); + entry.setResource(patient); + bundle.addEntry(entry); + + final IParser xmlParser = ourCtx.newXmlParser(); + xmlParser.setServerBaseUrl("http://www.example.com"); + + final String parsedBundle = xmlParser.encodeBundleToString(bundle); + System.out.println(parsedBundle); + assertEquals(expected, parsedBundle); + + // Parse with string + Bundle newBundle = xmlParser.parseBundle(parsedBundle); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntries().size()); + Patient newPatient = (Patient) newBundle.getEntries().get(0).getResource(); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + // Parse with stream + newBundle = xmlParser.parseBundle(new StringReader(parsedBundle)); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntries().size()); + newPatient = (Patient) newBundle.getEntries().get(0).getResource(); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + } + @BeforeClass public static void beforeClass() { XMLUnit.setIgnoreAttributeOrder(true); diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu2.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu2.java index 89a0e4a0ba0..58b2f163d3d 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu2.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu2.java @@ -14,7 +14,7 @@ public class CustomPatientDstu2 extends Patient { private static final long serialVersionUID = 1L; @Child(name = "homeless", order = 1) - @Extension(url = "%BASE_SERVER_URL%/StructureDefinition/homeless", definedLocally = true, isModifier = false) + @Extension(url = "/StructureDefinition/homeless", definedLocally = true, isModifier = false) @Description(shortDefinition = "The patient being homeless, true if homeless") private BooleanDt homeless; 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 844061232d6..b109314a0b3 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 @@ -16,6 +16,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.io.IOException; +import java.io.StringReader; import java.util.*; import org.apache.commons.io.IOUtils; @@ -1933,4 +1934,70 @@ public class JsonParserDstu2Test { assertTrue(parsedPatient.contains("http://myserver.com/StructureDefinition/Patient")); assertTrue(parsedPatient.contains("http://myserver.com/StructureDefinition/homeless")); } + + /** + * Test for the url generated based on the server config + */ + @Test + public void testCustomUrlExtension() { + final String expected = "{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://www.example.com/petname\",\"valueString\":\"myName\"}]}"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringDt("myName")); + + final IParser jsonParser = ourCtx.newJsonParser(); + jsonParser.setServerBaseUrl("http://www.example.com"); + + final String parsedPatient = jsonParser.encodeResourceToString(patient); + System.out.println(parsedPatient); + assertEquals(expected, parsedPatient); + + // Parse with string + MyPatientWithCustomUrlExtension newPatient = jsonParser.parseResource(MyPatientWithCustomUrlExtension.class, parsedPatient); + assertEquals("myName", newPatient.getPetName().getValue()); + + // Parse with stream + newPatient = jsonParser.parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertEquals("myName", newPatient.getPetName().getValue()); + + //Check no NPE if base server not configure + newPatient = ourCtx.newJsonParser().parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertNull("myName", newPatient.getPetName()); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + } + + @Test + public void testCustomUrlExtensioninBundle() { + final String expected = "{\"resourceType\":\"Bundle\",\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://www.example.com/petname\",\"valueString\":\"myName\"}]}}]}"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringDt("myName")); + + final Bundle bundle = new Bundle(); + final BundleEntry entry = new BundleEntry(); + entry.setResource(patient); + bundle.addEntry(entry); + + final IParser jsonParser = ourCtx.newJsonParser(); + jsonParser.setServerBaseUrl("http://www.example.com"); + + final String parsedBundle = jsonParser.encodeBundleToString(bundle); + System.out.println(parsedBundle); + assertEquals(expected, parsedBundle); + + // Parse with string + Bundle newBundle = jsonParser.parseBundle(parsedBundle); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntries().size()); + Patient newPatient = (Patient) newBundle.getEntries().get(0).getResource(); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + // Parse with stream + newBundle = jsonParser.parseBundle(new StringReader(parsedBundle)); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntries().size()); + newPatient = (Patient) newBundle.getEntries().get(0).getResource(); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + } } diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java new file mode 100644 index 00000000000..4b62f4ea575 --- /dev/null +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java @@ -0,0 +1,33 @@ +package ca.uhn.fhir.parser; + +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.Extension; +import ca.uhn.fhir.model.api.annotation.ResourceDef; +import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.primitive.StringDt; + +@ResourceDef() +public class MyPatientWithCustomUrlExtension extends Patient { + + private static final long serialVersionUID = 1L; + + @Child(name = "petName") + @Extension(url = "/petname", definedLocally = false, isModifier = false) + @Description(shortDefinition = "The name of the patient's favourite pet") + private StringDt myPetName; + + public StringDt getPetName() { + return myPetName; + } + + public void setPetName(StringDt thePetName) { + myPetName = thePetName; + } + + @Override + public boolean isEmpty() { + return super.isEmpty() && myPetName.isEmpty(); + } + +} 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 d75e0529fe4..1b3e9617515 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 @@ -2745,6 +2745,72 @@ public class XmlParserDstu2Test { assertTrue(parsedPatient.contains("<extension url=\"http://myserver.com/StructureDefinition/homeless\">")); } + /** + * Test for the url generated based on the server config + */ + @Test + public void testCustomUrlExtension() { + final String expected = "<Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://www.example.com/petname\"><valueString value=\"myName\"/></extension></Patient>"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringDt("myName")); + + final IParser xmlParser = ourCtx.newXmlParser(); + xmlParser.setServerBaseUrl("http://www.example.com"); + + final String parsedPatient = xmlParser.encodeResourceToString(patient); + System.out.println(parsedPatient); + assertEquals(expected, parsedPatient); + + // Parse with string + MyPatientWithCustomUrlExtension newPatient = xmlParser.parseResource(MyPatientWithCustomUrlExtension.class, parsedPatient); + assertEquals("myName", newPatient.getPetName().getValue()); + + // Parse with stream + newPatient = xmlParser.parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertEquals("myName", newPatient.getPetName().getValue()); + + //Check no NPE if base server not configure + newPatient = ourCtx.newXmlParser().parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertNull("myName", newPatient.getPetName()); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + } + + @Test + public void testCustomUrlExtensionInBundle() { + final String expected = "<Bundle xmlns=\"http://hl7.org/fhir\"><entry><resource><Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://www.example.com/petname\"><valueString value=\"myName\"/></extension></Patient></resource></entry></Bundle>"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringDt("myName")); + + final Bundle bundle = new Bundle(); + final BundleEntry entry = new BundleEntry(); + entry.setResource(patient); + bundle.addEntry(entry); + + final IParser xmlParser = ourCtx.newXmlParser(); + xmlParser.setServerBaseUrl("http://www.example.com"); + + final String parsedBundle = xmlParser.encodeBundleToString(bundle); + System.out.println(parsedBundle); + assertEquals(expected, parsedBundle); + + // Parse with string + Bundle newBundle = xmlParser.parseBundle(parsedBundle); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntries().size()); + Patient newPatient = (Patient) newBundle.getEntries().get(0).getResource(); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + // Parse with stream + newBundle = xmlParser.parseBundle(new StringReader(parsedBundle)); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntries().size()); + newPatient = (Patient) newBundle.getEntries().get(0).getResource(); + assertEquals("myName", ((StringDt) newPatient.getUndeclaredExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + } + @AfterClass public static void afterClassClearContext() { TestUtil.clearAllStaticFieldsForUnitTest(); diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/ModelScannerDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/ModelScannerDstu3Test.java index d699828d2a8..edb42d95db3 100644 --- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/ModelScannerDstu3Test.java +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/ModelScannerDstu3Test.java @@ -81,17 +81,17 @@ public class ModelScannerDstu3Test { assertEquals(RuntimeChildCompositeDatatypeDefinition.class, def.getChildByNameOrThrowDataFormatException("identifier").getClass()); - RuntimeChildDeclaredExtensionDefinition ext = def.getDeclaredExtension("http://foo/#f1"); + RuntimeChildDeclaredExtensionDefinition ext = def.getDeclaredExtension("http://foo/#f1", ""); assertNotNull(ext); BaseRuntimeElementDefinition<?> valueString = ext.getChildByName("valueString"); assertNotNull(valueString); - ext = def.getDeclaredExtension("http://foo/#f2"); + ext = def.getDeclaredExtension("http://foo/#f2", ""); assertNotNull(ext); valueString = ext.getChildByName("valueString"); assertNotNull(valueString); - ext = def.getDeclaredExtension("http://bar/#b1"); + ext = def.getDeclaredExtension("http://bar/#b1", ""); assertNotNull(ext); RuntimeChildDeclaredExtensionDefinition childExt = ext.getChildExtensionForUrl("http://bar/#b1/1"); assertNotNull(childExt); diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu3.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu3.java index 66812ad51e2..53074d730f9 100644 --- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu3.java +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/CustomPatientDstu3.java @@ -14,7 +14,7 @@ public class CustomPatientDstu3 extends Patient { private static final long serialVersionUID = 1L; @Child(name = "homeless", order = 1) - @Extension(url = "%BASE_SERVER_URL%/StructureDefinition/homeless", definedLocally = true, isModifier = false) + @Extension(url = "/StructureDefinition/homeless", definedLocally = true, isModifier = false) @Description(shortDefinition = "The patient being homeless, true if homeless") private BooleanType homeless; 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 662c25e92a7..d2b46acbc44 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 @@ -22,6 +22,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.io.IOException; +import java.io.StringReader; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -2169,6 +2170,72 @@ public class JsonParserDstu3Test { assertTrue(result.isSuccessful()); } + /** + * Test for the url generated based on the server config + */ + @Test + public void testCustomUrlExtension() { + final String expected = "{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://www.example.com/petname\",\"valueString\":\"myName\"}]}"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringType("myName")); + + final IParser jsonParser = ourCtx.newJsonParser(); + jsonParser.setServerBaseUrl("http://www.example.com"); + + final String parsedPatient = jsonParser.encodeResourceToString(patient); + System.out.println(parsedPatient); + assertEquals(expected, parsedPatient); + + // Parse with string + MyPatientWithCustomUrlExtension newPatient = jsonParser.parseResource(MyPatientWithCustomUrlExtension.class, parsedPatient); + assertEquals("myName", newPatient.getPetName().getValue()); + + // Parse with stream + newPatient = jsonParser.parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertEquals("myName", newPatient.getPetName().getValue()); + + //Check no NPE if base server not configure + newPatient = ourCtx.newJsonParser().parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertNull("myName", newPatient.getPetName()); + assertEquals("myName", ((StringType) newPatient.getExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + } + + @Test + public void testCustomUrlExtensioninBundle() { + final String expected = "{\"resourceType\":\"Bundle\",\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://www.example.com/petname\",\"valueString\":\"myName\"}]}}]}"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringType("myName")); + + final Bundle bundle = new Bundle(); + final BundleEntryComponent entry = new BundleEntryComponent(); + entry.setResource(patient); + bundle.addEntry(entry); + + final IParser jsonParser = ourCtx.newJsonParser(); + jsonParser.setServerBaseUrl("http://www.example.com"); + + final String parsedBundle = jsonParser.encodeResourceToString(bundle); + System.out.println(parsedBundle); + assertEquals(expected, parsedBundle); + + // Parse with string + Bundle newBundle = jsonParser.parseResource(Bundle.class, parsedBundle); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntry().size()); + Patient newPatient = (Patient) newBundle.getEntry().get(0).getResource(); + assertEquals("myName", ((StringType) newPatient.getExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + // Parse with stream + newBundle = jsonParser.parseResource(Bundle.class, new StringReader(parsedBundle)); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntry().size()); + newPatient = (Patient) newBundle.getEntry().get(0).getResource(); + assertEquals("myName", ((StringType) newPatient.getExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + } + @AfterClass public static void afterClassClearContext() { TestUtil.clearAllStaticFieldsForUnitTest(); diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java new file mode 100644 index 00000000000..d668ecf7e08 --- /dev/null +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/MyPatientWithCustomUrlExtension.java @@ -0,0 +1,33 @@ +package ca.uhn.fhir.parser; + +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.Extension; +import ca.uhn.fhir.model.api.annotation.ResourceDef; +import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.dstu3.model.Patient; + +@ResourceDef() +public class MyPatientWithCustomUrlExtension extends Patient { + + private static final long serialVersionUID = 1L; + + @Child(name = "petName") + @Extension(url = "/petname", definedLocally = false, isModifier = false) + @Description(shortDefinition = "The name of the patient's favourite pet") + private StringType myPetName; + + public StringType getPetName() { + return myPetName; + } + + public void setPetName(final StringType thePetName) { + myPetName = thePetName; + } + + @Override + public boolean isEmpty() { + return super.isEmpty() && myPetName.isEmpty(); + } + +} 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 02781c73ed6..851fe6df0e0 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 @@ -3184,6 +3184,72 @@ public class XmlParserDstu3Test { assertTrue(parsedPatient.contains("<extension url=\"http://myserver.com/StructureDefinition/homeless\">")); } +/** + * Test for the url generated based on the server config + */ + @Test + public void testCustomUrlExtension() { + final String expected = "<Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://www.example.com/petname\"><valueString value=\"myName\"/></extension></Patient>"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringType("myName")); + + final IParser xmlParser = ourCtx.newXmlParser(); + xmlParser.setServerBaseUrl("http://www.example.com"); + + final String parsedPatient = xmlParser.encodeResourceToString(patient); + System.out.println(parsedPatient); + assertEquals(expected, parsedPatient); + + // Parse with string + MyPatientWithCustomUrlExtension newPatient = xmlParser.parseResource(MyPatientWithCustomUrlExtension.class, parsedPatient); + assertEquals("myName", newPatient.getPetName().getValue()); + + // Parse with stream + newPatient = xmlParser.parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertEquals("myName", newPatient.getPetName().getValue()); + + //Check no NPE if base server not configure + newPatient = ourCtx.newXmlParser().parseResource(MyPatientWithCustomUrlExtension.class, new StringReader(parsedPatient)); + assertNull("myName", newPatient.getPetName()); + assertEquals("myName", ((StringType) newPatient.getExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + } + + @Test + public void testCustomUrlExtensioninBundle() { + final String expected = "<Bundle xmlns=\"http://hl7.org/fhir\"><entry><resource><Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://www.example.com/petname\"><valueString value=\"myName\"/></extension></Patient></resource></entry></Bundle>"; + + final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension(); + patient.setPetName(new StringType("myName")); + + final Bundle bundle = new Bundle(); + final BundleEntryComponent entry = new BundleEntryComponent(); + entry.setResource(patient); + bundle.addEntry(entry); + + final IParser xmlParser = ourCtx.newXmlParser(); + xmlParser.setServerBaseUrl("http://www.example.com"); + + final String parsedBundle = xmlParser.encodeResourceToString(bundle); + System.out.println(parsedBundle); + assertEquals(expected, parsedBundle); + + // Parse with string + Bundle newBundle = xmlParser.parseResource(Bundle.class, parsedBundle); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntry().size()); + Patient newPatient = (Patient) newBundle.getEntry().get(0).getResource(); + assertEquals("myName", ((StringType) newPatient.getExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + // Parse with stream + newBundle = xmlParser.parseResource(Bundle.class, new StringReader(parsedBundle)); + assertNotNull(newBundle); + assertEquals(1, newBundle.getEntry().size()); + newPatient = (Patient) newBundle.getEntry().get(0).getResource(); + assertEquals("myName", ((StringType) newPatient.getExtensionsByUrl("http://www.example.com/petname").get(0).getValue()).getValue()); + + } + @AfterClass public static void afterClassClearContext() { TestUtil.clearAllStaticFieldsForUnitTest();