Skip to content

Commit

Permalink
Fixes exception while unmarshalling ELEMENT node with children DV_COD…
Browse files Browse the repository at this point in the history
…ED_TEXT and DV_TEXT
  • Loading branch information
subigre committed Jan 18, 2022
1 parent 4e97efa commit 414a01a
Show file tree
Hide file tree
Showing 14 changed files with 44,126 additions and 137 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Note: version releases in the 0.x.y range may introduce breaking changes.
- Fix NullPointerException when event has an empty state (https://github.com/ehrbase/openEHR_SDK/pull/294)
- Fix issue when template does not contain list of values for DV_ORDINAL (https://github.com/ehrbase/openEHR_SDK/pull/295)
- Fix issue in AQL regarding LIMIT and OFFSET (https://github.com/ehrbase/openEHR_SDK/pull/296)

- Fix issue while unmarshalling FLAT composition that contains ELEMENT with children DV_CODED_TEXT and DV_TEXT (https://github.com/ehrbase/openEHR_SDK/pull/300)
-
## 1.16.0

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@

package org.ehrbase.serialisation.flatencoding.std.marshal;

import static org.ehrbase.serialisation.flatencoding.std.umarshal.StdToCompositionWalker.handleDVTextInternal;

import com.nedap.archie.rm.RMObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.ehrbase.serialisation.flatencoding.std.marshal.config.DefaultStdConfig;
import org.ehrbase.serialisation.flatencoding.std.marshal.config.StdConfig;
import org.ehrbase.serialisation.flatencoding.std.marshal.postprocessor.MarshalPostprocessor;
Expand All @@ -28,14 +34,7 @@
import org.ehrbase.serialisation.walker.FromCompositionWalker;
import org.ehrbase.util.reflection.ReflectionHelper;
import org.ehrbase.webtemplate.model.WebTemplateNode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.ehrbase.serialisation.flatencoding.std.umarshal.StdToCompositionWalker.handleDVTextInternal;
import org.ehrbase.webtemplate.util.WebTemplateUtils;

public class StdFromCompositionWalker extends FromCompositionWalker<Map<String, Object>> {

Expand Down Expand Up @@ -112,24 +111,9 @@ public static <T extends RMObject> List<MarshalPostprocessor<T>> findPostprocess

@Override
protected void handleDVText(WebTemplateNode currentNode) {
if (currentNode.getRmType().equals("ELEMENT")) {
List<WebTemplateNode> trueChildren =
currentNode.getChildren().stream()
.filter(
n ->
!List.of("null_flavour", "feeder_audit").contains(n.getName())
|| !n.isNullable())
.collect(Collectors.toList());
if (trueChildren.stream()
.map(WebTemplateNode::getId)
.collect(Collectors.toList())
.containsAll(List.of("coded_text_value", "text_value"))
&& currentNode.getChoicesInChildren().size() > 0
&& trueChildren.size() == 2) {
handleDVTextInternal(currentNode);
} else {
super.handleDVText(currentNode);
}
if (currentNode.getRmType().equals("ELEMENT")
&& WebTemplateUtils.hasDvCodedTextAndDvText(currentNode)) {
handleDVTextInternal(currentNode);
} else {
super.handleDVText(currentNode);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@

package org.ehrbase.serialisation.flatencoding.std.umarshal;

import static org.ehrbase.util.rmconstants.RmConstants.DV_CODED_TEXT;
import static org.ehrbase.util.rmconstants.RmConstants.DV_TEXT;
import static org.ehrbase.util.rmconstants.RmConstants.ELEMENT;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nedap.archie.rm.RMObject;
Expand All @@ -30,6 +34,15 @@
import com.nedap.archie.rm.datavalues.DvText;
import com.nedap.archie.rm.generic.PartyRelated;
import com.nedap.archie.rm.support.identification.TerminologyId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
Expand All @@ -50,11 +63,7 @@
import org.ehrbase.webtemplate.model.WebTemplateInput;
import org.ehrbase.webtemplate.model.WebTemplateNode;
import org.ehrbase.webtemplate.path.flat.FlatPathDto;

import java.util.*;
import java.util.stream.Collectors;

import static org.ehrbase.util.rmconstants.RmConstants.*;
import org.ehrbase.webtemplate.util.WebTemplateUtils;

public class StdToCompositionWalker extends ToCompositionWalker<Map<FlatPathDto, String>> {

Expand Down Expand Up @@ -144,12 +153,12 @@ protected ImmutablePair<Map<FlatPathDto, String>, RMObject> extractPair(
Integer i) {

if (
// Nodes with children need to be put on the stack even if there are skip since the might have
// children. If there are empty there will be removed in ToCompositionWalker::normalise
(CollectionUtils.isEmpty(childNode.getChildren())
// Nodes with children need to be put on the stack even if there are skip since the might have
// children. If there are empty there will be removed in ToCompositionWalker::normalise
(CollectionUtils.isEmpty(childNode.getChildren())
&& context.getFlatHelper().skip(childNode, currentNode))
// NonMandatoryRmAttribute are handled in the UnmarshalPostprocessor
|| (currentNode != null
// NonMandatoryRmAttribute are handled in the UnmarshalPostprocessor
|| (currentNode != null
&& context.getFlatHelper().isNonMandatoryRmAttribute(childNode, currentNode))) {
return new ImmutablePair<>(null, null);
}
Expand Down Expand Up @@ -208,7 +217,7 @@ protected void preHandle(Context<Map<FlatPathDto, String>> context) {

if (context.getRmObjectDeque().peek().getClass().isAssignableFrom(DvCodedText.class)
&& context.getObjectDeque().peek().keySet().stream()
.anyMatch(k -> "other".equals(k.getLast().getAttributeName()))) {
.anyMatch(k -> "other".equals(k.getLast().getAttributeName()))) {
replaceRmObject(context, new DvText());
}

Expand Down Expand Up @@ -285,8 +294,8 @@ private boolean isRaw(Context<Map<FlatPathDto, String>> context) {
return Objects.equals(current.getKey().getLast().getAttributeName(), "raw")
// last flat path segment matches node_id ( starting '_' marks optional flat path )
&& Objects.equals(
StringUtils.removeStart(context.getNodeDeque().peek().getId(false), "_"),
StringUtils.removeStart(current.getKey().getLast().getName(), "_"));
StringUtils.removeStart(context.getNodeDeque().peek().getId(false), "_"),
StringUtils.removeStart(current.getKey().getLast().getName(), "_"));
}

@Override
Expand All @@ -310,7 +319,8 @@ protected void postHandle(Context<Map<FlatPathDto, String>> context) {
if (context.getFlatHelper().skip(childNode, currentNode)) {

context.getNodeDeque().push(childNode);
context.getRmObjectDeque().push(new RMObject() {});
context.getRmObjectDeque().push(new RMObject() {
});

String path = context.getFlatHelper().buildNamePath(context, true);
Map<FlatPathDto, String> subValues =
Expand Down Expand Up @@ -385,54 +395,20 @@ public static <T extends RMObject> List<UnmarshalPostprocessor<T>> findUnmarshal

@Override
protected void handleDVText(WebTemplateNode currentNode) {
if (currentNode.getRmType().equals(ELEMENT)) {
List<WebTemplateNode> trueChildren =
currentNode.getChildren().stream()
.filter(n -> !"name".equals(n.getId()))
.filter(
n ->
!List.of("null_flavour", "feeder_audit").contains(n.getId())
|| !n.isNullable())
.collect(Collectors.toList());
if (trueChildren.stream()
.map(WebTemplateNode::getRmType)
.collect(Collectors.toList())
.containsAll(List.of(DV_TEXT, DV_CODED_TEXT))
&& currentNode.getChoicesInChildren().size() > 0
&& trueChildren.size() == 2) {
handleDVTextInternal(currentNode);
} else {
super.handleDVText(currentNode);
}
if (currentNode.getRmType().equals("ELEMENT")
&& WebTemplateUtils.hasDvCodedTextAndDvText(currentNode)) {
handleDVTextInternal(currentNode);
} else {
super.handleDVText(currentNode);
}
}

public static void handleDVTextInternal(WebTemplateNode node) {

if (node.getRmType().equals(ELEMENT)) {
List<WebTemplateNode> trueChildren =
node.getChildren().stream()
.filter(n -> !"name".equals(n.getId()))
.filter(
n ->
!List.of("null_flavour", "feeder_audit").contains(n.getId())
|| !n.isNullable())
.collect(Collectors.toList());
if (trueChildren.stream()
.map(WebTemplateNode::getId)
.collect(Collectors.toList())
.containsAll(List.of("coded_text_value", "text_value"))
&& node.getChoicesInChildren().size() > 0
&& trueChildren.size() == 2) {
WebTemplateNode merged = Filter.mergeDVText(node);

node.getChildren()
.removeIf(n -> List.of("coded_text_value", "text_value").contains(n.getId()));
node.getChildren().add(merged);
}
}
WebTemplateNode merged = Filter.mergeDVText(node);
node.getChildren()
.removeIf(
childNode -> List.of("coded_text_value", "text_value").contains(childNode.getId()));
node.getChildren().add(merged);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,63 @@ public void toFlatJsonAllTypes() throws IOException, XmlException {
});
}

@Test
public void toFlatJsonIps() throws Exception {
OPERATIONALTEMPLATE template =
TemplateDocument.Factory.parse(OperationalTemplateTestData.IPS.getStream())
.getTemplate();

Composition composition =
new CanonicalJson()
.unmarshal(
IOUtils.toString(
CompositionTestDataCanonicalJson.IPS.getStream(), StandardCharsets.UTF_8),
Composition.class);

FlatJsonMarshaller marshaller = new FlatJsonMarshaller();

String actual = marshaller.toFlatJson(composition, new OPTParser(template).parse());
assertThat(actual).isNotNull();

String expected =
IOUtils.toString(
CompositionTestDataSimSDTJson.IPS.getStream(), StandardCharsets.UTF_8);

List<String> errors = compere(actual, expected);


checkErrors(errors,
new String[] {
"Missing path: international_patient_summary/medication_summary/medication_statement/order_id:0|id, value: 9a0e5173-07c8-443d-b414-24432b9d95ca",
"Missing path: international_patient_summary/medical_devices/device_use_statement/device_details:0/medical_device/unique_device_identifier_udi|id, value: 73b166ae-1c28-4ce0-8c08-a9587d8fd95a",
"Missing path: international_patient_summary/medical_devices/device_use_statement/device_details:0/medical_device/other_identifier:0|id, value: 60287ff3-ec0f-4cd5-9000-2c05af2e6a84",
"Missing path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/requester_order_identifier|id, value: 38a6687c-5136-4e75-9f1c-126e8f0e112b",
"Missing path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/receiver_order_identifier|id, value: 9fc6db02-81de-4ec9-afe4-f365c42019e1",
"Missing path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/report_identifier|id, value: a147525c-4763-4070-ba22-26e6b33348f4",
"Missing path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/reported_image:0/image_identifier|id, value: 5462ef5c-2275-47c2-8fb5-f9f1d7a19613",
"Missing path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/reported_image:0/dicom_series_identifier|id, value: 55dd86d7-52ff-4064-8dc7-f8d9b2bc22e7",
"Missing path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/comparison_image:0/image_identifier|id, value: a6c20273-7b53-4c04-9b2c-2d4c218893b2",
"Missing path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/comparison_image:0/dicom_series_identifier|id, value: 1ba8eff7-8f3f-4625-9432-05aa01726073",
"Missing path: international_patient_summary/vital_signs/pulse_oximetry/any_event:0/spo, value: 0.8920999999999999",
"Missing path: international_patient_summary/plan_of_care/care_plan/care_plan_id|id, value: 0942fb74-27f8-48c6-869e-10192740c371",
"Missing path: international_patient_summary/plan_of_care/service_request/current_activity:0/action_archetype_id, value: /.*/"
},
new String[] {
"Extra path: international_patient_summary/medication_summary/medication_statement/order_id:0, value: 9a0e5173-07c8-443d-b414-24432b9d95ca",
"Extra path: international_patient_summary/medical_devices/device_use_statement/device_details:0/medical_device/unique_device_identifier_udi, value: 73b166ae-1c28-4ce0-8c08-a9587d8fd95a",
"Extra path: international_patient_summary/medical_devices/device_use_statement/device_details:0/medical_device/other_identifier:0, value: 60287ff3-ec0f-4cd5-9000-2c05af2e6a84",
"Extra path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/requester_order_identifier, value: 38a6687c-5136-4e75-9f1c-126e8f0e112b",
"Extra path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/receiver_order_identifier, value: 9fc6db02-81de-4ec9-afe4-f365c42019e1",
"Extra path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/report_identifier, value: a147525c-4763-4070-ba22-26e6b33348f4",
"Extra path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/reported_image:0/image_identifier, value: 5462ef5c-2275-47c2-8fb5-f9f1d7a19613",
"Extra path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/reported_image:0/dicom_series_identifier, value: 55dd86d7-52ff-4064-8dc7-f8d9b2bc22e7",
"Extra path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/comparison_image:0/image_identifier, value: a6c20273-7b53-4c04-9b2c-2d4c218893b2",
"Extra path: international_patient_summary/diagnostic_results/imaging_examination_result/examination_request_details:0/comparison_image:0/dicom_series_identifier, value: 1ba8eff7-8f3f-4625-9432-05aa01726073",
"Extra path: international_patient_summary/vital_signs/pulse_oximetry/any_event:0/spo, value: 0.8921",
"Extra path: international_patient_summary/plan_of_care/care_plan/care_plan_id, value: 0942fb74-27f8-48c6-869e-10192740c371"
});
}

public void checkErrors(List<String> errors, String[] missing, String[] extra) {

SoftAssertions softAssertions = new SoftAssertions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,21 @@ public void unmarshallNestedComposition() throws Exception {

assertDoesNotThrow(() -> new Validator(optTemplate).check(composition));
}


@Test
public void unmarshallIpsComposition() throws Exception {
var optTemplate = TemplateDocument.Factory.parse(OperationalTemplateTestData.IPS.getStream())
.getTemplate();
var webTemplate = new OPTParser(optTemplate).parse();

var json = IOUtils.toString(CompositionTestDataSimSDTJson.IPS.getStream(),
StandardCharsets.UTF_8);

var composition = new FlatJsonUnmarshaller().unmarshal(json, webTemplate);

assertThat(composition).isNotNull();

assertDoesNotThrow(() -> new Validator(optTemplate).check(composition));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public enum CompositionTestDataCanonicalJson {
MINIMAL_WITHOUT_OPTIONAL_ATTRIBUTE("dv multimedia without alternate_text", "minimal_without_optional_attribute.json"),
GECCO_PERSONENDATEN("GECCO_Personendaten", "gecco_personendaten.json"),
GECCO_LABORBEFUND("GECCO_Laborbefund", "gecco_laborbefund.json"),
PARTICIPATION_NO_CONTENT("to test various participation CR #710", "participation_no_content.json");
PARTICIPATION_NO_CONTENT("to test various participation CR #710", "participation_no_content.json"),
IPS("Internation Patient Summary", "ips_canonical.json");


private final String filename;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public enum CompositionTestDataSimSDTJson {
MULTI_LIST("MULTI_LIST", "multi_list.json"),
NCD("NCD", "NCD.json"),
EREACT_COVID_MANAGEMENT("flat with action", "EREACT - Covid status monitoring - FLAT.json"),
NESTED("nested.en.v1", "nested.en.v1.json");
NESTED("nested.en.v1", "nested.en.v1.json"),
IPS("International Patient Summary", "ips_flat.json");

private final String filename;
private final String description;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ public enum OperationalTemplateTestData {
MINIMAL_ACTION("Minimal Action 3", "minimal_action3.opt", "minimal_action_3.en.v1"),
NCD("ncd", "NCD.opt", "NCD"),
MULTIMEDIA_TEST("MultimediaTest", "multimedia_test.en.v1.opt", "multimedia_test.en.v1"),
NESTED("nested.en.v1", "nested.en.v1.opt", "nested.en.v1");
NESTED("nested.en.v1", "nested.en.v1.opt", "nested.en.v1"),
IPS("International Patient Summary", "ips.v0.opt", "International Patient Summary");

private final String filename;
private final String templateId;
Expand Down
Loading

0 comments on commit 414a01a

Please sign in to comment.