From faa6052bdf00021550b697f691fbcfab1098acc5 Mon Sep 17 00:00:00 2001 From: Paul-Christian Volkmer Date: Mon, 25 Nov 2024 18:35:44 +0100 Subject: [PATCH] feat: add default implementation of reference validator This adds a generic interface for MII mappers containing a default implementation of a reference validator. --- .../mapper/mii/ConditionMapper.java | 6 +- .../ume/obdstofhir/mapper/mii/Mapper.java | 30 +++++++++ .../mapper/mii/StrahlentherapieMapper.java | 10 +-- ...scheTherapieMedicationStatementMapper.java | 17 ++--- .../SystemischeTherapieProcedureMapper.java | 11 ++-- .../mapper/mii/ConditionMapperTest.java | 59 +++++++++++++++++ .../mii/StrahlentherapieMapperTest.java | 62 +++++++++++++++++ ...TherapieMedicationStatementMapperTest.java | 66 +++++++++++++++++++ ...ystemischeTherapieProcedureMapperTest.java | 62 +++++++++++++++++ 9 files changed, 296 insertions(+), 27 deletions(-) create mode 100644 src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/Mapper.java diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ConditionMapper.java b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ConditionMapper.java index 6be632f4..edf622d4 100644 --- a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ConditionMapper.java +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ConditionMapper.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.regex.Pattern; import org.hl7.fhir.r4.model.*; +import org.hl7.fhir.r4.model.Enumerations.ResourceType; import org.miracum.streams.ume.obdstofhir.FhirProperties; import org.miracum.streams.ume.obdstofhir.mapper.ObdsToFhirMapper; import org.slf4j.Logger; @@ -14,7 +15,8 @@ import org.springframework.util.StringUtils; @Service -public class ConditionMapper extends ObdsToFhirMapper { +public class ConditionMapper extends ObdsToFhirMapper + implements Mapper { private static final Logger LOG = LoggerFactory.getLogger(ConditionMapper.class); private static final Pattern icdVersionPattern = @@ -28,6 +30,8 @@ public ConditionMapper(FhirProperties fhirProperties) { public Condition map(OBDS.MengePatient.Patient.MengeMeldung.Meldung meldung, Reference patient) { var condition = new Condition(); + verifyReference(patient, ResourceType.PATIENT); + if (meldung.getDiagnose().getDiagnosesicherung() != null) { Coding verStatus = new Coding(fhirProperties.getSystems().getConditionVerStatus(), "confirmed", ""); diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/Mapper.java b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/Mapper.java new file mode 100644 index 00000000..7ef38598 --- /dev/null +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/Mapper.java @@ -0,0 +1,30 @@ +package org.miracum.streams.ume.obdstofhir.mapper.mii; + +import java.util.Objects; +import org.apache.commons.lang3.Validate; +import org.hl7.fhir.r4.model.Enumerations.ResourceType; +import org.hl7.fhir.r4.model.Reference; + +public interface Mapper { + + /** + * Default implementation of reference validation. This does not check the existance of the + * referenced resource! + * + * @param reference The reference to be validated + * @param resourceType The required resource type of the reference + * @return Will return `true` if reference is usable + * @throws NullPointerException if reference is null + * @throws IllegalArgumentException if reference is not of required reesource type. + */ + default boolean verifyReference(Reference reference, ResourceType resourceType) + throws NullPointerException, IllegalArgumentException { + Objects.requireNonNull( + reference, String.format("Reference to %s must not be null", resourceType.toString())); + Validate.isTrue( + Objects.equals(reference.getReferenceElement().getResourceType(), resourceType.toCode()), + String.format("The reference should point to a %s resource", resourceType.toString())); + + return true; + } +} diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapper.java b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapper.java index c296d6cc..85c2545d 100644 --- a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapper.java +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapper.java @@ -18,7 +18,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class StrahlentherapieMapper extends ObdsToFhirMapper { +public class StrahlentherapieMapper extends ObdsToFhirMapper implements Mapper { private static final Logger LOG = LoggerFactory.getLogger(StrahlentherapieMapper.class); public StrahlentherapieMapper(FhirProperties fhirProperties) { @@ -27,13 +27,9 @@ public StrahlentherapieMapper(FhirProperties fhirProperties) { public Procedure map(STTyp st, Reference subject) { Objects.requireNonNull(st); - Objects.requireNonNull(subject); - Validate.notBlank(st.getSTID(), "Required ST_ID is unset"); - Validate.isTrue( - Objects.equals( - subject.getReferenceElement().getResourceType(), ResourceType.PATIENT.toCode()), - "The subject reference should point to a Patient resource"); + + verifyReference(subject, ResourceType.PATIENT); var procedure = new Procedure(); procedure.getMeta().addProfile(fhirProperties.getProfiles().getMiiPrOnkoStrahlentherapie()); diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieMedicationStatementMapper.java b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieMedicationStatementMapper.java index a5950d03..6520a310 100644 --- a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieMedicationStatementMapper.java +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieMedicationStatementMapper.java @@ -23,7 +23,8 @@ import org.springframework.util.StringUtils; @Service -public class SystemischeTherapieMedicationStatementMapper extends ObdsToFhirMapper { +public class SystemischeTherapieMedicationStatementMapper extends ObdsToFhirMapper + implements Mapper { private static final Logger LOG = LoggerFactory.getLogger(SystemischeTherapieProcedureMapper.class); @@ -34,18 +35,10 @@ public SystemischeTherapieMedicationStatementMapper(FhirProperties fhirPropertie public Bundle map(SYSTTyp syst, Reference patient, Reference procedure) { Objects.requireNonNull(syst, "Systemtherapie must not be null"); - Objects.requireNonNull(patient, "Reference to Patient must not be null"); - Objects.requireNonNull(procedure, "Reference to Procedure must not be null"); - Validate.notBlank(syst.getSYSTID(), "Required SYST_ID is unset"); - Validate.isTrue( - Objects.equals( - patient.getReferenceElement().getResourceType(), ResourceType.PATIENT.toCode()), - "The subject reference should point to a Patient resource"); - Validate.isTrue( - Objects.equals( - procedure.getReferenceElement().getResourceType(), ResourceType.PROCEDURE.toCode()), - "The subject reference should point to a Procedure resource"); + + verifyReference(patient, ResourceType.PATIENT); + verifyReference(procedure, ResourceType.PROCEDURE); var bundle = new Bundle(); bundle.setType(Bundle.BundleType.TRANSACTION); diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieProcedureMapper.java b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieProcedureMapper.java index 2bfade61..6151aad0 100644 --- a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieProcedureMapper.java +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieProcedureMapper.java @@ -19,7 +19,8 @@ import org.springframework.stereotype.Service; @Service -public class SystemischeTherapieProcedureMapper extends ObdsToFhirMapper { +public class SystemischeTherapieProcedureMapper extends ObdsToFhirMapper + implements Mapper { private static final Logger LOG = LoggerFactory.getLogger(SystemischeTherapieProcedureMapper.class); @@ -30,13 +31,9 @@ public SystemischeTherapieProcedureMapper(FhirProperties fhirProperties) { public Procedure map(SYSTTyp syst, Reference subject) { Objects.requireNonNull(syst, "Systemtherapie must not be null"); - Objects.requireNonNull(subject, "Reference must not be null"); - Validate.notBlank(syst.getSYSTID(), "Required SYST_ID is unset"); - Validate.isTrue( - Objects.equals( - subject.getReferenceElement().getResourceType(), ResourceType.PATIENT.toCode()), - "The subject reference should point to a Patient resource"); + + verifyReference(subject, ResourceType.PATIENT); var procedure = new Procedure(); procedure.getMeta().addProfile(fhirProperties.getProfiles().getMiiPrOnkoSystemischeTherapie()); diff --git a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ConditionMapperTest.java b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ConditionMapperTest.java index f00307de..9cbb4921 100644 --- a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ConditionMapperTest.java +++ b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ConditionMapperTest.java @@ -1,6 +1,7 @@ package org.miracum.streams.ume.obdstofhir.mapper.mii; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import ca.uhn.fhir.context.FhirContext; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -14,6 +15,7 @@ import org.approvaltests.Approvals; import org.hl7.fhir.r4.model.Reference; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.miracum.streams.ume.obdstofhir.FhirProperties; @@ -64,4 +66,61 @@ void map_withGivenObds_shouldCreateValidConditionResource(String sourceFile) thr Approvals.verify( fhirJson, Approvals.NAMES.withParameters(sourceFile).forFile().withExtension(".fhir.json")); } + + @Test + void shouldNotVerifyNullReferences() throws Exception { + final var resource = this.getClass().getClassLoader().getResource("obds3/Testpatient_1.xml"); + assertThat(resource).isNotNull(); + + final var xmlMapper = + XmlMapper.builder() + .defaultUseWrapper(false) + .addModule(new JakartaXmlBindAnnotationModule()) + .addModule(new Jdk8Module()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + final var obds = xmlMapper.readValue(resource.openStream(), OBDS.class); + + var obdsPatient = obds.getMengePatient().getPatient().getFirst(); + + var wrongPatient = (Reference) null; + var conMeldung = + obdsPatient.getMengeMeldung().getMeldung().stream() + .filter(m -> m.getDiagnose() != null) + .findFirst() + .get(); + + var ex = assertThrows(NullPointerException.class, () -> sut.map(conMeldung, wrongPatient)); + assertThat(ex).hasMessage("Reference to PATIENT must not be null"); + } + + @Test + void shouldNotVerifyWrongReferencesType() throws Exception { + final var resource = this.getClass().getClassLoader().getResource("obds3/Testpatient_1.xml"); + assertThat(resource).isNotNull(); + + final var xmlMapper = + XmlMapper.builder() + .defaultUseWrapper(false) + .addModule(new JakartaXmlBindAnnotationModule()) + .addModule(new Jdk8Module()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + final var obds = xmlMapper.readValue(resource.openStream(), OBDS.class); + + var obdsPatient = obds.getMengePatient().getPatient().getFirst(); + + var wrongPatient = new Reference("Procedure/any"); + var conMeldung = + obdsPatient.getMengeMeldung().getMeldung().stream() + .filter(m -> m.getDiagnose() != null) + .findFirst() + .get(); + + var ex = assertThrows(IllegalArgumentException.class, () -> sut.map(conMeldung, wrongPatient)); + + assertThat(ex).hasMessage("The reference should point to a PATIENT resource"); + } } diff --git a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapperTest.java b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapperTest.java index 8f8d63cf..6dd093ac 100644 --- a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapperTest.java +++ b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapperTest.java @@ -1,6 +1,7 @@ package org.miracum.streams.ume.obdstofhir.mapper.mii; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import ca.uhn.fhir.context.FhirContext; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -12,6 +13,7 @@ import org.approvaltests.Approvals; import org.hl7.fhir.r4.model.Reference; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.miracum.streams.ume.obdstofhir.FhirProperties; @@ -60,4 +62,64 @@ void map_withGivenObds_shouldCreateValidProcedure(String sourceFile) throws IOEx Approvals.verify( fhirJson, Approvals.NAMES.withParameters(sourceFile).forFile().withExtension(".fhir.json")); } + + @Test + void shouldNotVerifyNullReferences() throws Exception { + final var resource = this.getClass().getClassLoader().getResource("obds3/Testpatient_1.xml"); + assertThat(resource).isNotNull(); + + final var xmlMapper = + XmlMapper.builder() + .defaultUseWrapper(false) + .addModule(new JakartaXmlBindAnnotationModule()) + .addModule(new Jdk8Module()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + final var obds = xmlMapper.readValue(resource.openStream(), OBDS.class); + + var obdsPatient = obds.getMengePatient().getPatient().getFirst(); + + var wrongPatient = (Reference) null; + var stMeldung = + obdsPatient.getMengeMeldung().getMeldung().stream() + .filter(m -> m.getST() != null) + .findFirst() + .get(); + + var ex = + assertThrows(NullPointerException.class, () -> sut.map(stMeldung.getST(), wrongPatient)); + assertThat(ex).hasMessage("Reference to PATIENT must not be null"); + } + + @Test + void shouldNotVerifyWrongReferencesType() throws Exception { + final var resource = this.getClass().getClassLoader().getResource("obds3/Testpatient_1.xml"); + assertThat(resource).isNotNull(); + + final var xmlMapper = + XmlMapper.builder() + .defaultUseWrapper(false) + .addModule(new JakartaXmlBindAnnotationModule()) + .addModule(new Jdk8Module()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + final var obds = xmlMapper.readValue(resource.openStream(), OBDS.class); + + var obdsPatient = obds.getMengePatient().getPatient().getFirst(); + + var wrongPatient = new Reference("Procedure/any"); + var stMeldung = + obdsPatient.getMengeMeldung().getMeldung().stream() + .filter(m -> m.getST() != null) + .findFirst() + .get(); + + var ex = + assertThrows( + IllegalArgumentException.class, () -> sut.map(stMeldung.getST(), wrongPatient)); + + assertThat(ex).hasMessage("The reference should point to a PATIENT resource"); + } } diff --git a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieMedicationStatementMapperTest.java b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieMedicationStatementMapperTest.java index 97987ce2..d82e6a30 100644 --- a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieMedicationStatementMapperTest.java +++ b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieMedicationStatementMapperTest.java @@ -1,6 +1,7 @@ package org.miracum.streams.ume.obdstofhir.mapper.mii; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import ca.uhn.fhir.context.FhirContext; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -12,6 +13,7 @@ import org.approvaltests.Approvals; import org.hl7.fhir.r4.model.Reference; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.miracum.streams.ume.obdstofhir.FhirProperties; @@ -63,4 +65,68 @@ void map_withGivenObds_shouldCreateValidMedicationStatement(String sourceFile) Approvals.verify( fhirJson, Approvals.NAMES.withParameters(sourceFile).forFile().withExtension(".fhir.json")); } + + @Test + void shouldNotVerifyNullReferences() throws Exception { + final var resource = this.getClass().getClassLoader().getResource("obds3/Testpatient_1.xml"); + assertThat(resource).isNotNull(); + + final var xmlMapper = + XmlMapper.builder() + .defaultUseWrapper(false) + .addModule(new JakartaXmlBindAnnotationModule()) + .addModule(new Jdk8Module()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + final var obds = xmlMapper.readValue(resource.openStream(), OBDS.class); + + var obdsPatient = obds.getMengePatient().getPatient().getFirst(); + + var wrongPatient = (Reference) null; + var procedure = new Reference("Procedure/any"); + var systMeldung = + obdsPatient.getMengeMeldung().getMeldung().stream() + .filter(m -> m.getSYST() != null) + .findFirst() + .get(); + + var ex = + assertThrows( + NullPointerException.class, + () -> sut.map(systMeldung.getSYST(), wrongPatient, procedure)); + assertThat(ex).hasMessage("Reference to PATIENT must not be null"); + } + + @Test + void shouldNotVerifyWrongReferencesType() throws Exception { + final var resource = this.getClass().getClassLoader().getResource("obds3/Testpatient_1.xml"); + assertThat(resource).isNotNull(); + + final var xmlMapper = + XmlMapper.builder() + .defaultUseWrapper(false) + .addModule(new JakartaXmlBindAnnotationModule()) + .addModule(new Jdk8Module()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + final var obds = xmlMapper.readValue(resource.openStream(), OBDS.class); + + var obdsPatient = obds.getMengePatient().getPatient().getFirst(); + + var wrongPatient = new Reference("Procedure/any"); + var procedure = new Reference("Procedure/any"); + var systMeldung = + obdsPatient.getMengeMeldung().getMeldung().stream() + .filter(m -> m.getSYST() != null) + .findFirst() + .get(); + + var ex = + assertThrows( + IllegalArgumentException.class, + () -> sut.map(systMeldung.getSYST(), wrongPatient, procedure)); + assertThat(ex).hasMessage("The reference should point to a PATIENT resource"); + } } diff --git a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieProcedureMapperTest.java b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieProcedureMapperTest.java index f3d9d997..77734b75 100644 --- a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieProcedureMapperTest.java +++ b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/SystemischeTherapieProcedureMapperTest.java @@ -1,6 +1,7 @@ package org.miracum.streams.ume.obdstofhir.mapper.mii; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import ca.uhn.fhir.context.FhirContext; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -12,6 +13,7 @@ import org.approvaltests.Approvals; import org.hl7.fhir.r4.model.Reference; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.miracum.streams.ume.obdstofhir.FhirProperties; @@ -60,4 +62,64 @@ void map_withGivenObds_shouldCreateValidProcedure(String sourceFile) throws IOEx Approvals.verify( fhirJson, Approvals.NAMES.withParameters(sourceFile).forFile().withExtension(".fhir.json")); } + + @Test + void shouldNotVerifyNullReferences() throws Exception { + final var resource = this.getClass().getClassLoader().getResource("obds3/Testpatient_1.xml"); + assertThat(resource).isNotNull(); + + final var xmlMapper = + XmlMapper.builder() + .defaultUseWrapper(false) + .addModule(new JakartaXmlBindAnnotationModule()) + .addModule(new Jdk8Module()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + final var obds = xmlMapper.readValue(resource.openStream(), OBDS.class); + + var obdsPatient = obds.getMengePatient().getPatient().getFirst(); + + var wrongPatient = (Reference) null; + var systMeldung = + obdsPatient.getMengeMeldung().getMeldung().stream() + .filter(m -> m.getSYST() != null) + .findFirst() + .get(); + + var ex = + assertThrows( + NullPointerException.class, () -> sut.map(systMeldung.getSYST(), wrongPatient)); + assertThat(ex).hasMessage("Reference to PATIENT must not be null"); + } + + @Test + void shouldNotVerifyWrongReferencesType() throws Exception { + final var resource = this.getClass().getClassLoader().getResource("obds3/Testpatient_1.xml"); + assertThat(resource).isNotNull(); + + final var xmlMapper = + XmlMapper.builder() + .defaultUseWrapper(false) + .addModule(new JakartaXmlBindAnnotationModule()) + .addModule(new Jdk8Module()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + final var obds = xmlMapper.readValue(resource.openStream(), OBDS.class); + + var obdsPatient = obds.getMengePatient().getPatient().getFirst(); + + var wrongPatient = new Reference("Procedure/any"); + var systMeldung = + obdsPatient.getMengeMeldung().getMeldung().stream() + .filter(m -> m.getSYST() != null) + .findFirst() + .get(); + + var ex = + assertThrows( + IllegalArgumentException.class, () -> sut.map(systMeldung.getSYST(), wrongPatient)); + assertThat(ex).hasMessage("The reference should point to a PATIENT resource"); + } }