diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TerserUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TerserUtil.java index a4ad7319484..2cdee809b8a 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TerserUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TerserUtil.java @@ -47,7 +47,7 @@ public final class TerserUtil { public static final String FIELD_NAME_IDENTIFIER = "identifier"; - private static final String EQUALS_DEEP="equalsDeep"; + private static final String EQUALS_DEEP = "equalsDeep"; public static final Collection IDS_AND_META_EXCLUDES = Collections.unmodifiableSet(Stream.of("id", "identifier", "meta").collect(Collectors.toSet())); @@ -177,10 +177,10 @@ public final class TerserUtil { }); } - private static Method getMethod(IBase item, String methodName){ + private static Method getMethod(IBase theBase, String theMethodName) { Method method = null; - for (Method m : item.getClass().getDeclaredMethods()) { - if (m.getName().equals(methodName)) { + for (Method m : theBase.getClass().getDeclaredMethods()) { + if (m.getName().equals(theMethodName)) { method = m; break; } @@ -188,18 +188,31 @@ public final class TerserUtil { return method; } - public static boolean equals(IBase theItem1, IBase theItem2){ - final Method m = getMethod(theItem1, EQUALS_DEEP); + /** + * Checks if two items are equal via {@link #EQUALS_DEEP} method + * + * @param theItem1 First item to compare + * @param theItem2 Second item to compare + * @return Returns true if they are equal and false otherwise + */ + public static boolean equals(IBase theItem1, IBase theItem2) { + if (theItem1 == null) { + return theItem2 == null; + } + final Method m = getMethod(theItem1, EQUALS_DEEP); + if (m == null) { + throw new IllegalArgumentException(String.format("Instance %s do not provide %s method", theItem1, EQUALS_DEEP)); + } return equals(theItem1, theItem2, m); } - public static boolean equals(IBase theItem1, IBase theItem2, Method m) { + private static boolean equals(IBase theItem1, IBase theItem2, Method m) { if (m != null) { try { return (Boolean) m.invoke(theItem1, theItem2); } catch (Exception e) { - throw new RuntimeException("Unable to compare equality via equalsDeep", e); + throw new RuntimeException(String.format("Unable to compare equality via %s", EQUALS_DEEP), e); } } return theItem1.equals(theItem2); @@ -314,10 +327,20 @@ public final class TerserUtil { */ public static void setField(FhirContext theFhirContext, FhirTerser theTerser, String theFieldName, IBaseResource theResource, IBase... theValues) { BaseRuntimeChildDefinition childDefinition = getBaseRuntimeChildDefinition(theFhirContext, theFieldName, theResource); - List theFromFieldValues = childDefinition.getAccessor().getValues(theResource); + if (theFromFieldValues.isEmpty()) { + for (IBase value : theValues) { + try { + childDefinition.getMutator().addValue(theResource, value); + } catch (UnsupportedOperationException e) { + ourLog.warn("Resource {} does not support multiple values, but an attempt to set {} was made. Setting the first item only", theResource, theValues); + childDefinition.getMutator().setValue(theResource, value); + break; + } + } + return; + } List theToFieldValues = Arrays.asList(theValues); - mergeFields(theTerser, theResource, childDefinition, theFromFieldValues, theToFieldValues); } @@ -505,6 +528,9 @@ public final class TerserUtil { */ public static T newElement(FhirContext theFhirContext, String theElementType, Object theConstructorParam) { BaseRuntimeElementDefinition def = theFhirContext.getElementDefinition(theElementType); + if (def == null) { + throw new IllegalArgumentException(String.format("Unable to find element type definition for %s", theElementType)); + } return (T) def.newInstance(theConstructorParam); } diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/TerserUtilTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/TerserUtilTest.java index 1ab062bd273..66c7cb40d4c 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/TerserUtilTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/TerserUtilTest.java @@ -2,6 +2,8 @@ package ca.uhn.fhir.util; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.RuntimeResourceDefinition; +import org.checkerframework.checker.units.qual.A; +import org.hl7.fhir.r4.model.Address; import org.hl7.fhir.r4.model.DateTimeType; import org.hl7.fhir.r4.model.DateType; import org.hl7.fhir.r4.model.Enumerations; @@ -9,16 +11,14 @@ import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.HumanName; import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.PrimitiveType; import org.junit.jupiter.api.Test; import java.util.GregorianCalendar; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; class TerserUtilTest { @@ -243,7 +243,7 @@ class TerserUtilTest { @Test - void testEqualsFunction(){ + void testEqualsFunction() { Patient p1 = new Patient(); Patient p2 = new Patient(); @@ -254,7 +254,7 @@ class TerserUtilTest { } @Test - void testEqualsFunctionNotEqual(){ + void testEqualsFunctionNotEqual() { Patient p1 = new Patient(); Patient p2 = new Patient(); @@ -263,4 +263,103 @@ class TerserUtilTest { assertFalse(TerserUtil.equals(p1, p2)); } + + @Test + void testHasValues() { + Patient p1 = new Patient(); + p1.addName().setFamily("Doe"); + + assertTrue(TerserUtil.hasValues(ourFhirContext, p1, "name")); + assertFalse(TerserUtil.hasValues(ourFhirContext, p1, "address")); + } + + @Test + void testGetValues() { + Patient p1 = new Patient(); + p1.addName().setFamily("Doe"); + + assertEquals("Doe", ((HumanName) TerserUtil.getValue(ourFhirContext, p1, "name")).getFamily()); + assertFalse(TerserUtil.getValues(ourFhirContext, p1, "name").isEmpty()); + assertNull(TerserUtil.getValues(ourFhirContext, p1, "whoaIsThatReal")); + assertNull(TerserUtil.getValue(ourFhirContext, p1, "whoaIsThatReal")); + } + + @Test + public void testReplaceFields() { + Patient p1 = new Patient(); + p1.addName().setFamily("Doe"); + Patient p2 = new Patient(); + p2.addName().setFamily("Smith"); + + TerserUtil.replaceField(ourFhirContext, "name", p1, p2); + + assertEquals(1, p2.getName().size()); + assertEquals("Doe", p2.getName().get(0).getFamily()); + } + + @Test + public void testClearFields() { + Patient p1 = new Patient(); + p1.addName().setFamily("Doe"); + + TerserUtil.clearField(ourFhirContext, "name", p1); + + assertEquals(0, p1.getName().size()); + } + + @Test + public void testSetField() { + Patient p1 = new Patient(); + + Address address = new Address(); + address.setCity("CITY"); + + TerserUtil.setField(ourFhirContext, "address", p1, address); + + assertEquals(1, p1.getAddress().size()); + assertEquals("CITY", p1.getAddress().get(0).getCity()); + } + + @Test + public void testSetFieldByFhirPath() { + Patient p1 = new Patient(); + + Address address = new Address(); + address.setCity("CITY"); + + TerserUtil.setFieldByFhirPath(ourFhirContext, "address", p1, address); + + assertEquals(1, p1.getAddress().size()); + assertEquals("CITY", p1.getAddress().get(0).getCity()); + } + + @Test + public void testClone() { + Patient p1 = new Patient(); + p1.addName().setFamily("Doe").addGiven("Joe"); + + Patient p2 = TerserUtil.clone(ourFhirContext, p1); + + assertEquals(p1.getName().get(0).getNameAsSingleString(), p2.getName().get(0).getNameAsSingleString()); + assertTrue(p1.equalsDeep(p2)); + } + + @Test + public void testNewElement() { + assertNotNull(TerserUtil.newElement(ourFhirContext, "string")); + assertEquals(1, ((PrimitiveType) TerserUtil.newElement(ourFhirContext, "integer", "1")).getValue()); + + assertNotNull(TerserUtil.newElement(ourFhirContext, "string")); + assertNull(((PrimitiveType) TerserUtil.newElement(ourFhirContext, "integer")).getValue()); + + assertNotNull(TerserUtil.newElement(ourFhirContext, "string", null)); + assertNull(((PrimitiveType) TerserUtil.newElement(ourFhirContext, "integer", null)).getValue()); + } + + @Test + public void testNewResource() { + assertNotNull(TerserUtil.newResource(ourFhirContext, "Patient")); + assertNotNull(TerserUtil.newResource(ourFhirContext, "Patient", null)); + } + }