diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeChildDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeChildDefinition.java index 729e9a70731..fb5be19b54b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeChildDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeChildDefinition.java @@ -89,6 +89,15 @@ public abstract class BaseRuntimeChildDefinition { void addValue(IBase theTarget, IBase theValue); void setValue(IBase theTarget, IBase theValue); + + /** + * Remove an item from a list of values + * @param theTarget field to remove the item from (e.g. patient.name) + * @param theIndex the index of the item to be removed (e.g. 1 for patient.name[1]) + */ + default void remove(IBase theTarget, int theIndex) { + // implemented in subclasses + } } BaseRuntimeElementDefinition findResourceReferenceDefinition(Map, BaseRuntimeElementDefinition> theClassToElementDefinitions) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java index 2ea35519c6e..19cf6807143 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java @@ -177,6 +177,18 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil public void setValue(IBase theTarget, IBase theValue) { addValue(theTarget, theValue, true); } + + @Override + public void remove(IBase theTarget, int theIndex) { + List existingList = (List) getFieldValue(theTarget, myField); + if (existingList == null) { + throw new IndexOutOfBoundsException(Msg.code(2143) + "Can not remove element at index " + theIndex + " from list - List is null"); + } + if (theIndex >= existingList.size()) { + throw new IndexOutOfBoundsException(Msg.code(2144) + "Can not remove element at index " + theIndex + " from list - List size is " + existingList.size()); + } + existingList.remove(theIndex); + } } private final class FieldPlainAccessor implements IAccessor { @@ -205,6 +217,11 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil public void setValue(IBase theTarget, IBase theValue) { addValue(theTarget, theValue); } + + @Override + public void remove(IBase theTarget, int theIndex) { + throw new UnsupportedOperationException(Msg.code(2142) + "Remove by index can only be called on a list-valued field. '" + myField.getName() + "' is a single-valued field."); + } } private static void setFieldValue(IBase theTarget, Object theValue, Field theField) { diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/context/BaseRuntimeElementDefinitionTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/context/BaseRuntimeElementDefinitionTest.java index 97f2d8da300..67164052ad4 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/context/BaseRuntimeElementDefinitionTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/context/BaseRuntimeElementDefinitionTest.java @@ -1,17 +1,21 @@ package ca.uhn.fhir.context; import ca.uhn.fhir.i18n.Msg; +import org.hl7.fhir.r4.model.Enumerations; +import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class BaseRuntimeElementDefinitionTest { + private static FhirContext ourFhirContext = FhirContext.forR4Cached(); + @Test public void testNewInstance_InvalidArgumentType() { - FhirContext ctx = FhirContext.forR4(); - BaseRuntimeElementDefinition def = ctx.getElementDefinition("string"); + BaseRuntimeElementDefinition def = ourFhirContext.getElementDefinition("string"); try { def.newInstance(123); @@ -21,4 +25,36 @@ public class BaseRuntimeElementDefinitionTest { } } + @Test + void mutator_remove() { + Patient patient = new Patient(); + patient.addName().setFamily("A1"); + patient.addName().setFamily("A2"); + + assertEquals(2, patient.getName().size()); + assertEquals("A1", patient.getName().get(0).getFamily()); + RuntimeResourceDefinition def = ourFhirContext.getResourceDefinition(patient); + BaseRuntimeChildDefinition child = def.getChildByName("name"); + BaseRuntimeChildDefinition.IMutator mutator = child.getMutator(); + + mutator.remove(patient, 0); + assertEquals(1, patient.getName().size()); + assertEquals("A2", patient.getName().get(0).getFamily()); + } + + @Test + void mutator_remov_nonList() { + Patient patient = new Patient(); + patient.setGender(Enumerations.AdministrativeGender.MALE); + + RuntimeResourceDefinition def = ourFhirContext.getResourceDefinition(patient); + BaseRuntimeChildDefinition child = def.getChildByName("gender"); + BaseRuntimeChildDefinition.IMutator mutator = child.getMutator(); + try { + mutator.remove(patient, 0); + fail(); + } catch (UnsupportedOperationException e) { + assertEquals("HAPI-2142: Remove by index can only be called on a list-valued field. 'gender' is a single-valued field.", e.getMessage()); + } + } }