Merge pull request #2668 from hapifhir/2667_terserutil_merge_empty_fields

Fixed primitive field merging
This commit is contained in:
Nick Goupinets 2021-05-26 09:54:38 -04:00 committed by GitHub
commit cc734613a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 11 deletions

View File

@ -28,9 +28,12 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Triple; import org.apache.commons.lang3.tuple.Triple;
import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseEnumeration;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.slf4j.Logger; import org.slf4j.Logger;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -283,9 +286,10 @@ public final class TerserUtil {
*/ */
public static void replaceFieldsByPredicate(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo, Predicate<Triple<BaseRuntimeChildDefinition, IBase, IBase>> thePredicate) { public static void replaceFieldsByPredicate(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo, Predicate<Triple<BaseRuntimeChildDefinition, IBase, IBase>> thePredicate) {
RuntimeResourceDefinition definition = theFhirContext.getResourceDefinition(theFrom); RuntimeResourceDefinition definition = theFhirContext.getResourceDefinition(theFrom);
FhirTerser terser = theFhirContext.newTerser();
for (BaseRuntimeChildDefinition childDefinition : definition.getChildrenAndExtension()) { for (BaseRuntimeChildDefinition childDefinition : definition.getChildrenAndExtension()) {
if (thePredicate.test(Triple.of(childDefinition, theFrom, theTo))) { if (thePredicate.test(Triple.of(childDefinition, theFrom, theTo))) {
replaceField(theFrom, theTo, childDefinition); replaceField(terser, theFrom, theTo, childDefinition);
} }
} }
} }
@ -313,7 +317,7 @@ public final class TerserUtil {
public static void replaceField(FhirContext theFhirContext, String theFieldName, IBaseResource theFrom, IBaseResource theTo) { public static void replaceField(FhirContext theFhirContext, String theFieldName, IBaseResource theFrom, IBaseResource theTo) {
RuntimeResourceDefinition definition = theFhirContext.getResourceDefinition(theFrom); RuntimeResourceDefinition definition = theFhirContext.getResourceDefinition(theFrom);
Validate.notNull(definition); Validate.notNull(definition);
replaceField(theFrom, theTo, theFhirContext.getResourceDefinition(theFrom).getChildByName(theFieldName)); replaceField(theFhirContext.newTerser(), theFrom, theTo, theFhirContext.getResourceDefinition(theFrom).getChildByName(theFieldName));
} }
/** /**
@ -325,7 +329,7 @@ public final class TerserUtil {
*/ */
public static void clearField(FhirContext theFhirContext, String theFieldName, IBaseResource theResource) { public static void clearField(FhirContext theFhirContext, String theFieldName, IBaseResource theResource) {
BaseRuntimeChildDefinition childDefinition = getBaseRuntimeChildDefinition(theFhirContext, theFieldName, theResource); BaseRuntimeChildDefinition childDefinition = getBaseRuntimeChildDefinition(theFhirContext, theFieldName, theResource);
childDefinition.getAccessor().getValues(theResource).clear(); clear(childDefinition.getAccessor().getValues(theResource));
} }
/** /**
@ -339,7 +343,7 @@ public final class TerserUtil {
BaseRuntimeElementDefinition definition = theFhirContext.getElementDefinition(theBase.getClass()); BaseRuntimeElementDefinition definition = theFhirContext.getElementDefinition(theBase.getClass());
BaseRuntimeChildDefinition childDefinition = definition.getChildByName(theFieldName); BaseRuntimeChildDefinition childDefinition = definition.getChildByName(theFieldName);
Validate.notNull(childDefinition); Validate.notNull(childDefinition);
childDefinition.getAccessor().getValues(theBase).clear(); clear(childDefinition.getAccessor().getValues(theBase));
} }
/** /**
@ -441,11 +445,12 @@ public final class TerserUtil {
return values.get(0); return values.get(0);
} }
private static void replaceField(IBaseResource theFrom, IBaseResource theTo, BaseRuntimeChildDefinition childDefinition) { private static void replaceField(FhirTerser theTerser, IBaseResource theFrom, IBaseResource theTo, BaseRuntimeChildDefinition childDefinition) {
childDefinition.getAccessor().getFirstValueOrNull(theFrom).ifPresent(v -> { List<IBase> fromValues = childDefinition.getAccessor().getValues(theFrom);
childDefinition.getMutator().setValue(theTo, v); List<IBase> toValues = childDefinition.getAccessor().getValues(theTo);
} clear(toValues);
);
mergeFields(theTerser, theTo, childDefinition, fromValues, toValues);
} }
/** /**
@ -532,13 +537,24 @@ public final class TerserUtil {
} }
IBase newFieldValue = childDefinition.getChildByName(childDefinition.getElementName()).newInstance(); IBase newFieldValue = childDefinition.getChildByName(childDefinition.getElementName()).newInstance();
theTerser.cloneInto(theFromFieldValue, newFieldValue, true); if (theFromFieldValue instanceof IPrimitiveType) {
try {
Method copyMethod = getMethod(theFromFieldValue, "copy");
if (copyMethod != null) {
newFieldValue = (IBase) copyMethod.invoke(theFromFieldValue, new Object[]{});
}
} catch (Throwable t) {
((IPrimitiveType) newFieldValue).setValueAsString(((IPrimitiveType) theFromFieldValue).getValueAsString());
}
} else {
theTerser.cloneInto(theFromFieldValue, newFieldValue, true);
}
try { try {
theToFieldValues.add(newFieldValue); theToFieldValues.add(newFieldValue);
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
childDefinition.getMutator().setValue(theTo, newFieldValue); childDefinition.getMutator().setValue(theTo, newFieldValue);
break; theToFieldValues = childDefinition.getAccessor().getValues(theTo);
} }
} }
} }
@ -615,4 +631,16 @@ public final class TerserUtil {
return (T) def.newInstance(theConstructorParam); return (T) def.newInstance(theConstructorParam);
} }
private static void clear(List<IBase> values) {
if (values == null) {
return;
}
try {
values.clear();
} catch (Throwable t) {
ourLog.debug("Unable to clear values " + String.valueOf(values), t);
}
}
} }

View File

@ -103,6 +103,38 @@ class TerserUtilTest {
assertEquals(p1.getName().get(0).getNameAsSingleString(), p2.getName().get(0).getNameAsSingleString()); assertEquals(p1.getName().get(0).getNameAsSingleString(), p2.getName().get(0).getNameAsSingleString());
} }
@Test
void testCloneIdentifiers() {
Patient p1 = new Patient();
p1.addIdentifier(new Identifier().setSystem("uri:mi").setValue("123456"));
p1.addIdentifier(new Identifier().setSystem("uri:mdi").setValue("287351247K"));
p1.addIdentifier(new Identifier().setSystem("uri:cdns").setValue("654841918"));
p1.addIdentifier(new Identifier().setSystem("uri:ssn").setValue("855191882"));
p1.addName().setFamily("Sat").addGiven("Joe");
Patient p2 = new Patient();
TerserUtil.mergeField(ourFhirContext, ourFhirContext.newTerser(), "identifier", p1, p2);
assertEquals(4, p2.getIdentifier().size());
assertTrue(p2.getName().isEmpty());
}
@Test
void testReplaceIdentifiers() {
Patient p1 = new Patient();
p1.addIdentifier(new Identifier().setSystem("uri:mi").setValue("123456"));
p1.addIdentifier(new Identifier().setSystem("uri:mdi").setValue("287351247K"));
p1.addIdentifier(new Identifier().setSystem("uri:cdns").setValue("654841918"));
p1.addIdentifier(new Identifier().setSystem("uri:ssn").setValue("855191882"));
p1.addName().setFamily("Sat").addGiven("Joe");
Patient p2 = new Patient();
TerserUtil.replaceField(ourFhirContext, "identifier", p1, p2);
assertEquals(4, p2.getIdentifier().size());
assertTrue(p2.getName().isEmpty());
}
@Test @Test
void testCloneWithNonPrimitves() { void testCloneWithNonPrimitves() {
Patient p1 = new Patient(); Patient p1 = new Patient();
@ -314,6 +346,7 @@ class TerserUtilTest {
// expect p2 to have "Doe" and MALE after replace // expect p2 to have "Doe" and MALE after replace
assertEquals(1, p2.getName().size()); assertEquals(1, p2.getName().size());
assertEquals("Doe", p2.getName().get(0).getFamily()); assertEquals("Doe", p2.getName().get(0).getFamily());
assertEquals(Enumerations.AdministrativeGender.MALE, p2.getGender()); assertEquals(Enumerations.AdministrativeGender.MALE, p2.getGender());
assertEquals(dob, p2.getBirthDate()); assertEquals(dob, p2.getBirthDate());
} }