[(fixjsongeneration)] When max cardinality in profile is changed to 1 output JSON should still contain an array.

This commit is contained in:
Petro Mykhaylyshyn 2020-01-02 15:38:26 +02:00 committed by James Agnew
parent 9c7f5e1b9b
commit a234b1f8a9
4 changed files with 132 additions and 5 deletions

View File

@ -24,6 +24,8 @@ import ca.uhn.fhir.context.*;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum; import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
import ca.uhn.fhir.model.api.*; import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.base.composite.BaseCodingDt; import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseContainedDt; import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
@ -44,6 +46,7 @@ import org.hl7.fhir.instance.model.api.*;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
import java.lang.reflect.Field;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.*; import java.util.*;
@ -357,6 +360,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
} }
} }
Map<String, Child> parentProfileElementMetadata = getParentProfileElementMetadata(theElement);
boolean haveWrittenExtensions = false; boolean haveWrittenExtensions = false;
for (CompositeChildElement nextChildElem : super.compositeChildIterator(theElement, theContainedResource, theParent, theEncodeContext)) { for (CompositeChildElement nextChildElem : super.compositeChildIterator(theElement, theContainedResource, theParent, theEncodeContext)) {
@ -487,7 +492,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
if (inArray) { if (inArray) {
theEventWriter.endArray(); theEventWriter.endArray();
} }
if (nextChild.getMax() > 1 || nextChild.getMax() == Child.MAX_UNLIMITED) { Child parentElementChildAnnotation = parentProfileElementMetadata.get(nextChild.getElementName());
if (isMultipleCardinality(nextChild.getMax()) || (parentElementChildAnnotation != null && isMultipleCardinality(parentElementChildAnnotation.max()))) {
beginArray(theEventWriter, nextChildSpecificName); beginArray(theEventWriter, nextChildSpecificName);
inArray = true; inArray = true;
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, nextChildElem, force, theEncodeContext); encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, nextChildElem, force, theEncodeContext);
@ -581,6 +587,24 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
} }
} }
private boolean isMultipleCardinality(int maxCardinality) {
return maxCardinality > 1 || maxCardinality == Child.MAX_UNLIMITED;
}
private Map<String, Child> getParentProfileElementMetadata(IBase theElement) {
Class<?> superclass = theElement.getClass().getSuperclass();
Map<String, Child> parentProfileElementsMetadata = new HashMap<>();
if(superclass.isAnnotationPresent(ResourceDef.class) || superclass.isAnnotationPresent(DatatypeDef.class)) {
for (Field field: superclass.getDeclaredFields()) {
Child childAnnotation = field.getAnnotation(Child.class);
if(childAnnotation != null) {
parentProfileElementsMetadata.put(childAnnotation.name(), childAnnotation);
}
}
}
return parentProfileElementsMetadata;
}
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonLikeWriter theEventWriter, boolean theContainedResource, CompositeChildElement theParent, EncodeContext theEncodeContext) throws IOException, DataFormatException { private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonLikeWriter theEventWriter, boolean theContainedResource, CompositeChildElement theParent, EncodeContext theEncodeContext) throws IOException, DataFormatException {
writeCommentsPreAndPost(theNextValue, theEventWriter); writeCommentsPreAndPost(theNextValue, theEventWriter);

View File

@ -3,15 +3,14 @@ package ca.uhn.fhir.parser;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.*; import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.base.composite.BaseCodingDt; import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt; import ca.uhn.fhir.model.dstu2.composite.*;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.*; import ca.uhn.fhir.model.dstu2.resource.*;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.valueset.*; import ca.uhn.fhir.model.dstu2.valueset.*;
import ca.uhn.fhir.model.primitive.*; import ca.uhn.fhir.model.primitive.*;
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation; import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
import ca.uhn.fhir.parser.testprofile.CommunicationProfile;
import ca.uhn.fhir.parser.testprofile.PatientProfile;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Level;
@ -1081,6 +1080,52 @@ public class JsonParserDstu2Test {
} }
} }
/**
* When max cardinality in profile is changed to 1 output JSON should still contain an array.
* http://hl7.org/fhir/profiling.html#cardinality
*/
@Test
public void testEncodePatientProfileWithChangedCardinalityFromManyToOne() {
PatientProfile patient = new PatientProfile();
patient.myIdentifier = Collections.singletonList(new IdentifierDt("http://test-system", "test-code"));
String encoded = ourCtx.newJsonParser().encodeResourceToString(patient);
ourLog.info(encoded);
assertThat(encoded, containsString("\"identifier\":[{\"system\":\"http://test-system\",\"value\":\"test-code\"}]"));
}
/**
* When max cardinality in profile is changed to 1 output JSON should still contain an array.
* http://hl7.org/fhir/profiling.html#cardinality
*/
@Test
public void testEncodePatientProfileWithChangedCardinalityFromManyToOneAsList() {
PatientProfile patient = new PatientProfile();
patient.myName = new HumanNameDt().setText("Testname");
String encoded = ourCtx.newJsonParser().encodeResourceToString(patient);
ourLog.info(encoded);
assertThat(encoded, containsString("\"name\":[{\"text\":\"Testname\"}]"));
}
/**
* When max cardinality in profile is changed to 1 output JSON should still contain an array.
* http://hl7.org/fhir/profiling.html#cardinality
*/
@Test
public void testEncodeCommunicationProfileWithChangedCardinalityFromManyToOneAsList() {
CommunicationProfile communication = new CommunicationProfile();
communication.myPayload = new CommunicationProfile._Payload();
communication.myPayload.myContent = new StringDt("testContent");
String encoded = ourCtx.newJsonParser().encodeResourceToString(communication);
ourLog.info(encoded);
assertThat(encoded, containsString("\"payload\":[{\"contentString\":\"testContent\"}]"));
}
@Test @Test
public void testEncodingNullExtension() { public void testEncodingNullExtension() {
Patient p = new Patient(); Patient p = new Patient();

View File

@ -0,0 +1,32 @@
package ca.uhn.fhir.parser.testprofile;
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.ResourceDef;
import ca.uhn.fhir.model.dstu2.resource.Communication;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.util.ElementUtil;
@ResourceDef(name = "Communication", profile = "http://hl7.org/fhir/profiles/CommunicationProfile", id = "communicationProfile")
public class CommunicationProfile extends Communication {
@Child(name = "payload", min = 1, max = 1, order = Child.REPLACE_PARENT, type = {_Payload.class})
@Description(shortDefinition = "", formalDefinition = "Text, attachment(s), or resource(s) that was communicated to the recipient.")
public _Payload myPayload;
@Block
public static class _Payload extends Payload {
@Child(name = "content", min = 0, max = 1, order = Child.REPLACE_PARENT, type = {StringDt.class})
@Description(shortDefinition = "", formalDefinition = "A communicated content")
public StringDt myContent;
@Override
public boolean isEmpty() {
return super.isEmpty() && ElementUtil.isEmpty(myContent);
}
}
}

View File

@ -0,0 +1,26 @@
package ca.uhn.fhir.parser.testprofile;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import java.util.List;
@ResourceDef(name="Patient", profile="http://hl7.org/fhir/profiles/PatientProfile", id="patientProfile")
public class PatientProfile extends Patient {
/**
* identifier
*/
@Child(name = "identifier", min = 1, max = 1, order = Child.REPLACE_PARENT, summary = true, type = {IdentifierDt.class})
@Description(shortDefinition = "id", formalDefinition = "An identifier for this patient.")
public List<IdentifierDt> myIdentifier;
@Child(name = "name", min = 1, max = 1, order = Child.REPLACE_PARENT, summary = true, type = {HumanNameDt.class})
@Description(shortDefinition = "", formalDefinition = "Name.")
public HumanNameDt myName;
}