Terser cloneInto doesn't work for contained resources (#4467)

* Add fix

* Add docs
This commit is contained in:
James Agnew 2023-01-26 09:55:19 -05:00 committed by GitHub
parent 69f64269cf
commit 8c287f0269
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 5 deletions

View File

@ -197,7 +197,8 @@ public class FhirTerser {
for (BaseRuntimeChildDefinition nextChild : children)
for (IBase nextValue : nextChild.getAccessor().getValues(theSource)) {
String elementName = nextChild.getChildNameByDatatype(nextValue.getClass());
Class<? extends IBase> valueType = nextValue.getClass();
String elementName = nextChild.getChildNameByDatatype(valueType);
BaseRuntimeChildDefinition targetChild = targetDef.getChildByName(elementName);
if (targetChild == null) {
if (theIgnoreMissingFields) {
@ -206,10 +207,24 @@ public class FhirTerser {
throw new DataFormatException(Msg.code(1789) + "Type " + theTarget.getClass().getName() + " does not have a child with name " + elementName);
}
BaseRuntimeElementDefinition<?> element = myContext.getElementDefinition(nextValue.getClass());
BaseRuntimeElementDefinition<?> element = myContext.getElementDefinition(valueType);
Object instanceConstructorArg = targetChild.getInstanceConstructorArguments();
IBase target;
if (instanceConstructorArg != null) {
if (element == null && BaseContainedDt.class.isAssignableFrom(valueType)) {
/*
* This is a hack for DSTU2 - The way we did contained resources in
* the DSTU2 model was weird, since the element isn't actually a FHIR type.
* This is fixed in DSTU3+ so this hack only applies there.
*/
BaseContainedDt containedTarget = (BaseContainedDt) ReflectionUtil.newInstance(valueType);
BaseContainedDt containedSource = (BaseContainedDt) nextValue;
for (IResource next : containedSource.getContainedResources()) {
List containedResources = containedTarget.getContainedResources();
containedResources.add(next);
}
targetChild.getMutator().addValue(theTarget, containedTarget);
continue;
} else if (instanceConstructorArg != null) {
target = element.newInstance(instanceConstructorArg);
} else {
target = element.newInstance();

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 4467
title: "The FhirTerser#clone method failed to clone resources when contained resources were
present in the source resource. This has been fixed."

View File

@ -19,10 +19,13 @@ import ca.uhn.fhir.parser.DataFormatException;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@ -30,6 +33,7 @@ import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
@ -41,7 +45,8 @@ import static org.mockito.Mockito.when;
public class FhirTerserDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2();
private static FhirContext ourCtx = FhirContext.forDstu2Cached();
private static final Logger ourLog = LoggerFactory.getLogger(FhirTerserDstu2Test.class);
@Test
public void testCloneIntoComposite() {
@ -54,6 +59,27 @@ public class FhirTerserDstu2Test {
assertEquals("CODE", target.getCode());
}
@Test
public void testCloneResource() {
Organization org = new Organization();
org.setName("Contained Org Name");
Patient patient = new Patient();
patient.setActive(true);
patient.getManagingOrganization().setResource(org);
// Re-encode
String string = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info("Encoded: {}", string);
patient = ourCtx.newJsonParser().parseResource(Patient.class, string);
Patient clonedPatient = ourCtx.newTerser().clone(patient);
assertEquals(true, clonedPatient.getActive().booleanValue());
string = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(clonedPatient);
ourLog.info("Encoded: {}", string);
assertThat(string, containsString("\"contained\""));
}
@Test
public void testCloneIntoCompositeMismatchedFields() {
QuantityDt source = new QuantityDt();