Respect order for order=REPLACE_PARENT

This commit is contained in:
James Agnew 2016-06-29 10:26:36 -04:00
parent 1eb1dc7e36
commit 38d30eef49
4 changed files with 100 additions and 4 deletions

View File

@ -245,6 +245,8 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IBase> ext
String elementName = childAnnotation.name(); String elementName = childAnnotation.name();
int order = childAnnotation.order(); int order = childAnnotation.order();
boolean childIsChoiceType = false; boolean childIsChoiceType = false;
boolean orderIsReplaceParent = false;
if (order == Child.REPLACE_PARENT) { if (order == Child.REPLACE_PARENT) {
if (extensionAttr != null) { if (extensionAttr != null) {
@ -253,6 +255,7 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IBase> ext
BaseRuntimeDeclaredChildDefinition nextDef = nextEntry.getValue(); BaseRuntimeDeclaredChildDefinition nextDef = nextEntry.getValue();
if (nextDef instanceof RuntimeChildDeclaredExtensionDefinition) { if (nextDef instanceof RuntimeChildDeclaredExtensionDefinition) {
if (nextDef.getExtensionUrl().equals(extensionAttr.url())) { if (nextDef.getExtensionUrl().equals(extensionAttr.url())) {
orderIsReplaceParent = true;
order = nextEntry.getKey(); order = nextEntry.getKey();
orderMap.remove(nextEntry.getKey()); orderMap.remove(nextEntry.getKey());
elementNames.remove(elementName); elementNames.remove(elementName);
@ -270,6 +273,7 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IBase> ext
for (Entry<Integer, BaseRuntimeDeclaredChildDefinition> nextEntry : orderMap.entrySet()) { for (Entry<Integer, BaseRuntimeDeclaredChildDefinition> nextEntry : orderMap.entrySet()) {
BaseRuntimeDeclaredChildDefinition nextDef = nextEntry.getValue(); BaseRuntimeDeclaredChildDefinition nextDef = nextEntry.getValue();
if (elementName.equals(nextDef.getElementName())) { if (elementName.equals(nextDef.getElementName())) {
orderIsReplaceParent = true;
order = nextEntry.getKey(); order = nextEntry.getKey();
BaseRuntimeDeclaredChildDefinition existing = orderMap.remove(nextEntry.getKey()); BaseRuntimeDeclaredChildDefinition existing = orderMap.remove(nextEntry.getKey());
elementNames.remove(elementName); elementNames.remove(elementName);
@ -297,7 +301,8 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IBase> ext
if (order < 0 && order != Child.ORDER_UNKNOWN) { if (order < 0 && order != Child.ORDER_UNKNOWN) {
throw new ConfigurationException("Invalid order '" + order + "' on @Child for field '" + next.getName() + "' on target type: " + theClass); throw new ConfigurationException("Invalid order '" + order + "' on @Child for field '" + next.getName() + "' on target type: " + theClass);
} }
if (order != Child.ORDER_UNKNOWN) {
if (order != Child.ORDER_UNKNOWN && !orderIsReplaceParent) {
order = order + baseElementOrder; order = order + baseElementOrder;
} }
// int min = childAnnotation.min(); // int min = childAnnotation.min();

View File

@ -0,0 +1,58 @@
package ca.uhn.fhir.parser;
import org.hl7.fhir.dstu3.exceptions.FHIRException;
import org.hl7.fhir.dstu3.model.Identifier;
import org.hl7.fhir.dstu3.model.MessageHeader;
import ca.uhn.fhir.model.api.annotation.Block;
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;
@ResourceDef(name = "FooMessageHeader")
public class FooMessageHeaderWithExplicitField extends MessageHeader {
private static final long serialVersionUID = 1L;
/**
* The source application from which this message originated.
*/
@Child(name = "source", type = {}, order = Child.REPLACE_PARENT, min = 1, max = 1, modifier = false, summary = true)
@Description(shortDefinition = "Message Source Application", formalDefinition = "The source application from which this message originated.")
protected FooMessageSourceComponent source;
public void setSourceNew(FooMessageSourceComponent theSource) {
source = theSource;
}
@Block()
public static class FooMessageSourceComponent extends MessageHeader.MessageSourceComponent {
private static final long serialVersionUID = 1L;
@Child(name = "ext-messageheader-application-id", type = Identifier.class, modifier = true)
@Description(shortDefinition = "Message Header Application ID")
@Extension(url = "http://foo", definedLocally = false, isModifier = false)
private Identifier messageHeaderApplicationId;
/*
* Get messageHeaderApplicationId
*/
public Identifier getMessageHeaderApplicationId() throws FHIRException {
if (messageHeaderApplicationId == null) {
messageHeaderApplicationId = new Identifier();
}
return messageHeaderApplicationId;
}
/*
* Set messageHeaderApplicationId
*/
public void setmessageHeaderApplicationId(Identifier messageHeaderApplicationId) {
this.messageHeaderApplicationId = messageHeaderApplicationId;
}
}
}

View File

@ -34,7 +34,6 @@ import org.custommonkey.xmlunit.XMLUnit;
import org.hamcrest.collection.IsEmptyCollection; import org.hamcrest.collection.IsEmptyCollection;
import org.hamcrest.core.StringContains; import org.hamcrest.core.StringContains;
import org.hamcrest.text.StringContainsInOrder; import org.hamcrest.text.StringContainsInOrder;
import org.hl7.fhir.dstu3.exceptions.FHIRException;
import org.hl7.fhir.dstu3.model.Address.AddressUse; import org.hl7.fhir.dstu3.model.Address.AddressUse;
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory; import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
import org.hl7.fhir.dstu3.model.AllergyIntolerance; import org.hl7.fhir.dstu3.model.AllergyIntolerance;
@ -77,7 +76,6 @@ import org.hl7.fhir.dstu3.model.Location;
import org.hl7.fhir.dstu3.model.Medication; import org.hl7.fhir.dstu3.model.Medication;
import org.hl7.fhir.dstu3.model.MedicationOrder; import org.hl7.fhir.dstu3.model.MedicationOrder;
import org.hl7.fhir.dstu3.model.MedicationStatement; import org.hl7.fhir.dstu3.model.MedicationStatement;
import org.hl7.fhir.dstu3.model.MessageHeader.MessageSourceComponent;
import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Observation.ObservationRelationshipType; import org.hl7.fhir.dstu3.model.Observation.ObservationRelationshipType;
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus; import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
@ -107,6 +105,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.ResourceDef; import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.parser.FooMessageHeaderWithExplicitField.FooMessageSourceComponent;
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation; import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
@ -1407,6 +1406,8 @@ public class XmlParserDstu3Test {
FooMessageHeader header = new FooMessageHeader(); FooMessageHeader header = new FooMessageHeader();
header.setSource(source); header.setSource(source);
header.addDestination().setName("DEST");
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.addEntry().setResource(header); bundle.addEntry().setResource(header);
@ -1417,6 +1418,31 @@ public class XmlParserDstu3Test {
ourLog.info(encode); ourLog.info(encode);
assertThat(encode, containsString("<value value=\"APPID\"/>")); assertThat(encode, containsString("<value value=\"APPID\"/>"));
assertThat(encode, stringContainsInOrder("<source", "<dest"));
}
@Test
public void testEncodeDeclaredBlock() throws Exception {
FooMessageSourceComponent source = new FooMessageHeaderWithExplicitField.FooMessageSourceComponent();
source.getMessageHeaderApplicationId().setValue("APPID");
source.setName("NAME");
FooMessageHeaderWithExplicitField header = new FooMessageHeaderWithExplicitField();
header.setSourceNew(source);
header.addDestination().setName("DEST");
Bundle bundle = new Bundle();
bundle.addEntry().setResource(header);
IParser p = ourCtx.newXmlParser();
p.setPrettyPrint(true);
String encode = p.encodeResourceToString(bundle);
ourLog.info(encode);
assertThat(encode, containsString("<value value=\"APPID\"/>"));
assertThat(encode, stringContainsInOrder("<source", "<dest"));
} }
@Test @Test

View File

@ -395,6 +395,13 @@
Parser is now better able to handle encoding fields which have been Parser is now better able to handle encoding fields which have been
populated with a class that extends the expected class populated with a class that extends the expected class
</action> </action>
<action type="fix">
When declaring a child with
<![CDATA[<code>order=Child.REPLACE_PARENT</code>]]>
the serialized form still put the element at the
end of the resource instead of in the correct
order
</action>
</release> </release>
<release version="1.5" date="2016-04-20"> <release version="1.5" date="2016-04-20">
<action type="fix" issue="339"> <action type="fix" issue="339">