From 0f012603012c47d66f8a1378cd263e0db82a93f5 Mon Sep 17 00:00:00 2001
From: James Agnew
+ * Note that before HAPI 0.9 this method returned a {@link StringDt} but as of
+ * HAPI 0.9 this method returns a plain string. This was changed because it does not make sense to use a StringDt here
+ * since the URL itself can not contain extensions and it was therefore misleading.
+ *
> List> toBaseExtensionList(final List theList) { + List> retVal = new ArrayList >(theList.size()); + retVal.addAll(theList); + return retVal; } private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, BaseResourceReferenceDt theRef) throws XMLStreamException { @@ -638,12 +666,12 @@ public class XmlParser extends BaseParser implements IParser { postExtensionChildren.add(next); } } - encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, preExtensionChildren, theIncludedResource); + encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, preExtensionChildren, theIncludedResource); - encodeExtensionsIfPresent(theResDef, theResource, theEventWriter, theElement, theIncludedResource); - encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions(), theIncludedResource); + encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource); + encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, resDef.getExtensions(), theIncludedResource); - encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, postExtensionChildren, theIncludedResource); + encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, postExtensionChildren, theIncludedResource); } @@ -706,7 +734,7 @@ public class XmlParser extends BaseParser implements IParser { if (theResource instanceof IAnyResource) { // HL7.org Structures - encodeCompositeElementToStreamWriter(resDef, theResource, theResource, theEventWriter, resDef, theContainedResource); + encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, resDef, theContainedResource); } else { @@ -753,7 +781,7 @@ public class XmlParser extends BaseParser implements IParser { } theEventWriter.writeCharacters(bin.getContentAsBase64()); } else { - encodeCompositeElementToStreamWriter(resDef, theResource, theResource, theEventWriter, resDef, theContainedResource); + encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, resDef, theContainedResource); } } @@ -794,25 +822,20 @@ public class XmlParser extends BaseParser implements IParser { } } - private void encodeUndeclaredExtensions(RuntimeResourceDefinition theResDef, IBaseResource theResource, XMLStreamWriter theWriter, List theExtensions, String tagName, - boolean theIncludedResource) throws XMLStreamException, DataFormatException { - for (ExtensionDt next : theExtensions) { + private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theWriter, List extends IBaseExtension>> theExtensions, String tagName, boolean theIncludedResource) + throws XMLStreamException, DataFormatException { + for (IBaseExtension> next : theExtensions) { + if (next == null) { + continue; + } + theWriter.writeStartElement(tagName); - theWriter.writeAttribute("url", next.getUrl().getValue()); + + String url = next.getUrl(); + theWriter.writeAttribute("url", url); if (next.getValue() != null) { - IElement value = next.getValue(); - // RuntimeChildUndeclaredExtensionDefinition extDef = - // myContext.getRuntimeChildUndeclaredExtensionDefinition(); - // String childName = extDef.getChildNameByDatatype(nextValue.getClass()); - // if (childName == null) { - // throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + - // nextValue.getClass().getCanonicalName()); - // } - // BaseRuntimeElementDefinition> childDef = - // extDef.getChildElementDefinitionByDatatype(nextValue.getClass()); - // - // + IBaseDatatype value = next.getValue(); RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition(); String childName = extDef.getChildNameByDatatype(value.getClass()); BaseRuntimeElementDefinition> childDef; @@ -826,11 +849,11 @@ public class XmlParser extends BaseParser implements IParser { } else { childDef = extDef.getChildElementDefinitionByDatatype(value.getClass()); } - encodeChildElementToStreamWriter(theResDef, theResource, theWriter, value, childName, childDef, null, theIncludedResource); + encodeChildElementToStreamWriter(theResource, theWriter, value, childName, childDef, null, theIncludedResource); } // child extensions - encodeExtensionsIfPresent(theResDef, theResource, theWriter, next, theIncludedResource); + encodeExtensionsIfPresent(theResource, theWriter, next, theIncludedResource); theWriter.writeEndElement(); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java index d595ae49665..27868f5d46d 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java @@ -26,15 +26,12 @@ import java.io.IOException; import java.io.Reader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.TreeSet; -import ca.uhn.fhir.rest.annotation.*; - import org.apache.commons.io.IOUtils; import org.hl7.fhir.instance.model.IBaseResource; @@ -47,6 +44,18 @@ import ca.uhn.fhir.model.base.resource.BaseOperationOutcome; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum; import ca.uhn.fhir.parser.IParser; +import ca.uhn.fhir.rest.annotation.AddTags; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.Delete; +import ca.uhn.fhir.rest.annotation.DeleteTags; +import ca.uhn.fhir.rest.annotation.GetTags; +import ca.uhn.fhir.rest.annotation.History; +import ca.uhn.fhir.rest.annotation.Metadata; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.annotation.Transaction; +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.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException; @@ -61,9 +70,9 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; +import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException; -import ca.uhn.fhir.rest.server.exceptions.ResourceVersionNotSpecifiedException; import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.util.ReflectionUtil; @@ -217,7 +226,7 @@ public abstract class BaseMethodBinding implements IClientResponseHandler ex = new ResourceVersionConflictException("Server responded with HTTP 409"); break; case Constants.STATUS_HTTP_412_PRECONDITION_FAILED: - ex = new ResourceVersionNotSpecifiedException("Server responded with HTTP 412"); + ex = new PreconditionFailedException("Server responded with HTTP 412"); break; case Constants.STATUS_HTTP_422_UNPROCESSABLE_ENTITY: IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theStatusCode); diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseEnumFactory.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseEnumFactory.java new file mode 100644 index 00000000000..ab56defe694 --- /dev/null +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseEnumFactory.java @@ -0,0 +1,25 @@ +package org.hl7.fhir.instance.model.api; + +public interface IBaseEnumFactory > { + + /** + * Read an enumeration value from the string that represents it on the XML or JSON + * + * @param codeString + * the value found in the XML or JSON + * @return the enumeration value + * @throws IllegalArgumentException + * is the value is not known + */ + public T fromCode(String codeString) throws IllegalArgumentException; + + /** + * Get the XML/JSON representation for an enumerated value + * + * @param code + * - the enumeration value + * @return the XML/JSON representation + */ + public String toCode(T code); + +} diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseExtension.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseExtension.java index d48da6dd004..0d0dbf01aec 100644 --- a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseExtension.java +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseExtension.java @@ -11,5 +11,9 @@ public interface IBaseExtension extends ICompositeType { String getUrl(); IBaseDatatype getValue(); + + T setUrl(String theUrl); + T setValue(IBaseDatatype theValue); + } diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseHasExtensions.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseHasExtensions.java new file mode 100644 index 00000000000..257b7466478 --- /dev/null +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseHasExtensions.java @@ -0,0 +1,11 @@ +package org.hl7.fhir.instance.model.api; + +import java.util.List; + +public interface IBaseHasExtensions { + + public List extends IBaseExtension>> getExtension(); + + public IBaseExtension> addExtension(); + +} diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseHasModifierExtensions.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseHasModifierExtensions.java new file mode 100644 index 00000000000..23cba0358a3 --- /dev/null +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseHasModifierExtensions.java @@ -0,0 +1,11 @@ +package org.hl7.fhir.instance.model.api; + +import java.util.List; + +public interface IBaseHasModifierExtensions { + + public List extends IBaseExtension>> getModifierExtension(); + + public IBaseExtension> addModifierExtension(); + +} diff --git a/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/parser/MultiVersionJsonParserTest.java b/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/parser/MultiVersionJsonParserTest.java index a51236d25ff..113baa19ce1 100644 --- a/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/parser/MultiVersionJsonParserTest.java +++ b/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/parser/MultiVersionJsonParserTest.java @@ -22,7 +22,7 @@ public class MultiVersionJsonParserTest { String str = FhirContext.forDstu2().newJsonParser().encodeResourceToString(p); ourLog.info(str); - assertThat(str,StringContains.containsString("{\"resourceType\":\"Patient\",\"http://foo#ext\":[{\"valueQuantity\":{\"value\":2.2}}],\"identifier\":[{\"system\":\"urn:sys\",\"value\":\"001\"}]}")); + assertThat(str,StringContains.containsString("{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://foo#ext\",\"valueQuantity\":{\"value\":2.2}}],\"identifier\":[{\"system\":\"urn:sys\",\"value\":\"001\"}]}")); } } diff --git a/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/testmindeps/ValidatorTest.java b/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/testmindeps/ValidatorTest.java index 0a591bc2443..f83848dd45b 100644 --- a/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/testmindeps/ValidatorTest.java +++ b/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/testmindeps/ValidatorTest.java @@ -9,22 +9,23 @@ import ca.uhn.fhir.validation.FhirValidator; public class ValidatorTest { - @Test - public void testValidator() { - - FhirContext ctx = new FhirContext(); - FhirValidator val = ctx.newValidator(); - - // Phloc is not onthe classpath - assertTrue(val.isValidateAgainstStandardSchema()); - assertFalse(val.isValidateAgainstStandardSchematron()); + @Test + public void testValidator() { + + FhirContext ctx = new FhirContext(); + FhirValidator val = ctx.newValidator(); + + // Phloc is not onthe classpath + assertTrue(val.isValidateAgainstStandardSchema()); + assertFalse(val.isValidateAgainstStandardSchematron()); + + try { + val.setValidateAgainstStandardSchematron(true); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Phloc-schematron library not found on classpath, can not enable perform schematron validation", e.getMessage()); + } + + } - try { val.setValidateAgainstStandardSchematron(true); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("Phloc-schematron library not found on classpath, can not enable perform schematron validation", e.getMessage()); - } - - } - } diff --git a/hapi-fhir-jpaserver-example/src/main/java/ca/uhn/fhir/jpa/demo/JpaServerDemo.java b/hapi-fhir-jpaserver-example/src/main/java/ca/uhn/fhir/jpa/demo/JpaServerDemo.java index 731afbca793..5775f0ce6c1 100644 --- a/hapi-fhir-jpaserver-example/src/main/java/ca/uhn/fhir/jpa/demo/JpaServerDemo.java +++ b/hapi-fhir-jpaserver-example/src/main/java/ca/uhn/fhir/jpa/demo/JpaServerDemo.java @@ -9,6 +9,7 @@ import org.springframework.web.context.WebApplicationContext; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1; +import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2; import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.rest.server.ETagSupportEnum; import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; @@ -48,7 +49,7 @@ public class JpaServerDemo extends RestfulServer { * The system provider implements non-resource-type methods, such as * transaction, and global history. */ - JpaSystemProviderDstu1 systemProvider = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu1.class); + JpaSystemProviderDstu2 systemProvider = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class); setPlainProviders(systemProvider); /* diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java index 72731a1c9c1..3c94a4bf79d 100644 --- a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java @@ -23,10 +23,12 @@ package ca.uhn.fhir.model.dev; import java.io.InputStream; import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.instance.model.api.IBaseExtension; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.api.IFhirVersion; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.base.composite.BaseContainedDt; @@ -102,6 +104,4 @@ public class FhirDev implements IFhirVersion { return ContainedDt.class; } - - } diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java index 36713dc4a1b..e271fca91e4 100644 --- a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java @@ -57,7 +57,6 @@ import ca.uhn.fhir.context.RuntimeResourceBlockDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceReferenceDefinition; import ca.uhn.fhir.model.api.ICompositeDatatype; -import ca.uhn.fhir.model.api.IDatatype; import ca.uhn.fhir.model.api.IFhirVersion; import ca.uhn.fhir.model.api.IPrimitiveDatatype; import ca.uhn.fhir.model.api.IResource; @@ -378,6 +377,4 @@ public class FhirDstu1 implements IFhirVersion { return ContainedDt.class; } - - } 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 77de4d8cff5..9a924807c49 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 @@ -1,9 +1,15 @@ package ca.uhn.fhir.parser; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.stringContainsInOrder; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; import java.io.IOException; import java.io.OutputStreamWriter; @@ -24,8 +30,6 @@ import org.hamcrest.text.StringContainsInOrder; import org.hl7.fhir.instance.model.IBaseResource; import org.junit.BeforeClass; import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Matchers; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; @@ -41,7 +45,6 @@ import ca.uhn.fhir.model.api.annotation.ResourceDef; import ca.uhn.fhir.model.base.composite.BaseNarrativeDt; import ca.uhn.fhir.model.dstu.composite.AddressDt; import ca.uhn.fhir.model.dstu.composite.HumanNameDt; -import ca.uhn.fhir.model.dstu.composite.NarrativeDt; import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu.resource.Binary; import ca.uhn.fhir.model.dstu.resource.Conformance; @@ -59,7 +62,10 @@ import ca.uhn.fhir.model.dstu.resource.ValueSet; import ca.uhn.fhir.model.dstu.resource.ValueSet.Define; import ca.uhn.fhir.model.dstu.resource.ValueSet.DefineConcept; import ca.uhn.fhir.model.dstu.valueset.AddressUseEnum; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum; +import ca.uhn.fhir.model.primitive.DateDt; +import ca.uhn.fhir.model.primitive.DateTimeDt; import ca.uhn.fhir.model.primitive.DecimalDt; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; @@ -94,6 +100,120 @@ public class JsonParserTest { } + @Test + public void testEncodeAndParseExtensions() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setUse(IdentifierUseEnum.OFFICIAL).setSystem("urn:example").setValue("7000135"); + + ExtensionDt ext = new ExtensionDt(); + ext.setUrl("http://example.com/extensions#someext"); + ext.setValue(new DateTimeDt("2011-01-02T11:13:15")); + patient.addUndeclaredExtension(ext); + + ExtensionDt parent = new ExtensionDt().setUrl("http://example.com#parent"); + patient.addUndeclaredExtension(parent); + ExtensionDt child1 = new ExtensionDt().setUrl( "http://example.com#child").setValue( new StringDt("value1")); + parent.addUndeclaredExtension(child1); + ExtensionDt child2 = new ExtensionDt().setUrl( "http://example.com#child").setValue( new StringDt("value2")); + parent.addUndeclaredExtension(child2); + + ExtensionDt modExt = new ExtensionDt(); + modExt.setUrl("http://example.com/extensions#modext"); + modExt.setValue(new DateDt("1995-01-02")); + modExt.setModifier(true); + patient.addUndeclaredExtension(modExt); + + HumanNameDt name = patient.addName(); + name.addFamily("Blah"); + StringDt given = name.addGiven(); + given.setValue("Joe"); + ExtensionDt ext2 = new ExtensionDt().setUrl("http://examples.com#givenext").setValue(new StringDt("given")); + given.addUndeclaredExtension(ext2); + + StringDt given2 = name.addGiven(); + given2.setValue("Shmoe"); + ExtensionDt given2ext = new ExtensionDt().setUrl("http://examples.com#givenext_parent"); + given2.addUndeclaredExtension(given2ext); + given2ext.addUndeclaredExtension(new ExtensionDt().setUrl("http://examples.com#givenext_child").setValue(new StringDt("CHILD"))); + + String output = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newJsonParser().encodeResourceToString(patient); + assertThat(enc, org.hamcrest.Matchers.stringContainsInOrder("{\"resourceType\":\"Patient\",", + "\"extension\":[{\"url\":\"http://example.com/extensions#someext\",\"valueDateTime\":\"2011-01-02T11:13:15\"}", + "{\"url\":\"http://example.com#parent\",\"extension\":[{\"url\":\"http://example.com#child\",\"valueString\":\"value1\"},{\"url\":\"http://example.com#child\",\"valueString\":\"value2\"}]}" + )); + assertThat(enc, org.hamcrest.Matchers.stringContainsInOrder("\"modifierExtension\":[" + + "{" + + "\"url\":\"http://example.com/extensions#modext\"," + + "\"valueDate\":\"1995-01-02\"" + + "}" + + "],")); + assertThat(enc, containsString("\"_given\":[" + + "{" + + "\"extension\":[" + + "{" + + "\"url\":\"http://examples.com#givenext\"," + + "\"valueString\":\"given\"" + + "}" + + "]" + + "}," + + "{" + + "\"extension\":[" + + "{" + + "\"url\":\"http://examples.com#givenext_parent\"," + + "\"extension\":[" + + "{" + + "\"url\":\"http://examples.com#givenext_child\"," + + "\"valueString\":\"CHILD\"" + + "}" + + "]" + + "}" + + "]" + + "}")); + + /* + * Now parse this back + */ + + Patient parsed =ourCtx.newJsonParser().parseResource(Patient.class, enc); + ext = parsed.getUndeclaredExtensions().get(0); + assertEquals("http://example.com/extensions#someext", ext.getUrl()); + assertEquals("2011-01-02T11:13:15", ((DateTimeDt)ext.getValue()).getValueAsString()); + + parent = patient.getUndeclaredExtensions().get(1); + assertEquals("http://example.com#parent", parent.getUrl()); + assertNull(parent.getValue()); + child1 = parent.getExtension().get(0); + assertEquals( "http://example.com#child", child1.getUrl()); + assertEquals("value1", ((StringDt)child1.getValue()).getValueAsString()); + child2 = parent.getExtension().get(1); + assertEquals( "http://example.com#child", child2.getUrl()); + assertEquals("value2", ((StringDt)child2.getValue()).getValueAsString()); + + modExt = parsed.getUndeclaredModifierExtensions().get(0); + assertEquals("http://example.com/extensions#modext", modExt.getUrl()); + assertEquals("1995-01-02", ((DateDt)modExt.getValue()).getValueAsString()); + + name = parsed.getName().get(0); + + ext2 = name.getGiven().get(0).getUndeclaredExtensions().get(0); + assertEquals("http://examples.com#givenext", ext2.getUrl()); + assertEquals("given", ((StringDt)ext2.getValue()).getValueAsString()); + + given2ext = name.getGiven().get(1).getUndeclaredExtensions().get(0); + assertEquals("http://examples.com#givenext_parent", given2ext.getUrl()); + assertNull(given2ext.getValue()); + ExtensionDt given2ext2 = given2ext.getExtension().get(0); + assertEquals("http://examples.com#givenext_child", given2ext2.getUrl()); + assertEquals("CHILD", ((StringDt)given2ext2.getValue()).getValue()); + + } + + + /** * #65 */ @@ -1136,7 +1256,7 @@ public class JsonParserTest { List undeclaredExtensions = obs.getContact().get(0).getName().getFamily().get(0).getUndeclaredExtensions(); ExtensionDt undeclaredExtension = undeclaredExtensions.get(0); - assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl().getValue()); + assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl()); ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToWriter(obs, new OutputStreamWriter(System.out)); @@ -1184,7 +1304,7 @@ public class JsonParserTest { List undeclaredExtensions = obs.getContact().get(0).getName().getFamily().get(0).getUndeclaredExtensions(); ExtensionDt undeclaredExtension = undeclaredExtensions.get(0); - assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl().getValue()); + assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl()); IParser jsonParser = fhirCtx.newJsonParser().setPrettyPrint(true); String encoded = jsonParser.encodeResourceToString(obs); 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 def9035d86c..5e154491072 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 @@ -67,6 +67,7 @@ import ca.uhn.fhir.model.dstu.valueset.AdministrativeGenderCodesEnum; import ca.uhn.fhir.model.dstu.valueset.DocumentReferenceStatusEnum; import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum; +import ca.uhn.fhir.model.primitive.DateDt; import ca.uhn.fhir.model.primitive.DateTimeDt; import ca.uhn.fhir.model.primitive.DecimalDt; import ca.uhn.fhir.model.primitive.IdDt; @@ -151,6 +152,95 @@ public class XmlParserTest { } + + @Test + public void testEncodeAndParseExtensions() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setUse(IdentifierUseEnum.OFFICIAL).setSystem("urn:example").setValue("7000135"); + + ExtensionDt ext = new ExtensionDt(); + ext.setUrl("http://example.com/extensions#someext"); + ext.setValue(new DateTimeDt("2011-01-02T11:13:15")); + patient.addUndeclaredExtension(ext); + + ExtensionDt parent = new ExtensionDt().setUrl("http://example.com#parent"); + patient.addUndeclaredExtension(parent); + ExtensionDt child1 = new ExtensionDt().setUrl( "http://example.com#child").setValue( new StringDt("value1")); + parent.addUndeclaredExtension(child1); + ExtensionDt child2 = new ExtensionDt().setUrl( "http://example.com#child").setValue( new StringDt("value2")); + parent.addUndeclaredExtension(child2); + + ExtensionDt modExt = new ExtensionDt(); + modExt.setUrl("http://example.com/extensions#modext"); + modExt.setValue(new DateDt("1995-01-02")); + modExt.setModifier(true); + patient.addUndeclaredExtension(modExt); + + HumanNameDt name = patient.addName(); + name.addFamily("Blah"); + StringDt given = name.addGiven(); + given.setValue("Joe"); + ExtensionDt ext2 = new ExtensionDt().setUrl("http://examples.com#givenext").setValue(new StringDt("given")); + given.addUndeclaredExtension(ext2); + + StringDt given2 = name.addGiven(); + given2.setValue("Shmoe"); + ExtensionDt given2ext = new ExtensionDt().setUrl("http://examples.com#givenext_parent"); + given2.addUndeclaredExtension(given2ext); + given2ext.addUndeclaredExtension(new ExtensionDt().setUrl("http://examples.com#givenext_child").setValue(new StringDt("CHILD"))); + + String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newXmlParser().encodeResourceToString(patient); + assertThat(enc, containsString(" ")); + assertThat(enc, containsString(" ")); + assertThat( + enc, + containsString(" ")); + assertThat(enc, containsString(" ")); + assertThat(enc, containsString(" ")); + + /* + * Now parse this back + */ + + Patient parsed =ourCtx.newXmlParser().parseResource(Patient.class, enc); + ext = parsed.getUndeclaredExtensions().get(0); + assertEquals("http://example.com/extensions#someext", ext.getUrl()); + assertEquals("2011-01-02T11:13:15", ((DateTimeDt)ext.getValue()).getValueAsString()); + + parent = patient.getUndeclaredExtensions().get(1); + assertEquals("http://example.com#parent", parent.getUrl()); + assertNull(parent.getValue()); + child1 = parent.getExtension().get(0); + assertEquals( "http://example.com#child", child1.getUrl()); + assertEquals("value1", ((StringDt)child1.getValue()).getValueAsString()); + child2 = parent.getExtension().get(1); + assertEquals( "http://example.com#child", child2.getUrl()); + assertEquals("value2", ((StringDt)child2.getValue()).getValueAsString()); + + modExt = parsed.getUndeclaredModifierExtensions().get(0); + assertEquals("http://example.com/extensions#modext", modExt.getUrl()); + assertEquals("1995-01-02", ((DateDt)modExt.getValue()).getValueAsString()); + + name = parsed.getName().get(0); + + ext2 = name.getGiven().get(0).getUndeclaredExtensions().get(0); + assertEquals("http://examples.com#givenext", ext2.getUrl()); + assertEquals("given", ((StringDt)ext2.getValue()).getValueAsString()); + + given2ext = name.getGiven().get(1).getUndeclaredExtensions().get(0); + assertEquals("http://examples.com#givenext_parent", given2ext.getUrl()); + assertNull(given2ext.getValue()); + ExtensionDt given2ext2 = given2ext.getExtension().get(0); + assertEquals("http://examples.com#givenext_child", given2ext2.getUrl()); + assertEquals("CHILD", ((StringDt)given2ext2.getValue()).getValue()); + + } + + @Test public void testEncodeBundle() throws InterruptedException { Bundle b = new Bundle(); @@ -1490,7 +1580,7 @@ public class XmlParserTest { List undeclaredExtensions = obs.getContact().get(0).getName().getFamily().get(0).getUndeclaredExtensions(); ExtensionDt undeclaredExtension = undeclaredExtensions.get(0); - assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl().getValue()); + assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl()); ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToWriter(obs, new OutputStreamWriter(System.out)); @@ -1545,7 +1635,7 @@ public class XmlParserTest { List undeclaredExtensions = obs.getContact().get(0).getName().getFamily().get(0).getUndeclaredExtensions(); ExtensionDt undeclaredExtension = undeclaredExtensions.get(0); - assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl().getValue()); + assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl()); fhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToWriter(obs, new OutputStreamWriter(System.out)); diff --git a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java index c57c7d8fd14..615c4e8bce2 100644 --- a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java +++ b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java @@ -23,10 +23,12 @@ package ca.uhn.fhir.model.dstu2; import java.io.InputStream; import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.instance.model.api.IBaseExtension; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.api.IDatatype; import ca.uhn.fhir.model.api.IFhirVersion; import ca.uhn.fhir.model.api.IResource; diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java index cf7b148df43..e41c511eddc 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java @@ -13,6 +13,7 @@ import net.sf.json.JSONSerializer; import net.sf.json.JsonConfig; import org.apache.commons.io.IOUtils; +import org.hamcrest.Matchers; import org.junit.Test; import ca.uhn.fhir.context.ConfigurationException; @@ -20,13 +21,16 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.dstu2.composite.HumanNameDt; import ca.uhn.fhir.model.dstu2.resource.Binary; import ca.uhn.fhir.model.dstu2.resource.MedicationPrescription; import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.model.dstu2.resource.QuestionnaireAnswers; +import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum; 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; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.StringDt; @@ -65,6 +69,120 @@ public class JsonParserTest { //@formatter:on } + @Test + public void testEncodeAndParseExtensions() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setUse(IdentifierUseEnum.OFFICIAL).setSystem("urn:example").setValue("7000135"); + + ExtensionDt ext = new ExtensionDt(); + ext.setUrl("http://example.com/extensions#someext"); + ext.setValue(new DateTimeDt("2011-01-02T11:13:15")); + patient.addUndeclaredExtension(ext); + + ExtensionDt parent = new ExtensionDt().setUrl("http://example.com#parent"); + patient.addUndeclaredExtension(parent); + ExtensionDt child1 = new ExtensionDt().setUrl( "http://example.com#child").setValue( new StringDt("value1")); + parent.addUndeclaredExtension(child1); + ExtensionDt child2 = new ExtensionDt().setUrl( "http://example.com#child").setValue( new StringDt("value2")); + parent.addUndeclaredExtension(child2); + + ExtensionDt modExt = new ExtensionDt(); + modExt.setUrl("http://example.com/extensions#modext"); + modExt.setValue(new DateDt("1995-01-02")); + modExt.setModifier(true); + patient.addUndeclaredExtension(modExt); + + HumanNameDt name = patient.addName(); + name.addFamily("Blah"); + StringDt given = name.addGiven(); + given.setValue("Joe"); + ExtensionDt ext2 = new ExtensionDt().setUrl("http://examples.com#givenext").setValue(new StringDt("given")); + given.addUndeclaredExtension(ext2); + + StringDt given2 = name.addGiven(); + given2.setValue("Shmoe"); + ExtensionDt given2ext = new ExtensionDt().setUrl("http://examples.com#givenext_parent"); + given2.addUndeclaredExtension(given2ext); + given2ext.addUndeclaredExtension(new ExtensionDt().setUrl("http://examples.com#givenext_child").setValue(new StringDt("CHILD"))); + + String output = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newJsonParser().encodeResourceToString(patient); + assertThat(enc, Matchers.stringContainsInOrder("{\"resourceType\":\"Patient\",", + "\"extension\":[{\"url\":\"http://example.com/extensions#someext\",\"valueDateTime\":\"2011-01-02T11:13:15\"}", + "{\"url\":\"http://example.com#parent\",\"extension\":[{\"url\":\"http://example.com#child\",\"valueString\":\"value1\"},{\"url\":\"http://example.com#child\",\"valueString\":\"value2\"}]}" + )); + assertThat(enc, Matchers.stringContainsInOrder("\"modifierExtension\":[" + + "{" + + "\"url\":\"http://example.com/extensions#modext\"," + + "\"valueDate\":\"1995-01-02\"" + + "}" + + "],")); + assertThat(enc, containsString("\"_given\":[" + + "{" + + "\"extension\":[" + + "{" + + "\"url\":\"http://examples.com#givenext\"," + + "\"valueString\":\"given\"" + + "}" + + "]" + + "}," + + "{" + + "\"extension\":[" + + "{" + + "\"url\":\"http://examples.com#givenext_parent\"," + + "\"extension\":[" + + "{" + + "\"url\":\"http://examples.com#givenext_child\"," + + "\"valueString\":\"CHILD\"" + + "}" + + "]" + + "}" + + "]" + + "}")); + + /* + * Now parse this back + */ + + Patient parsed =ourCtx.newJsonParser().parseResource(Patient.class, enc); + ext = parsed.getUndeclaredExtensions().get(0); + assertEquals("http://example.com/extensions#someext", ext.getUrl()); + assertEquals("2011-01-02T11:13:15", ((DateTimeDt)ext.getValue()).getValueAsString()); + + parent = patient.getUndeclaredExtensions().get(1); + assertEquals("http://example.com#parent", parent.getUrl()); + assertNull(parent.getValue()); + child1 = parent.getExtension().get(0); + assertEquals( "http://example.com#child", child1.getUrl()); + assertEquals("value1", ((StringDt)child1.getValue()).getValueAsString()); + child2 = parent.getExtension().get(1); + assertEquals( "http://example.com#child", child2.getUrl()); + assertEquals("value2", ((StringDt)child2.getValue()).getValueAsString()); + + modExt = parsed.getUndeclaredModifierExtensions().get(0); + assertEquals("http://example.com/extensions#modext", modExt.getUrl()); + assertEquals("1995-01-02", ((DateDt)modExt.getValue()).getValueAsString()); + + name = parsed.getName().get(0); + + ext2 = name.getGiven().get(0).getUndeclaredExtensions().get(0); + assertEquals("http://examples.com#givenext", ext2.getUrl()); + assertEquals("given", ((StringDt)ext2.getValue()).getValueAsString()); + + given2ext = name.getGiven().get(1).getUndeclaredExtensions().get(0); + assertEquals("http://examples.com#givenext_parent", given2ext.getUrl()); + assertNull(given2ext.getValue()); + ExtensionDt given2ext2 = given2ext.getExtension().get(0); + assertEquals("http://examples.com#givenext_child", given2ext2.getUrl()); + assertEquals("CHILD", ((StringDt)given2ext2.getValue()).getValue()); + + } + + + /** * #65 */ @@ -77,7 +195,7 @@ public class JsonParserTest { String encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(parsed); ourLog.info(encoded); - assertThat(encoded, containsString("{\"linkId\":\"value123\",\"_linkId\":{\"http://123\":[{\"valueString\":\"HELLO\"}]}}")); + assertThat(encoded, containsString("{\"linkId\":\"value123\",\"_linkId\":{\"extension\":[{\"url\":\"http://123\",\"valueString\":\"HELLO\"}]}}")); } @@ -244,102 +362,6 @@ public class JsonParserTest { } - @Test - public void testParseAndEncodeNewExtensionFormat() { - - //@formatter:off - String resource = "{\n" + - " \"resourceType\" : \"Patient\",\n" + - " \"http://acme.org/fhir/ExtensionDefinition/trial-status\" : [{\n" + - " \"code\" : [{ \"valueCode\" : \"unsure\" }],\n" + - " \"date\" : [{ \"valueDate\" : \"2009-03-14\" }], \n" + - " \"registrar\" : [{ \"valueReference\" : {\n" + - " \"reference\" : \"Practitioner/example\"\n" + - " }\n" + - " }]\n" + - " }],\n" + - " \"modifier\" : { \n" + - " \"http://example.org/fhir/ExtensionDefinition/some-kind-of-modifier\" : [{\n" + - " \"valueBoolean\" : true\n" + - " }]\n" + - " }," + - " \"name\" : [{\n" + - " \"family\": [\n" + - " \"du\",\n" + - " \"Marché\"\n" + - " ],\n" + - " \"_family\": [\n" + - " {\n" + - " \"http://hl7.org/fhir/ExtensionDefinition/iso21090-EN-qualifier\": [\n" + - " {\n" + - " \"valueCode\": \"VV\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " null\n" + - " ],\n" + - " \"given\": [\n" + - " \"Bénédicte\"\n" + - " ]\n" + - " }],\n" + - " \"gender\" : \"M\"\n" + - "}"; - //@formatter:on - -// ourLog.info(resource); - - Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, resource); - - // Modifier extension - assertEquals(1, parsed.getUndeclaredExtensionsByUrl("http://example.org/fhir/ExtensionDefinition/some-kind-of-modifier").size()); - assertTrue( parsed.getUndeclaredExtensionsByUrl("http://example.org/fhir/ExtensionDefinition/some-kind-of-modifier").get(0).isModifier()); - assertEquals(BooleanDt.class, parsed.getUndeclaredExtensionsByUrl("http://example.org/fhir/ExtensionDefinition/some-kind-of-modifier").get(0).getValueAsPrimitive().getClass()); - assertEquals("true", parsed.getUndeclaredExtensionsByUrl("http://example.org/fhir/ExtensionDefinition/some-kind-of-modifier").get(0).getValueAsPrimitive().getValueAsString()); - - // Gender - assertEquals("M",parsed.getGender()); - assertEquals(1, parsed.getUndeclaredExtensionsByUrl("http://acme.org/fhir/ExtensionDefinition/trial-status").size()); - - // Trial status - ExtensionDt ext = parsed.getUndeclaredExtensionsByUrl("http://acme.org/fhir/ExtensionDefinition/trial-status").get(0); - assertNull(ext.getValue()); - assertEquals(1, ext.getUndeclaredExtensionsByUrl("http://acme.org/fhir/ExtensionDefinition/code").size()); - assertEquals(CodeDt.class, ext.getUndeclaredExtensionsByUrl("http://acme.org/fhir/ExtensionDefinition/code").get(0).getValue().getClass()); - assertEquals("unsure", ext.getUndeclaredExtensionsByUrl("http://acme.org/fhir/ExtensionDefinition/code").get(0).getValueAsPrimitive().getValueAsString()); - assertEquals(1, ext.getUndeclaredExtensionsByUrl("http://acme.org/fhir/ExtensionDefinition/date").size()); - assertEquals(DateDt.class, ext.getUndeclaredExtensionsByUrl("http://acme.org/fhir/ExtensionDefinition/date").get(0).getValue().getClass()); - assertEquals("2009-03-14", ext.getUndeclaredExtensionsByUrl("http://acme.org/fhir/ExtensionDefinition/date").get(0).getValueAsPrimitive().getValueAsString()); - - // Name - assertEquals(1, parsed.getName().size()); - assertEquals(2, parsed.getName().get(0).getFamily().size()); - assertEquals("du Marché", parsed.getName().get(0).getFamilyAsSingleString()); - assertEquals(1, parsed.getName().get(0).getGiven().size()); - assertEquals("Bénédicte", parsed.getName().get(0).getGivenAsSingleString()); - - // Patient.name[0].family extensions - assertEquals(1, parsed.getNameFirstRep().getFamily().get(0).getUndeclaredExtensionsByUrl("http://hl7.org/fhir/ExtensionDefinition/iso21090-EN-qualifier").size()); - assertEquals(CodeDt.class, parsed.getNameFirstRep().getFamily().get(0).getUndeclaredExtensionsByUrl("http://hl7.org/fhir/ExtensionDefinition/iso21090-EN-qualifier").get(0).getValueAsPrimitive().getClass()); - assertEquals("VV", parsed.getNameFirstRep().getFamily().get(0).getUndeclaredExtensionsByUrl("http://hl7.org/fhir/ExtensionDefinition/iso21090-EN-qualifier").get(0).getValueAsPrimitive().getValueAsString()); - - /* - * Now re-encode - */ - String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed); - ourLog.info(encoded); - - JSON expected = JSONSerializer.toJSON(resource.trim()); - JSON actual = JSONSerializer.toJSON(encoded.trim()); - - String exp = expected.toString().replace("\\r\\n", "\\n"); // .replace("§", "§"); - String act = actual.toString().replace("\\r\\n", "\\n"); - - ourLog.info("Expected: {}", exp); - ourLog.info("Actual : {}", act); - - assertEquals(exp, act); - - } @Test public void testParseAndEncodeBundleWithDeletedEntry() { diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java index 392e1425786..f93e9f862c4 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java @@ -1,7 +1,13 @@ package ca.uhn.fhir.parser; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.emptyOrNullString; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import java.io.StringReader; @@ -13,8 +19,10 @@ import org.junit.Test; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.dstu2.composite.DurationDt; +import ca.uhn.fhir.model.dstu2.composite.HumanNameDt; import ca.uhn.fhir.model.dstu2.resource.AllergyIntolerance; import ca.uhn.fhir.model.dstu2.resource.Binary; import ca.uhn.fhir.model.dstu2.resource.Composition; @@ -22,7 +30,11 @@ import ca.uhn.fhir.model.dstu2.resource.Encounter; import ca.uhn.fhir.model.dstu2.resource.MedicationPrescription; import ca.uhn.fhir.model.dstu2.resource.Organization; import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.primitive.DateDt; +import ca.uhn.fhir.model.primitive.DateTimeDt; import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.StringDt; public class XmlParserTest { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserTest.class); @@ -89,7 +101,8 @@ public class XmlParserTest { public void testParseAndEncodeBundleNewStyle() throws Exception { String content = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/bundle-example.xml")); - ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, content); + IParser newXmlParser = ourCtx.newXmlParser(); + ca.uhn.fhir.model.dstu2.resource.Bundle parsed = newXmlParser.parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, content); assertEquals("http://example.com/base/Bundle/example/_history/1", parsed.getId().getValue()); assertEquals("1", parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.VERSION)); assertEquals(new InstantDt("2014-08-18T01:43:30Z"), parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED)); @@ -275,4 +288,93 @@ public class XmlParserTest { assertEquals(2, parsed.getContained().getContainedResources().size()); } + @Test + public void testEncodeAndParseExtensions() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setUse(IdentifierUseEnum.OFFICIAL).setSystem("urn:example").setValue("7000135"); + + ExtensionDt ext = new ExtensionDt(); + ext.setUrl("http://example.com/extensions#someext"); + ext.setValue(new DateTimeDt("2011-01-02T11:13:15")); + patient.addUndeclaredExtension(ext); + + ExtensionDt parent = new ExtensionDt().setUrl("http://example.com#parent"); + patient.addUndeclaredExtension(parent); + ExtensionDt child1 = new ExtensionDt().setUrl( "http://example.com#child").setValue( new StringDt("value1")); + parent.addUndeclaredExtension(child1); + ExtensionDt child2 = new ExtensionDt().setUrl( "http://example.com#child").setValue( new StringDt("value2")); + parent.addUndeclaredExtension(child2); + + ExtensionDt modExt = new ExtensionDt(); + modExt.setUrl("http://example.com/extensions#modext"); + modExt.setValue(new DateDt("1995-01-02")); + modExt.setModifier(true); + patient.addUndeclaredExtension(modExt); + + HumanNameDt name = patient.addName(); + name.addFamily("Blah"); + StringDt given = name.addGiven(); + given.setValue("Joe"); + ExtensionDt ext2 = new ExtensionDt().setUrl("http://examples.com#givenext").setValue(new StringDt("given")); + given.addUndeclaredExtension(ext2); + + StringDt given2 = name.addGiven(); + given2.setValue("Shmoe"); + ExtensionDt given2ext = new ExtensionDt().setUrl("http://examples.com#givenext_parent"); + given2.addUndeclaredExtension(given2ext); + given2ext.addUndeclaredExtension(new ExtensionDt().setUrl("http://examples.com#givenext_child").setValue(new StringDt("CHILD"))); + + String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newXmlParser().encodeResourceToString(patient); + assertThat(enc, containsString(" ")); + assertThat(enc, containsString(" ")); + assertThat( + enc, + containsString(" ")); + assertThat(enc, containsString(" ")); + assertThat(enc, containsString(" ")); + + /* + * Now parse this back + */ + + Patient parsed =ourCtx.newXmlParser().parseResource(Patient.class, enc); + ext = parsed.getUndeclaredExtensions().get(0); + assertEquals("http://example.com/extensions#someext", ext.getUrl()); + assertEquals("2011-01-02T11:13:15", ((DateTimeDt)ext.getValue()).getValueAsString()); + + parent = patient.getUndeclaredExtensions().get(1); + assertEquals("http://example.com#parent", parent.getUrl()); + assertNull(parent.getValue()); + child1 = parent.getExtension().get(0); + assertEquals( "http://example.com#child", child1.getUrl()); + assertEquals("value1", ((StringDt)child1.getValue()).getValueAsString()); + child2 = parent.getExtension().get(1); + assertEquals( "http://example.com#child", child2.getUrl()); + assertEquals("value2", ((StringDt)child2.getValue()).getValueAsString()); + + modExt = parsed.getUndeclaredModifierExtensions().get(0); + assertEquals("http://example.com/extensions#modext", modExt.getUrl()); + assertEquals("1995-01-02", ((DateDt)modExt.getValue()).getValueAsString()); + + name = parsed.getName().get(0); + + ext2 = name.getGiven().get(0).getUndeclaredExtensions().get(0); + assertEquals("http://examples.com#givenext", ext2.getUrl()); + assertEquals("given", ((StringDt)ext2.getValue()).getValueAsString()); + + given2ext = name.getGiven().get(1).getUndeclaredExtensions().get(0); + assertEquals("http://examples.com#givenext_parent", given2ext.getUrl()); + assertNull(given2ext.getValue()); + ExtensionDt given2ext2 = given2ext.getExtension().get(0); + assertEquals("http://examples.com#givenext_child", given2ext2.getUrl()); + assertEquals("CHILD", ((StringDt)given2ext2.getValue()).getValue()); + + } + + + } diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java index ac37009394b..e0b35e711b4 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java @@ -475,21 +475,4 @@ public class IncludeTest { } - public static void main(String[] args) { - - Organization org = new Organization(); - org.setId("Organization/65546"); - org.getNameElement().setValue("Contained Test Organization"); - - Patient patient = new Patient(); - patient.setId("Patient/1333"); - patient.addIdentifier().setSystem("urn:mrns").setValue("253345"); - patient.getManagingOrganization().setResource(patient); - - System.out.println(new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(patient)); - - patient.getManagingOrganization().getReference(); - - } - } diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/validation/ResourceValidatorTest.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/validation/ResourceValidatorTest.java index de90f1a85d4..e95587dfcbb 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/validation/ResourceValidatorTest.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/validation/ResourceValidatorTest.java @@ -27,7 +27,7 @@ import ca.uhn.fhir.model.primitive.DateTimeDt; public class ResourceValidatorTest { - private static FhirContext ourCtx = new FhirContext(); + private static FhirContext ourCtx = FhirContext.forDstu2(); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceValidatorTest.class); @SuppressWarnings("deprecation") diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/FhirDstu2Hl7Org.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/FhirDstu2Hl7Org.java index b43f57f2985..c007c5a0e57 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/FhirDstu2Hl7Org.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/FhirDstu2Hl7Org.java @@ -26,12 +26,15 @@ import java.util.ArrayList; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.conf.ServerConformanceProvider; import org.hl7.fhir.instance.conf.ServerProfileProvider; +import org.hl7.fhir.instance.model.Extension; import org.hl7.fhir.instance.model.Profile; import org.hl7.fhir.instance.model.Reference; +import org.hl7.fhir.instance.model.api.IBaseExtension; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.api.IFhirVersion; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.base.composite.BaseContainedDt; diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/BackboneElement.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/BackboneElement.java index 7c1cbede262..8558a11dcc6 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/BackboneElement.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/BackboneElement.java @@ -37,11 +37,13 @@ import org.hl7.fhir.instance.model.annotations.Child; import org.hl7.fhir.instance.model.annotations.Description; import org.hl7.fhir.instance.model.annotations.DatatypeDef; import org.hl7.fhir.instance.model.api.IBackboneElement; +import org.hl7.fhir.instance.model.api.IBaseHasExtensions; +import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions; /** * Base definition for all elements that are defined inside a resource - but not those in a data type. */ @DatatypeDef(name="BackboneElement") -public abstract class BackboneElement extends Element implements IBackboneElement { +public abstract class BackboneElement extends Element implements IBackboneElement, IBaseHasExtensions, IBaseHasModifierExtensions { /** * May be used to represent additional information that is not part of the basic definition of the element, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions. diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/DomainResource.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/DomainResource.java index 74fa55b4636..0cdcebb4a41 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/DomainResource.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/DomainResource.java @@ -38,11 +38,13 @@ import org.hl7.fhir.instance.model.annotations.SearchParamDefinition; import org.hl7.fhir.instance.model.annotations.Block; import org.hl7.fhir.instance.model.annotations.Child; import org.hl7.fhir.instance.model.annotations.Description; +import org.hl7.fhir.instance.model.api.IBaseHasExtensions; +import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions; /** * A resource that includes narrative, extensions, and contained resources. */ @ResourceDef(name="DomainResource", profile="http://hl7.org/fhir/Profile/DomainResource") -public abstract class DomainResource extends Resource { +public abstract class DomainResource extends Resource implements IBaseHasExtensions, IBaseHasModifierExtensions { /** * A human-readable narrative that contains a summary of the resource, and may be used to represent the content of the resource to a human. The narrative need not encode all the structured data, but is required to contain sufficient detail to make it "clinically safe" for a human to just read the narrative. Resource definitions may define what content should be represented in the narrative to ensure clinical safety. diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Element.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Element.java index b6841533751..732337bccc2 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Element.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Element.java @@ -37,10 +37,11 @@ import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.instance.model.annotations.Child; import org.hl7.fhir.instance.model.annotations.Description; import org.hl7.fhir.instance.model.annotations.DatatypeDef; +import org.hl7.fhir.instance.model.api.IBaseHasExtensions; /** * Base definition for all elements in a resource. */ -public abstract class Element extends Base { +public abstract class Element extends Base implements IBaseHasExtensions { /** * unique id for the element within a resource (for internal references). diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/EnumFactory.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/EnumFactory.java index dc27717ca51..c722c39e25e 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/EnumFactory.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/EnumFactory.java @@ -1,5 +1,7 @@ package org.hl7.fhir.instance.model; +import org.hl7.fhir.instance.model.api.IBaseEnumFactory; + /* Copyright (c) 2011+, HL7, Inc @@ -33,7 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. /** * Helper class to help manage generic enumerated types */ -public interface EnumFactory > { +public interface EnumFactory > extends IBaseEnumFactory { /** * Read an enumeration value from the string that represents it on the XML or JSON diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Enumeration.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Enumeration.java index 6eaa8ebd3d9..c0ed0894587 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Enumeration.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Enumeration.java @@ -1,6 +1,7 @@ package org.hl7.fhir.instance.model; import org.hl7.fhir.instance.model.annotations.DatatypeDef; +import org.hl7.fhir.instance.model.api.IBaseEnumFactory; /* Copyright (c) 2011+, HL7, Inc @@ -50,6 +51,16 @@ public class Enumeration > extends PrimitiveType { myEnumFactory = theEnumFactory; } + /** + * Constructor + */ + public Enumeration(IBaseEnumFactory theEnumFactory) { + if (theEnumFactory == null) + throw new IllegalArgumentException("An enumeration factory must be provided"); + myEnumFactory = (EnumFactory ) theEnumFactory; + } + + /** * Constructor */ diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Extension.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Extension.java index 22d10a27fc3..8d10bb2c5bc 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Extension.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Extension.java @@ -36,12 +36,14 @@ import java.util.List; import org.hl7.fhir.instance.model.annotations.Child; import org.hl7.fhir.instance.model.annotations.DatatypeDef; import org.hl7.fhir.instance.model.annotations.Description; +import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseExtension; +import org.hl7.fhir.instance.model.api.IBaseHasExtensions; /** * Optional Extensions Element - found in all resources. */ @DatatypeDef(name="Extension") -public class Extension extends Element implements IBaseExtension { +public class Extension extends Element implements IBaseExtension , IBaseHasExtensions { /** * Source of the definition for the extension code - a logical name or a URL. @@ -175,6 +177,11 @@ public class Extension extends Element implements IBaseExtension { ; } + @Override + public Extension setValue(IBaseDatatype theValue) { + return setValue((Type)theValue); + } + } diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Identifier.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Identifier.java index 49bcfad5ba0..c749600981c 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Identifier.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Identifier.java @@ -146,7 +146,7 @@ public class Identifier extends Type implements ICompositeType { /** * The purpose of this identifier. */ - @Child(name="use", type={CodeType.class}, order=0, min=0, max=1) + @Child(name="use", type={CodeType.class}, order=0, min=0, max=1, enumFactory=IdentifierUseEnumFactory.class) @Description(shortDefinition="usual | official | temp | secondary (If known)", formalDefinition="The purpose of this identifier." ) protected Enumeration use; diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/PrimitiveType.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/PrimitiveType.java index d58917a643d..8344292e9e0 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/PrimitiveType.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/PrimitiveType.java @@ -2,8 +2,9 @@ package org.hl7.fhir.instance.model; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.hl7.fhir.instance.model.api.IBaseHasExtensions; -public abstract class PrimitiveType extends Type implements IPrimitiveType { +public abstract class PrimitiveType extends Type implements IPrimitiveType , IBaseHasExtensions { private static final long serialVersionUID = 3L; diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/annotations/Child.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/annotations/Child.java index 97fac708847..bb0cda27e09 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/annotations/Child.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/annotations/Child.java @@ -34,7 +34,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.hl7.fhir.instance.model.Enumeration; import org.hl7.fhir.instance.model.IBase; +import org.hl7.fhir.instance.model.api.IBaseEnumFactory; /** * Field annotation for fields within resource and datatype definitions, indicating @@ -96,6 +98,12 @@ public @interface Child { */ Class extends IBase>[] type() default {}; + /** + * For children which accept an {@link Enumeration} as the type, this + * field indicates the type to use for the enum factory + */ + Class extends IBaseEnumFactory>> enumFactory() default NoEnumFactory.class; + // Not implemented // /** // * This value is used when extending a built-in model class and defining a @@ -105,5 +113,23 @@ public @interface Child { // * HumanNameDt which adds extensions of your choosing) you could do that using a replacement field. // */ // String replaces() default ""; + + public static class NoEnumFactory implements IBaseEnumFactory > { + + private NoEnumFactory() { + // non instantiable + } + @Override + public Enum> fromCode(String theCodeString) throws IllegalArgumentException { + return null; + } + + @Override + public String toCode(Enum> theCode) { + return null; + } + + } + } diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/model/ModelInheritanceTest.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/model/ModelInheritanceTest.java index 65a64de79d7..e695285dde4 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/model/ModelInheritanceTest.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/model/ModelInheritanceTest.java @@ -1,19 +1,24 @@ package ca.uhn.fhir.model; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import org.hl7.fhir.instance.model.Address; +import org.hl7.fhir.instance.model.BackboneElement; import org.hl7.fhir.instance.model.Base; import org.hl7.fhir.instance.model.BooleanType; import org.hl7.fhir.instance.model.Bundle; import org.hl7.fhir.instance.model.Coding; import org.hl7.fhir.instance.model.DecimalType; +import org.hl7.fhir.instance.model.DomainResource; +import org.hl7.fhir.instance.model.Element; import org.hl7.fhir.instance.model.Extension; import org.hl7.fhir.instance.model.IBase; import org.hl7.fhir.instance.model.ICompositeType; import org.hl7.fhir.instance.model.IPrimitiveType; import org.hl7.fhir.instance.model.IdType; +import org.hl7.fhir.instance.model.Identifier; import org.hl7.fhir.instance.model.IntegerType; import org.hl7.fhir.instance.model.Meta; import org.hl7.fhir.instance.model.Narrative; @@ -22,7 +27,9 @@ import org.hl7.fhir.instance.model.Reference; import org.hl7.fhir.instance.model.Resource; import org.hl7.fhir.instance.model.Timing; import org.hl7.fhir.instance.model.Type; +import org.hl7.fhir.instance.model.Identifier.IdentifierUseEnumFactory; import org.hl7.fhir.instance.model.annotations.Block; +import org.hl7.fhir.instance.model.annotations.Child; import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IBackboneElement; import org.hl7.fhir.instance.model.api.IBaseBooleanDatatype; @@ -30,6 +37,8 @@ import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype; import org.hl7.fhir.instance.model.api.IBaseExtension; +import org.hl7.fhir.instance.model.api.IBaseHasExtensions; +import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions; import org.hl7.fhir.instance.model.api.IBaseIntegerDatatype; import org.hl7.fhir.instance.model.api.ICoding; import org.hl7.fhir.instance.model.api.IDatatypeElement; @@ -56,6 +65,9 @@ public class ModelInheritanceTest { * * ElementDefinition * * Backbone elements (eg .ElementDefinitionSlicingComponent) do not extend BackboneElement or have a @Block annotation for some reason + * + * Extension + * * Should URL not be StringType since it can't take extensions? * */ @@ -76,13 +88,20 @@ public class ModelInheritanceTest { public void testBase() { assertTrue(IBase.class.isAssignableFrom(Base.class)); } + + public void testIdentifierUse() throws Exception { + Child child = Identifier.class.getField("use").getAnnotation(Child.class); + assertEquals(IdentifierUseEnumFactory.class, child.enumFactory()); + } + /** * Should be "implements IBaseExtension " */ @Test public void testExtension() { assertTrue(IBaseExtension.class.isAssignableFrom(Extension.class)); + assertTrue(IBaseHasExtensions.class.isAssignableFrom(Extension.class)); } @Test @@ -108,6 +127,7 @@ public class ModelInheritanceTest { @Test public void testPrimitiveType() { assertTrue(IPrimitiveType.class.isAssignableFrom(PrimitiveType.class)); + assertTrue(IBaseHasExtensions.class.isAssignableFrom(PrimitiveType.class)); } @Test @@ -136,7 +156,20 @@ public class ModelInheritanceTest { @Test public void testBackboneElement() { - assertTrue(IBackboneElement.class.isAssignableFrom(IBackboneElement.class)); + assertTrue(IBackboneElement.class.isAssignableFrom(BackboneElement.class)); + assertTrue(IBaseHasExtensions.class.isAssignableFrom(BackboneElement.class)); + assertTrue(IBaseHasModifierExtensions.class.isAssignableFrom(BackboneElement.class)); + } + + @Test + public void testElement() { + assertTrue(IBaseHasExtensions.class.isAssignableFrom(Element.class)); + } + + @Test + public void testDomainResource() { + assertTrue(IBaseHasExtensions.class.isAssignableFrom(DomainResource.class)); + assertTrue(IBaseHasModifierExtensions.class.isAssignableFrom(DomainResource.class)); } @Test diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java index 54e9bedcf2e..881c80f8b41 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java @@ -1,7 +1,16 @@ package ca.uhn.fhir.parser; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.stringContainsInOrder; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.io.OutputStreamWriter; @@ -25,15 +34,16 @@ import org.hl7.fhir.instance.model.Bundle; import org.hl7.fhir.instance.model.Bundle.BundleEntryComponent; import org.hl7.fhir.instance.model.Conformance; import org.hl7.fhir.instance.model.DateTimeType; +import org.hl7.fhir.instance.model.DateType; import org.hl7.fhir.instance.model.DecimalType; import org.hl7.fhir.instance.model.DiagnosticReport; import org.hl7.fhir.instance.model.Extension; import org.hl7.fhir.instance.model.HumanName; import org.hl7.fhir.instance.model.IBaseResource; import org.hl7.fhir.instance.model.IPrimitiveType; +import org.hl7.fhir.instance.model.Identifier.IdentifierUse; import org.hl7.fhir.instance.model.InstantType; import org.hl7.fhir.instance.model.List_; -import org.hl7.fhir.instance.model.Identifier.IdentifierUse; import org.hl7.fhir.instance.model.Narrative.NarrativeStatus; import org.hl7.fhir.instance.model.Observation; import org.hl7.fhir.instance.model.Organization; @@ -83,6 +93,119 @@ public class JsonParserTest { } + + @Test + public void testEncodeAndParseExtensions() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setUse(IdentifierUse.OFFICIAL).setSystem("urn:example").setValue("7000135"); + + Extension ext = new Extension(); + ext.setUrl("http://example.com/extensions#someext"); + ext.setValue(new DateTimeType("2011-01-02T11:13:15")); + patient.getExtension().add(ext); + + Extension parent = new Extension().setUrl("http://example.com#parent"); + patient.getExtension().add(parent); + Extension child1 = new Extension().setUrl( "http://example.com#child").setValue( new StringType("value1")); + parent.getExtension().add(child1); + Extension child2 = new Extension().setUrl( "http://example.com#child").setValue( new StringType("value2")); + parent.getExtension().add(child2); + + Extension modExt = new Extension(); + modExt.setUrl("http://example.com/extensions#modext"); + modExt.setValue(new DateType("1995-01-02")); + patient.getModifierExtension().add(modExt); + + HumanName name = patient.addName(); + name.addFamily("Blah"); + StringType given = name.addGivenElement(); + given.setValue("Joe"); + Extension ext2 = new Extension().setUrl("http://examples.com#givenext").setValue(new StringType("given")); + given.getExtension().add(ext2); + + StringType given2 = name.addGivenElement(); + given2.setValue("Shmoe"); + Extension given2ext = new Extension().setUrl("http://examples.com#givenext_parent"); + given2.getExtension().add(given2ext); + given2ext.addExtension().setUrl("http://examples.com#givenext_child").setValue(new StringType("CHILD")); + + String output = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newJsonParser().encodeResourceToString(patient); + assertThat(enc, org.hamcrest.Matchers.stringContainsInOrder("{\"resourceType\":\"Patient\",", + "\"extension\":[{\"url\":\"http://example.com/extensions#someext\",\"valueDateTime\":\"2011-01-02T11:13:15\"}", + "{\"url\":\"http://example.com#parent\",\"extension\":[{\"url\":\"http://example.com#child\",\"valueString\":\"value1\"},{\"url\":\"http://example.com#child\",\"valueString\":\"value2\"}]}" + )); + assertThat(enc, org.hamcrest.Matchers.stringContainsInOrder("\"modifierExtension\":[" + + "{" + + "\"url\":\"http://example.com/extensions#modext\"," + + "\"valueDate\":\"1995-01-02\"" + + "}" + + "],")); + assertThat(enc, containsString("\"_given\":[" + + "{" + + "\"extension\":[" + + "{" + + "\"url\":\"http://examples.com#givenext\"," + + "\"valueString\":\"given\"" + + "}" + + "]" + + "}," + + "{" + + "\"extension\":[" + + "{" + + "\"url\":\"http://examples.com#givenext_parent\"," + + "\"extension\":[" + + "{" + + "\"url\":\"http://examples.com#givenext_child\"," + + "\"valueString\":\"CHILD\"" + + "}" + + "]" + + "}" + + "]" + + "}")); + + /* + * Now parse this back + */ + + Patient parsed =ourCtx.newJsonParser().parseResource(Patient.class, enc); + ext = parsed.getExtension().get(0); + assertEquals("http://example.com/extensions#someext", ext.getUrl()); + assertEquals("2011-01-02T11:13:15", ((DateTimeType)ext.getValue()).getValueAsString()); + + parent = patient.getExtension().get(1); + assertEquals("http://example.com#parent", parent.getUrl()); + assertNull(parent.getValue()); + child1 = parent.getExtension().get(0); + assertEquals( "http://example.com#child", child1.getUrl()); + assertEquals("value1", ((StringType)child1.getValue()).getValueAsString()); + child2 = parent.getExtension().get(1); + assertEquals( "http://example.com#child", child2.getUrl()); + assertEquals("value2", ((StringType)child2.getValue()).getValueAsString()); + + modExt = parsed.getModifierExtension().get(0); + assertEquals("http://example.com/extensions#modext", modExt.getUrl()); + assertEquals("1995-01-02", ((DateType)modExt.getValue()).getValueAsString()); + + name = parsed.getName().get(0); + + ext2 = name.getGiven().get(0).getExtension().get(0); + assertEquals("http://examples.com#givenext", ext2.getUrl()); + assertEquals("given", ((StringType)ext2.getValue()).getValueAsString()); + + given2ext = name.getGiven().get(1).getExtension().get(0); + assertEquals("http://examples.com#givenext_parent", given2ext.getUrl()); + assertNull(given2ext.getValue()); + Extension given2ext2 = given2ext.getExtension().get(0); + assertEquals("http://examples.com#givenext_child", given2ext2.getUrl()); + assertEquals("CHILD", ((StringType)given2ext2.getValue()).getValue()); + + } + + @Test public void testEncodeNonContained() { Organization org = new Organization(); @@ -740,6 +863,7 @@ public class JsonParserTest { enc, containsString(" ")); assertThat(enc, containsString(" ")); + assertThat(enc, containsString(" ")); } diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java index fa45b0174f3..7c643b944bc 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java @@ -37,6 +37,7 @@ import org.hl7.fhir.instance.model.Composition; import org.hl7.fhir.instance.model.Conformance; import org.hl7.fhir.instance.model.Conformance.ConformanceRestResourceComponent; import org.hl7.fhir.instance.model.DateTimeType; +import org.hl7.fhir.instance.model.DateType; import org.hl7.fhir.instance.model.DecimalType; import org.hl7.fhir.instance.model.DiagnosticReport; import org.hl7.fhir.instance.model.DocumentManifest; @@ -876,7 +877,7 @@ public class XmlParserTest { } @Test - public void testMoreExtensions() throws Exception { + public void testEncodeAndParseExtensions() throws Exception { Patient patient = new Patient(); patient.addIdentifier().setUse(IdentifierUse.OFFICIAL).setSystem("urn:example").setValue("7000135"); @@ -884,14 +885,22 @@ public class XmlParserTest { Extension ext = new Extension(); ext.setUrl("http://example.com/extensions#someext"); ext.setValue(new DateTimeType("2011-01-02T11:13:15")); - - // Add the extension to the resource patient.getExtension().add(ext); - // END SNIPPET: resourceExtension - // START SNIPPET: resourceStringExtension + Extension parent = new Extension().setUrl("http://example.com#parent"); + patient.getExtension().add(parent); + Extension child1 = new Extension().setUrl( "http://example.com#child").setValue( new StringType("value1")); + parent.getExtension().add(child1); + Extension child2 = new Extension().setUrl( "http://example.com#child").setValue( new StringType("value2")); + parent.getExtension().add(child2); + + Extension modExt = new Extension(); + modExt.setUrl("http://example.com/extensions#modext"); + modExt.setValue(new DateType("1995-01-02")); + patient.getModifierExtension().add(modExt); + HumanName name = patient.addName(); - name.addFamily("Shmoe"); + name.addFamily("Blah"); StringType given = name.addGivenElement(); given.setValue("Joe"); Extension ext2 = new Extension().setUrl("http://examples.com#givenext").setValue(new StringType("given")); @@ -902,28 +911,55 @@ public class XmlParserTest { Extension given2ext = new Extension().setUrl("http://examples.com#givenext_parent"); given2.getExtension().add(given2ext); given2ext.addExtension().setUrl("http://examples.com#givenext_child").setValue(new StringType("CHILD")); - // END SNIPPET: resourceStringExtension - - // START SNIPPET: subExtension - Extension parent = new Extension().setUrl("http://example.com#parent"); - patient.getExtension().add(parent); - - Extension child1 = new Extension().setUrl( "http://example.com#child").setValue( new StringType("value1")); - parent.getExtension().add(child1); - - Extension child2 = new Extension().setUrl( "http://example.com#child").setValue( new StringType("value1")); - parent.getExtension().add(child2); - // END SNIPPET: subExtension String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); ourLog.info(output); String enc = ourCtx.newXmlParser().encodeResourceToString(patient); - assertThat(enc, containsString(" ")); + assertThat(enc, containsString(" ")); + assertThat(enc, containsString(" ")); assertThat( enc, - containsString(" ")); - assertThat(enc, containsString(" ")); + containsString(" ")); + assertThat(enc, containsString(" ")); + assertThat(enc, containsString(" ")); + + /* + * Now parse this back + */ + + Patient parsed =ourCtx.newXmlParser().parseResource(Patient.class, enc); + ext = parsed.getExtension().get(0); + assertEquals("http://example.com/extensions#someext", ext.getUrl()); + assertEquals("2011-01-02T11:13:15", ((DateTimeType)ext.getValue()).getValueAsString()); + + parent = patient.getExtension().get(1); + assertEquals("http://example.com#parent", parent.getUrl()); + assertNull(parent.getValue()); + child1 = parent.getExtension().get(0); + assertEquals( "http://example.com#child", child1.getUrl()); + assertEquals("value1", ((StringType)child1.getValue()).getValueAsString()); + child2 = parent.getExtension().get(1); + assertEquals( "http://example.com#child", child2.getUrl()); + assertEquals("value2", ((StringType)child2.getValue()).getValueAsString()); + + modExt = parsed.getModifierExtension().get(0); + assertEquals("http://example.com/extensions#modext", modExt.getUrl()); + assertEquals("1995-01-02", ((DateType)modExt.getValue()).getValueAsString()); + + name = parsed.getName().get(0); + + ext2 = name.getGiven().get(0).getExtension().get(0); + assertEquals("http://examples.com#givenext", ext2.getUrl()); + assertEquals("given", ((StringType)ext2.getValue()).getValueAsString()); + + given2ext = name.getGiven().get(1).getExtension().get(0); + assertEquals("http://examples.com#givenext_parent", given2ext.getUrl()); + assertNull(given2ext.getValue()); + Extension given2ext2 = given2ext.getExtension().get(0); + assertEquals("http://examples.com#givenext_child", given2ext2.getUrl()); + assertEquals("CHILD", ((StringType)given2ext2.getValue()).getValue()); + } @Test diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java index 4ff8d686c22..4fc2a43ac68 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java @@ -24,6 +24,7 @@ import java.io.InputStream; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.IBaseResource; +import org.hl7.fhir.instance.model.api.IBaseExtension; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirVersionEnum; @@ -107,5 +108,11 @@ public class FhirDev implements IFhirVersion { } + @Override + public IBaseExtension> newExtension() { + return null; + } + + } diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java index 66bd2e7837f..d3b0383ada0 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java @@ -35,6 +35,7 @@ import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.text.WordUtils; import org.hl7.fhir.instance.model.IBaseResource; +import org.hl7.fhir.instance.model.api.IBaseExtension; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition; @@ -379,6 +380,11 @@ public class FhirDstu1 implements IFhirVersion { return ContainedDt.class; } + @Override + public IBaseExtension> newExtension() { + return null; + } + } diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java index 255585d26e8..54fc0759cb3 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java @@ -23,6 +23,7 @@ package ca.uhn.fhir.model.dstu2; import java.io.InputStream; import org.hl7.fhir.instance.model.IBaseResource; +import org.hl7.fhir.instance.model.api.IBaseExtension; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirVersionEnum; @@ -92,4 +93,9 @@ public class FhirDstu2 implements IFhirVersion { throw new UnsupportedOperationException(); } + @Override + public IBaseExtension> newExtension() { + return null; + } + } diff --git a/src/site/xdoc/doc_rest_server.xml b/src/site/xdoc/doc_rest_server.xml index 9d24dda5776..7f18525bfc3 100644 --- a/src/site/xdoc/doc_rest_server.xml +++ b/src/site/xdoc/doc_rest_server.xml @@ -141,6 +141,29 @@ + + ++ The server will return data in a number of places that includes the + complete "identity" of a resource. Identity in this case refers to the + web address that a user can use to access the resource. +
++ For instance, if your server is hosted at
+http://foo.com/fhir
+ and your resource provider returns a Patient resource with the ID "123", + the server should translate that ID to "http://foo.com/fhir/Patient/123". ++ The server will attempt to determine what the base URL should be based on + what the request it receives looks like, but if it is not getting + the right address you may wish to hardcode the base URL, as shown + in the following example: +
++ + + +