Encode non-resource types (#5003)
* Encode non-resource types * Add changelog * Compile fix
This commit is contained in:
parent
ee3c59a3bc
commit
ddf3b72f2d
|
@ -223,7 +223,7 @@ class ModelScanner {
|
|||
private void scanBlock(Class<? extends IBase> theClass) {
|
||||
ourLog.debug("Scanning resource block class: {}", theClass.getName());
|
||||
|
||||
String resourceName = theClass.getCanonicalName();
|
||||
String blockName = theClass.getSimpleName();
|
||||
|
||||
// Just in case someone messes up when upgrading from DSTU2
|
||||
if (myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
|
||||
|
@ -232,7 +232,7 @@ class ModelScanner {
|
|||
}
|
||||
}
|
||||
|
||||
RuntimeResourceBlockDefinition blockDef = new RuntimeResourceBlockDefinition(resourceName, theClass, isStandardType(theClass), myContext, myClassToElementDefinitions);
|
||||
RuntimeResourceBlockDefinition blockDef = new RuntimeResourceBlockDefinition(blockName, theClass, isStandardType(theClass), myContext, myClassToElementDefinitions);
|
||||
blockDef.populateScanAlso(myScanAlso);
|
||||
|
||||
myClassToElementDefinitions.put(theClass, blockDef);
|
||||
|
|
|
@ -100,7 +100,7 @@ public abstract class BaseParser implements IParser {
|
|||
|
||||
private FhirTerser.ContainedResources myContainedResources;
|
||||
private boolean myEncodeElementsAppliesToChildResourcesOnly;
|
||||
private FhirContext myContext;
|
||||
private final FhirContext myContext;
|
||||
private List<EncodeContextPath> myDontEncodeElements;
|
||||
private List<EncodeContextPath> myEncodeElements;
|
||||
private Set<String> myEncodeElementsAppliesToResourceTypes;
|
||||
|
@ -262,6 +262,10 @@ public abstract class BaseParser implements IParser {
|
|||
|
||||
protected abstract void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter, EncodeContext theEncodeContext) throws IOException, DataFormatException;
|
||||
|
||||
protected void doEncodeToWriter(IBase theElement, Writer theWriter, EncodeContext theEncodeContext) throws IOException, DataFormatException {
|
||||
throw new InternalErrorException(Msg.code(2363) + "This parser does not support encoding non-resource values");
|
||||
}
|
||||
|
||||
protected abstract <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) throws DataFormatException;
|
||||
|
||||
@Override
|
||||
|
@ -270,7 +274,7 @@ public abstract class BaseParser implements IParser {
|
|||
try {
|
||||
encodeResourceToWriter(theResource, stringWriter);
|
||||
} catch (IOException e) {
|
||||
throw new Error(Msg.code(1828) + "Encountered IOException during write to string - This should not happen!");
|
||||
throw new Error(Msg.code(1828) + "Encountered IOException during write to string - This should not happen!", e);
|
||||
}
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
@ -278,10 +282,34 @@ public abstract class BaseParser implements IParser {
|
|||
@Override
|
||||
public final void encodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException, DataFormatException {
|
||||
EncodeContext encodeContext = new EncodeContext();
|
||||
|
||||
encodeResourceToWriter(theResource, theWriter, encodeContext);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String encodeToString(IBase theElement) throws DataFormatException {
|
||||
Writer stringWriter = new StringBuilderWriter();
|
||||
try {
|
||||
encodeToWriter(theElement, stringWriter);
|
||||
} catch (IOException e) {
|
||||
throw new Error(Msg.code(2364) + "Encountered IOException during write to string - This should not happen!", e);
|
||||
}
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeToWriter(IBase theElement, Writer theWriter) throws DataFormatException, IOException {
|
||||
if (theElement instanceof IBaseResource) {
|
||||
encodeResourceToWriter((IBaseResource) theElement, theWriter);
|
||||
} else if (theElement instanceof IPrimitiveType) {
|
||||
theWriter.write(((IPrimitiveType<?>) theElement).getValueAsString());
|
||||
} else {
|
||||
EncodeContext encodeContext = new EncodeContext();
|
||||
encodeToWriter(theElement, theWriter, encodeContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void encodeResourceToWriter(IBaseResource theResource, Writer theWriter, EncodeContext theEncodeContext) throws IOException {
|
||||
Validate.notNull(theResource, "theResource can not be null");
|
||||
Validate.notNull(theWriter, "theWriter can not be null");
|
||||
|
@ -289,12 +317,11 @@ public abstract class BaseParser implements IParser {
|
|||
|
||||
if (myContext.getVersion().getVersion() == FhirVersionEnum.R4B && theResource.getStructureFhirVersionEnum() == FhirVersionEnum.R5) {
|
||||
// TODO: remove once we've bumped the core lib version
|
||||
} else
|
||||
if (theResource.getStructureFhirVersionEnum() != myContext.getVersion().getVersion()) {
|
||||
} else if (theResource.getStructureFhirVersionEnum() != myContext.getVersion().getVersion()) {
|
||||
throw new IllegalArgumentException(Msg.code(1829) + "This parser is for FHIR version " + myContext.getVersion().getVersion() + " - Can not encode a structure for version " + theResource.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
String resourceName = myContext.getResourceType(theResource);
|
||||
String resourceName = myContext.getElementDefinition(theResource.getClass()).getName();
|
||||
theEncodeContext.pushPath(resourceName, true);
|
||||
|
||||
doEncodeResourceToWriter(theResource, theWriter, theEncodeContext);
|
||||
|
@ -302,6 +329,20 @@ public abstract class BaseParser implements IParser {
|
|||
theEncodeContext.popPath();
|
||||
}
|
||||
|
||||
protected void encodeToWriter(IBase theElement, Writer theWriter, EncodeContext theEncodeContext) throws IOException {
|
||||
Validate.notNull(theElement, "theElement can not be null");
|
||||
Validate.notNull(theWriter, "theWriter can not be null");
|
||||
Validate.notNull(theEncodeContext, "theEncodeContext can not be null");
|
||||
|
||||
BaseRuntimeElementDefinition<?> def = myContext.getElementDefinition(theElement.getClass());
|
||||
String elementName = def.getName();
|
||||
theEncodeContext.pushPath(elementName, true);
|
||||
|
||||
doEncodeToWriter(theElement, theWriter, theEncodeContext);
|
||||
|
||||
theEncodeContext.popPath();
|
||||
}
|
||||
|
||||
private void filterCodingsWithNoCodeOrSystem(List<? extends IBaseCoding> tagList) {
|
||||
for (int i = 0; i < tagList.size(); i++) {
|
||||
if (isBlank(tagList.get(i).getCode()) && isBlank(tagList.get(i).getSystem())) {
|
||||
|
@ -896,7 +937,7 @@ public abstract class BaseParser implements IParser {
|
|||
RuntimeChildChoiceDefinition choice = (RuntimeChildChoiceDefinition) nextChild;
|
||||
b.append(" - Expected one of: " + choice.getValidChildTypes());
|
||||
}
|
||||
throw new DataFormatException(Msg.code(1831) + b.toString());
|
||||
throw new DataFormatException(Msg.code(1831) + b);
|
||||
}
|
||||
throw new DataFormatException(Msg.code(1832) + nextChild + " has no child of type " + theType);
|
||||
}
|
||||
|
@ -971,7 +1012,7 @@ public abstract class BaseParser implements IParser {
|
|||
if (myDef != null) {
|
||||
path.append(myDef.getElementName());
|
||||
}
|
||||
ourLog.trace(" * Next path: {}", path.toString());
|
||||
ourLog.trace(" * Next path: {}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import ca.uhn.fhir.context.ParserOptions;
|
|||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
|
@ -46,10 +47,56 @@ import java.util.Set;
|
|||
*/
|
||||
public interface IParser {
|
||||
|
||||
/**
|
||||
* Encodes a resource using the parser's given encoding format.
|
||||
*
|
||||
* @param theResource The resource to encode. Must not be null.
|
||||
* @return A string representation of the encoding
|
||||
* @throws DataFormatException If any invalid elements within the contents to be encoded prevent successful encoding.
|
||||
*/
|
||||
String encodeResourceToString(IBaseResource theResource) throws DataFormatException;
|
||||
|
||||
/**
|
||||
* Encodes a resource using the parser's given encoding format.
|
||||
*
|
||||
* @param theResource The resource to encode. Must not be null.
|
||||
* @param theWriter The writer to write to.
|
||||
* @throws DataFormatException If any invalid elements within the contents to be encoded prevent successful encoding.
|
||||
*/
|
||||
void encodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException, DataFormatException;
|
||||
|
||||
/**
|
||||
* Encodes any FHIR element to a string.
|
||||
* If a {@link IBaseResource resource object} is passed in, the resource will be encoded using standard FHIR
|
||||
* encoding rules. If a {@link org.hl7.fhir.instance.model.api.IPrimitiveType primitive datatype} is passed in,
|
||||
* the string value of the primitive type is encoded. Any extensions on the primitive type are not encoded.
|
||||
* If any other object is passed in, a fragment is encoded. The format of the fragment depends on the encoding:
|
||||
* <ul>
|
||||
* <li><b>JSON</b>: The fragment is output as a simple JSON object, exactly as it would appear within an encoded resource.</li>
|
||||
* <li><b>XML</b>: The fragment is output as an XML element as it would appear within an encoded resource, however it is wrapped in an element called <code><element></code> in order to avoid producing a document with multiple root tags.</li>
|
||||
* <li><b>RDF/Turtle</b>: This mode is not supported and will throw an {@link ca.uhn.fhir.rest.server.exceptions.InternalErrorException}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 6.8.0
|
||||
*/
|
||||
String encodeToString(IBase theElement) throws DataFormatException;
|
||||
|
||||
/**
|
||||
* Encodes any FHIR element to a writer.
|
||||
* If a {@link IBaseResource resource object} is passed in, the resource will be encoded using standard FHIR
|
||||
* encoding rules. If a {@link org.hl7.fhir.instance.model.api.IPrimitiveType primitive datatype} is passed in,
|
||||
* the string value of the primitive type is encoded. Any extensions on the primitive type are not encoded.
|
||||
* If any other object is passed in, a fragment is encoded. The format of the fragment depends on the encoding:
|
||||
* <ul>
|
||||
* <li><b>JSON</b>: The fragment is output as a simple JSON object, exactly as it would appear within an encoded resource.</li>
|
||||
* <li><b>XML</b>: The fragment is output as an XML element as it would appear within an encoded resource, however it is wrapped in an element called <code><element></code> in order to avoid producing a document with multiple root tags.</li>
|
||||
* <li><b>RDF/Turtle</b>: This mode is not supported and will throw an {@link ca.uhn.fhir.rest.server.exceptions.InternalErrorException}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 6.8.0
|
||||
*/
|
||||
void encodeToWriter(IBase theElement, Writer theWriter) throws DataFormatException, IOException;
|
||||
|
||||
/**
|
||||
* If not set to null (as is the default) this ID will be used as the ID in any
|
||||
* resources encoded by this parser
|
||||
|
|
|
@ -210,6 +210,15 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
eventWriter.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEncodeToWriter(IBase theElement, Writer theWriter, EncodeContext theEncodeContext) throws IOException, DataFormatException {
|
||||
BaseJsonLikeWriter eventWriter = createJsonWriter(theWriter);
|
||||
eventWriter.beginObject();
|
||||
encodeCompositeElementToStreamWriter(null, null, theElement, eventWriter, false, null, theEncodeContext);
|
||||
eventWriter.endObject();
|
||||
eventWriter.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) {
|
||||
JsonLikeStructure jsonStructure = new JacksonStructure();
|
||||
|
@ -1446,9 +1455,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
// Undeclared extensions
|
||||
extractUndeclaredExtensions(theValue, extensions, modifierExtensions, myParent, null, theEncodeContext, theContainedResource);
|
||||
// Declared extensions
|
||||
if (def != null) {
|
||||
extractDeclaredExtensions(theValue, def, extensions, modifierExtensions, myParent);
|
||||
}
|
||||
extractDeclaredExtensions(theValue, def, extensions, modifierExtensions, myParent);
|
||||
boolean haveContent = false;
|
||||
if (!extensions.isEmpty() || !modifierExtensions.isEmpty()) {
|
||||
haveContent = true;
|
||||
|
|
|
@ -33,6 +33,7 @@ import ca.uhn.fhir.i18n.Msg;
|
|||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.rdf.RDFUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jena.datatypes.xsd.XSDDatatype;
|
||||
|
@ -59,6 +60,7 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||
import org.hl7.fhir.instance.model.api.INarrative;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.Arrays;
|
||||
|
|
|
@ -71,6 +71,7 @@ import javax.xml.stream.events.EntityReference;
|
|||
import javax.xml.stream.events.Namespace;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
|
@ -140,6 +141,22 @@ public class XmlParser extends BaseParser {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEncodeToWriter(IBase theElement, Writer theWriter, EncodeContext theEncodeContext) throws IOException, DataFormatException {
|
||||
XMLStreamWriter eventWriter;
|
||||
try {
|
||||
eventWriter = createXmlWriter(theWriter);
|
||||
|
||||
eventWriter.writeStartElement("element");
|
||||
encodeCompositeElementToStreamWriter(null, theElement, eventWriter, false, new CompositeChildElement(null, theEncodeContext), theEncodeContext);
|
||||
eventWriter.writeEndElement();
|
||||
|
||||
eventWriter.flush();
|
||||
} catch (XMLStreamException e) {
|
||||
throw new ConfigurationException(Msg.code(2365) + "Failed to initialize STaX event factory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) {
|
||||
XMLEventReader streamReader = createStreamReader(theReader);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: add
|
||||
issue: 5003
|
||||
title: "The IParser interface now has an additional pair of methods called `encodeToString(IBase)` and `encodeToWriter(IBase, Writer)` that
|
||||
can be used to encode fragments of resources, such as datatypes or infrastructure elements."
|
|
@ -21,6 +21,7 @@ import org.hl7.fhir.r4.model.Binary;
|
|||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Composition;
|
||||
import org.hl7.fhir.r4.model.DateTimeType;
|
||||
import org.hl7.fhir.r4.model.DecimalType;
|
||||
import org.hl7.fhir.r4.model.Device;
|
||||
import org.hl7.fhir.r4.model.DocumentReference;
|
||||
import org.hl7.fhir.r4.model.Encounter;
|
||||
|
@ -1158,6 +1159,48 @@ public class JsonParserR4Test extends BaseTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeToString_PrimitiveDataType() {
|
||||
DecimalType object = new DecimalType("123.456000");
|
||||
String expected = "123.456000";
|
||||
String actual = ourCtx.newJsonParser().encodeToString(object);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeToString_Resource() {
|
||||
Patient p = new Patient();
|
||||
p.setId("Patient/123");
|
||||
p.setActive(true);
|
||||
String expected = "{\"resourceType\":\"Patient\",\"id\":\"123\",\"active\":true}";
|
||||
String actual = ourCtx.newJsonParser().encodeToString(p);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeToString_GeneralPurposeDataType() {
|
||||
HumanName name = new HumanName();
|
||||
name.setFamily("Simpson").addGiven("Homer").addGiven("Jay");
|
||||
name.addExtension("http://foo", new StringType("bar"));
|
||||
|
||||
String expected = "{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"bar\"}],\"family\":\"Simpson\",\"given\":[\"Homer\",\"Jay\"]}";
|
||||
String actual = ourCtx.newJsonParser().encodeToString(name);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeToString_BackboneElement() {
|
||||
Patient.PatientCommunicationComponent communication = new Patient().addCommunication();
|
||||
communication.setPreferred(true);
|
||||
communication.getLanguage().setText("English");
|
||||
|
||||
String expected = "{\"language\":{\"text\":\"English\"},\"preferred\":true}";
|
||||
String actual = ourCtx.newJsonParser().encodeToString(communication);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPreCommentsToFhirComments() {
|
||||
final Patient patient = new Patient();
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.r4.model.DecimalType;
|
||||
import org.hl7.fhir.r4.model.Encounter;
|
||||
import org.hl7.fhir.r4.model.HumanName;
|
||||
import org.hl7.fhir.r4.model.Medication;
|
||||
import org.hl7.fhir.r4.model.MedicationDispense;
|
||||
import org.hl7.fhir.r4.model.MedicationRequest;
|
||||
|
@ -13,6 +16,7 @@ import org.hl7.fhir.r4.model.Patient;
|
|||
import org.hl7.fhir.r4.model.Practitioner;
|
||||
import org.hl7.fhir.r4.model.QuestionnaireResponse;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -23,269 +27,62 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@Disabled
|
||||
public class RDFParserR4Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(RDFParserR4Test.class);
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final FhirContext ourCtx = FhirContext.forR4Cached();
|
||||
|
||||
/*
|
||||
private Bundle createBundleWithPatient() {
|
||||
Bundle b = new Bundle();
|
||||
b.setId("BUNDLEID");
|
||||
b.getMeta().addProfile("http://FOO");
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeToString_PrimitiveDataType() {
|
||||
DecimalType object = new DecimalType("123.456000");
|
||||
String expected = "123.456000";
|
||||
String actual = ourCtx.newRDFParser().encodeToString(object);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeToString_Resource() {
|
||||
Patient p = new Patient();
|
||||
p.setId("PATIENTID");
|
||||
p.getMeta().addProfile("http://BAR");
|
||||
p.addName().addGiven("GIVEN");
|
||||
b.addEntry().setResource(p);
|
||||
return b;
|
||||
}
|
||||
*/
|
||||
p.setId("Patient/123");
|
||||
p.setActive(true);
|
||||
String expected = """
|
||||
@prefix fhir: <http://hl7.org/fhir/> .
|
||||
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
@prefix sct: <http://snomed.info/id#> .
|
||||
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
||||
|
||||
@Test
|
||||
public void testDontStripVersions() {
|
||||
FhirContext ctx = FhirContext.forR4();
|
||||
ctx.getParserOptions().setDontStripVersionsFromReferencesAtPaths("QuestionnaireResponse.questionnaire");
|
||||
<http://hl7.org/fhir/Patient/123>
|
||||
rdf:type fhir:Patient ;
|
||||
fhir:Patient.active [ fhir:value true ] ;
|
||||
fhir:Resource.id [ fhir:value "123" ] ;
|
||||
fhir:nodeRole fhir:treeRoot .
|
||||
""";
|
||||
|
||||
QuestionnaireResponse qr = new QuestionnaireResponse();
|
||||
qr.getQuestionnaireElement().setValueAsString("Questionnaire/123/_history/456");
|
||||
|
||||
String output = ctx.newRDFParser().setPrettyPrint(true).encodeResourceToString(qr);
|
||||
ourLog.info(output);
|
||||
|
||||
assertThat(output, containsString("\"Questionnaire/123/_history/456\""));
|
||||
String actual = ourCtx.newRDFParser().encodeToString(p);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateContainedResourcesNotOutputtedTwice() {
|
||||
MedicationDispense md = new MedicationDispense();
|
||||
public void testEncodeToString_GeneralPurposeDataType() {
|
||||
HumanName name = new HumanName();
|
||||
name.setFamily("Simpson").addGiven("Homer").addGiven("Jay");
|
||||
name.addExtension("http://foo", new StringType("bar"));
|
||||
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
md.addAuthorizingPrescription().setResource(mr);
|
||||
|
||||
Medication med = new Medication();
|
||||
md.setMedication(new Reference(med));
|
||||
mr.setMedication(new Reference(med));
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(md);
|
||||
ourLog.info(encoded);
|
||||
|
||||
int idx = encoded.indexOf("\"Medication\"");
|
||||
assertNotEquals(-1, idx);
|
||||
|
||||
idx = encoded.indexOf("\"Medication\"", idx + 1);
|
||||
assertEquals(-1, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* See #814
|
||||
*/
|
||||
@Test
|
||||
public void testDuplicateContainedResourcesNotOutputtedTwiceWithManualIds() {
|
||||
MedicationDispense md = new MedicationDispense();
|
||||
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
mr.setId("#MR");
|
||||
md.addAuthorizingPrescription().setResource(mr);
|
||||
|
||||
Medication med = new Medication();
|
||||
med.setId("#MED");
|
||||
md.setMedication(new Reference(med));
|
||||
mr.setMedication(new Reference(med));
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(md);
|
||||
ourLog.info(encoded);
|
||||
|
||||
int idx = encoded.indexOf("\"Medication\"");
|
||||
assertNotEquals(-1, idx);
|
||||
|
||||
idx = encoded.indexOf("\"Medication\"", idx + 1);
|
||||
assertEquals(-1, idx);
|
||||
}
|
||||
|
||||
/*
|
||||
* See #814
|
||||
*/
|
||||
@Test
|
||||
public void testDuplicateContainedResourcesNotOutputtedTwiceWithManualIdsAndManualAddition() {
|
||||
MedicationDispense md = new MedicationDispense();
|
||||
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
mr.setId("#MR");
|
||||
md.addAuthorizingPrescription().setResource(mr);
|
||||
|
||||
Medication med = new Medication();
|
||||
med.setId("#MED");
|
||||
|
||||
Reference medRef = new Reference();
|
||||
medRef.setReference("#MED");
|
||||
md.setMedication(medRef);
|
||||
mr.setMedication(medRef);
|
||||
|
||||
md.getContained().add(mr);
|
||||
md.getContained().add(med);
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(md);
|
||||
ourLog.info(encoded);
|
||||
|
||||
int idx = encoded.indexOf("\"Medication\"");
|
||||
assertNotEquals(-1, idx);
|
||||
|
||||
idx = encoded.indexOf("\"Medication\"", idx + 1);
|
||||
assertEquals(-1, idx);
|
||||
assertEquals("HAPI-2363: This parser does not support encoding non-resource values",
|
||||
assertThrows(InternalErrorException.class, ()->ourCtx.newRDFParser().encodeToString(name)).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeAndParseUnicodeCharacterInNarrative() {
|
||||
Patient p = new Patient();
|
||||
p.getText().getDiv().setValueAsString("<div>Copy © 1999</div>");
|
||||
String encoded = ourCtx.newRDFParser().encodeResourceToString(p);
|
||||
ourLog.info(encoded);
|
||||
public void testEncodeToString_BackboneElement() {
|
||||
Patient.PatientCommunicationComponent communication = new Patient().addCommunication();
|
||||
communication.setPreferred(true);
|
||||
communication.getLanguage().setText("English");
|
||||
|
||||
p = (Patient) ourCtx.newRDFParser().parseResource(encoded);
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">Copy © 1999</div>", p.getText().getDivAsString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeResourceWithMixedManualAndAutomaticContainedResourcesLocalFirst() {
|
||||
Observation obs = new Observation();
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.setId("#1");
|
||||
pt.addName().setFamily("FAM");
|
||||
obs.getSubject().setReference("#1");
|
||||
obs.getContained().add(pt);
|
||||
|
||||
Encounter enc = new Encounter();
|
||||
enc.setStatus(Encounter.EncounterStatus.ARRIVED);
|
||||
obs.getEncounter().setResource(enc);
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(obs);
|
||||
ourLog.info(encoded);
|
||||
|
||||
obs = ourCtx.newRDFParser().parseResource(Observation.class, encoded);
|
||||
assertEquals("#1", obs.getContained().get(0).getId());
|
||||
assertEquals("#2", obs.getContained().get(1).getId());
|
||||
|
||||
pt = (Patient) obs.getSubject().getResource();
|
||||
assertEquals("FAM", pt.getNameFirstRep().getFamily());
|
||||
|
||||
enc = (Encounter) obs.getEncounter().getResource();
|
||||
assertEquals(Encounter.EncounterStatus.ARRIVED, enc.getStatus());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeResourceWithMixedManualAndAutomaticContainedResourcesLocalLast() {
|
||||
Observation obs = new Observation();
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().setFamily("FAM");
|
||||
obs.getSubject().setResource(pt);
|
||||
|
||||
Encounter enc = new Encounter();
|
||||
enc.setId("#1");
|
||||
enc.setStatus(Encounter.EncounterStatus.ARRIVED);
|
||||
obs.getEncounter().setReference("#1");
|
||||
obs.getContained().add(enc);
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(obs);
|
||||
ourLog.info(encoded);
|
||||
|
||||
obs = ourCtx.newRDFParser().parseResource(Observation.class, encoded);
|
||||
assertEquals("#1", obs.getContained().get(0).getId());
|
||||
assertEquals("#2", obs.getContained().get(1).getId());
|
||||
|
||||
pt = (Patient) obs.getSubject().getResource();
|
||||
assertEquals("FAM", pt.getNameFirstRep().getFamily());
|
||||
|
||||
enc = (Encounter) obs.getEncounter().getResource();
|
||||
assertEquals(Encounter.EncounterStatus.ARRIVED, enc.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeResourceWithMixedManualAndAutomaticContainedResourcesLocalLast2() {
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
Practitioner pract = new Practitioner().setActive(true);
|
||||
mr.getRequester().setResource(pract);
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(mr);
|
||||
ourLog.info(encoded);
|
||||
mr = ourCtx.newRDFParser().parseResource(MedicationRequest.class, encoded);
|
||||
|
||||
mr.setMedication(new Reference(new Medication().setStatus(Medication.MedicationStatus.ACTIVE)));
|
||||
encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(mr);
|
||||
ourLog.info(encoded);
|
||||
mr = ourCtx.newRDFParser().parseResource(MedicationRequest.class, encoded);
|
||||
|
||||
assertEquals("#2", mr.getContained().get(0).getId());
|
||||
assertEquals("#1", mr.getContained().get(1).getId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that long JSON strings don't get broken up
|
||||
*/
|
||||
@Test
|
||||
public void testNoBreakInLongString() {
|
||||
String longString = StringUtils.leftPad("", 100000, 'A');
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily(longString);
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(p);
|
||||
|
||||
assertThat(encoded, containsString(longString));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testParseAndEncodeExtensionWithValueWithExtension() {
|
||||
String input = "{\n" +
|
||||
" \"resourceType\": \"Patient\",\n" +
|
||||
" \"extension\": [\n" +
|
||||
" {\n" +
|
||||
" \"url\": \"https://purl.org/elab/fhir/network/StructureDefinition/1/BirthWeight\",\n" +
|
||||
" \"_valueDecimal\": {\n" +
|
||||
" \"extension\": [\n" +
|
||||
" {\n" +
|
||||
" \"url\": \"http://www.hl7.org/fhir/extension-data-absent-reason.html\",\n" +
|
||||
" \"valueCoding\": {\n" +
|
||||
" \"system\": \"http://hl7.org/fhir/ValueSet/birthweight\",\n" +
|
||||
" \"code\": \"Underweight\",\n" +
|
||||
" \"userSelected\": false\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"identifier\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"https://purl.org/elab/fhir/network/StructureDefinition/1/EuroPrevallStudySubjects\",\n" +
|
||||
" \"value\": \"1\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"gender\": \"female\"\n" +
|
||||
"}";
|
||||
|
||||
IParser jsonParser = ourCtx.newRDFParser();
|
||||
IParser xmlParser = ourCtx.newXmlParser();
|
||||
jsonParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
|
||||
xmlParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
|
||||
|
||||
Patient parsed = jsonParser.parseResource(Patient.class, input);
|
||||
|
||||
ourLog.info(jsonParser.setPrettyPrint(true).encodeResourceToString(parsed));
|
||||
assertThat(xmlParser.encodeResourceToString(parsed), containsString("Underweight"));
|
||||
assertThat(jsonParser.encodeResourceToString(parsed), containsString("Underweight"));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
assertEquals("HAPI-2363: This parser does not support encoding non-resource values",
|
||||
assertThrows(InternalErrorException.class, ()->ourCtx.newRDFParser().encodeToString(communication)).getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,8 +14,10 @@ import org.hl7.fhir.r4.model.Appointment;
|
|||
import org.hl7.fhir.r4.model.AuditEvent;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Composition;
|
||||
import org.hl7.fhir.r4.model.DecimalType;
|
||||
import org.hl7.fhir.r4.model.DocumentReference;
|
||||
import org.hl7.fhir.r4.model.Extension;
|
||||
import org.hl7.fhir.r4.model.HumanName;
|
||||
import org.hl7.fhir.r4.model.MessageHeader;
|
||||
import org.hl7.fhir.r4.model.Meta;
|
||||
import org.hl7.fhir.r4.model.Narrative;
|
||||
|
@ -24,6 +26,7 @@ import org.hl7.fhir.r4.model.Organization;
|
|||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -197,6 +200,47 @@ public class XmlParserR4Test extends BaseTest {
|
|||
ourLog.info(encoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeToString_PrimitiveDataType() {
|
||||
DecimalType object = new DecimalType("123.456000");
|
||||
String expected = "123.456000";
|
||||
String actual = ourCtx.newXmlParser().encodeToString(object);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeToString_Resource() {
|
||||
Patient p = new Patient();
|
||||
p.setId("Patient/123");
|
||||
p.setActive(true);
|
||||
String expected = "<Patient xmlns=\"http://hl7.org/fhir\"><id value=\"123\"/><active value=\"true\"/></Patient>";
|
||||
String actual = ourCtx.newXmlParser().encodeToString(p);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeToString_GeneralPurposeDataType() {
|
||||
HumanName name = new HumanName();
|
||||
name.setFamily("Simpson").addGiven("Homer").addGiven("Jay");
|
||||
name.addExtension("http://foo", new StringType("bar"));
|
||||
|
||||
String expected = "<element><extension url=\"http://foo\"><valueString value=\"bar\"/></extension><family value=\"Simpson\"/><given value=\"Homer\"/><given value=\"Jay\"/></element>";
|
||||
String actual = ourCtx.newXmlParser().encodeToString(name);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeToString_BackboneElement() {
|
||||
Patient.PatientCommunicationComponent communication = new Patient().addCommunication();
|
||||
communication.setPreferred(true);
|
||||
communication.getLanguage().setText("English");
|
||||
|
||||
String expected = "<element><language><text value=\"English\"/></language><preferred value=\"true\"/></element>";
|
||||
String actual = ourCtx.newXmlParser().encodeToString(communication);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensure that a contained bundle doesn't cause a crash
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue