From 9e7e6698bdfb6ed91852611c96b449b9bcbee93c Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 24 Aug 2021 06:56:51 +1000 Subject: [PATCH 1/2] fix DiagnosticReport rendering (NPEs) --- .../renderers/DiagnosticReportRenderer.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java index 7e51886a1..1e1e72cdb 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java @@ -189,9 +189,9 @@ public class DiagnosticReportRenderer extends ResourceRenderer { ObservationNode obs = new ObservationNode(); obs.ref = b.get("reference").primitiveValue(); obs.obs = resolveReference(rw, obs.ref); - if (obs.obs.getResource() != null) { + if (obs.obs != null && obs.obs.getResource() != null) { PropertyWrapper t = getProperty(obs.obs.getResource(), "contained"); - if (t.hasValues()) { + if (t != null && t.hasValues()) { obs.contained = fetchObservations(t.getValues(), rw); } } @@ -239,7 +239,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer { private boolean scanObsForRefRange(List observations) { for (ObservationNode o : observations) { - if (o.obs.getResource() != null) { + if (o.obs != null && o.obs.getResource() != null) { PropertyWrapper pw = getProperty(o.obs.getResource(), "referenceRange"); if (valued(pw)) { return true; @@ -256,7 +256,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer { private boolean scanObsForNote(List observations) { for (ObservationNode o : observations) { - if (o.obs.getResource() != null) { + if (o.obs != null && o.obs.getResource() != null) { PropertyWrapper pw = getProperty(o.obs.getResource(), "note"); if (valued(pw)) { return true; @@ -273,7 +273,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer { private boolean scanObsForIssued(List observations, DataType iss) throws UnsupportedEncodingException, FHIRException, IOException { for (ObservationNode o : observations) { - if (o.obs.getResource() != null) { + if (o.obs != null && o.obs.getResource() != null) { PropertyWrapper pw = getProperty(o.obs.getResource(), "issued"); if (valued(pw)) { if (!Base.compareDeep(pw.value().getBase(), iss, true)) { @@ -292,7 +292,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer { private boolean scanObsForEffective(List observations, DataType eff) throws UnsupportedEncodingException, FHIRException, IOException { for (ObservationNode o : observations) { - if (o.obs.getResource() != null) { + if (o.obs != null && o.obs.getResource() != null) { PropertyWrapper pw = getProperty(o.obs.getResource(), "effective[x]"); if (valued(pw)) { if (!Base.compareDeep(pw.value().getBase(), eff, true)) { @@ -311,7 +311,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer { private boolean scanObsForFlags(List observations) throws UnsupportedEncodingException, FHIRException, IOException { for (ObservationNode o : observations) { - if (o.obs.getResource() != null) { + if (o.obs != null && o.obs.getResource() != null) { PropertyWrapper pw = getProperty(o.obs.getResource(), "interpretation"); if (valued(pw)) { return true; @@ -335,15 +335,15 @@ public class DiagnosticReportRenderer extends ResourceRenderer { private void addObservationToTable(XhtmlNode tbl, ObservationNode o, int i, String cs, boolean refRange, boolean flags, boolean note, boolean effectiveTime, boolean issued, DataType eff, DataType iss) throws UnsupportedEncodingException, FHIRException, IOException { XhtmlNode tr = tbl.tr(); - if (o.obs.getReference() == null) { + if (o.obs != null && o.obs.getReference() == null) { XhtmlNode td = tr.td().colspan(cs); td.i().tx("This Observation could not be resolved"); } else { - if (o.obs.getResource() != null) { + if (o.obs != null && o.obs.getResource() != null) { addObservationToTable(tr, o.obs.getResource(), i, o.obs.getReference(), refRange, flags, note, effectiveTime, issued, eff, iss); } else { XhtmlNode td = tr.td().colspan(cs); - td.i().ah(o.obs.getReference()).tx("Observation"); + td.i().tx("Observation"); } if (o.contained != null) { for (ObservationNode c : o.contained) { From fb0d90ad1fa51f45ebdabd543f91f00dc9c8ba7f Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 24 Aug 2021 17:03:33 +1000 Subject: [PATCH 2/2] return system+code with display when validating --- .../hl7/fhir/r5/context/BaseWorkerContext.java | 12 +++++++++--- .../hl7/fhir/r5/context/IWorkerContext.java | 17 +++++++++++++---- .../hl7/fhir/r5/context/TerminologyCache.java | 6 +++++- .../terminologies/ValueSetCheckerSimple.java | 18 +++++++++--------- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index c7ea92444..4ceb1f27a 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -1062,6 +1062,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte boolean ok = false; String message = "No Message returned"; String display = null; + String system = null; + String code = null; TerminologyServiceErrorClass err = TerminologyServiceErrorClass.UNKNOWN; for (ParametersParameterComponent p : pOut.getParameter()) { if (p.hasValue()) { @@ -1071,6 +1073,10 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte message = ((StringType) p.getValue()).getValue(); } else if (p.getName().equals("display")) { display = ((StringType) p.getValue()).getValue(); + } else if (p.getName().equals("system")) { + system = ((StringType) p.getValue()).getValue(); + } else if (p.getName().equals("code")) { + code = ((StringType) p.getValue()).getValue(); } else if (p.getName().equals("cause")) { try { IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue()); @@ -1089,11 +1095,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte if (!ok) { return new ValidationResult(IssueSeverity.ERROR, message+" (from "+txClient.getAddress()+")", err).setTxLink(txLog.getLastId()); } else if (message != null && !message.equals("No Message returned")) { - return new ValidationResult(IssueSeverity.WARNING, message+" (from "+txClient.getAddress()+")", new ConceptDefinitionComponent().setDisplay(display)).setTxLink(txLog.getLastId()); + return new ValidationResult(IssueSeverity.WARNING, message+" (from "+txClient.getAddress()+")", system, new ConceptDefinitionComponent().setDisplay(display).setCode(code)).setTxLink(txLog.getLastId()); } else if (display != null) { - return new ValidationResult(new ConceptDefinitionComponent().setDisplay(display)).setTxLink(txLog.getLastId()); + return new ValidationResult(system, new ConceptDefinitionComponent().setDisplay(display).setCode(code)).setTxLink(txLog.getLastId()); } else { - return new ValidationResult(new ConceptDefinitionComponent()).setTxLink(txLog.getLastId()); + return new ValidationResult(system, new ConceptDefinitionComponent().setCode(code)).setTxLink(txLog.getLastId()); } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java index fd3b1c84e..e135c99a1 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java @@ -538,6 +538,7 @@ public interface IWorkerContext { class ValidationResult { private ConceptDefinitionComponent definition; + private String system; private IssueSeverity severity; private String message; private TerminologyServiceErrorClass errorClass; @@ -548,13 +549,15 @@ public interface IWorkerContext { this.message = message; } - public ValidationResult(ConceptDefinitionComponent definition) { + public ValidationResult(String system, ConceptDefinitionComponent definition) { + this.system = system; this.definition = definition; } - public ValidationResult(IssueSeverity severity, String message, ConceptDefinitionComponent definition) { + public ValidationResult(IssueSeverity severity, String message, String system, ConceptDefinitionComponent definition) { this.severity = severity; this.message = message; + this.system = system; this.definition = definition; } @@ -568,12 +571,18 @@ public interface IWorkerContext { return severity == null || severity == IssueSeverity.INFORMATION || severity == IssueSeverity.WARNING; } + public String getSystem() { + return system; + } + public String getDisplay() { -// We don't want to return question-marks because that prevents something more useful from being displayed (e.g. the code) if there's no display value -// return definition == null ? "??" : definition.getDisplay(); return definition == null ? null : definition.getDisplay(); } + public String getCode() { + return definition == null ? null : definition.getCode(); + } + public ConceptDefinitionComponent asConceptDefinition() { return definition; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TerminologyCache.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TerminologyCache.java index cabac030d..ac8b0a6b4 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TerminologyCache.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TerminologyCache.java @@ -333,6 +333,8 @@ public class TerminologyCache { } else { sw.write("v: {\r\n"); sw.write(" \"display\" : \""+Utilities.escapeJson(ce.v.getDisplay()).trim()+"\",\r\n"); + sw.write(" \"code\" : \""+Utilities.escapeJson(ce.v.getCode()).trim()+"\",\r\n"); + sw.write(" \"system\" : \""+Utilities.escapeJson(ce.v.getSystem()).trim()+"\",\r\n"); sw.write(" \"severity\" : "+(ce.v.getSeverity() == null ? "null" : "\""+ce.v.getSeverity().toCode().trim()+"\"")+",\r\n"); sw.write(" \"error\" : \""+Utilities.escapeJson(ce.v.getMessage()).trim()+"\"\r\n}\r\n"); } @@ -379,7 +381,9 @@ public class TerminologyCache { } else { IssueSeverity severity = o.get("severity") instanceof JsonNull ? null : IssueSeverity.fromCode(o.get("severity").getAsString()); String display = loadJS(o.get("display")); - ce.v = new ValidationResult(severity, error, new ConceptDefinitionComponent().setDisplay(display)); + String code = loadJS(o.get("code")); + String system = loadJS(o.get("system")); + ce.v = new ValidationResult(severity, error, system, new ConceptDefinitionComponent().setDisplay(display).setCode(code)); } nc.map.put(String.valueOf(hashNWS(ce.request)), ce); nc.list.add(ce); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java index 4a768e362..709886004 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java @@ -176,7 +176,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe res = validateCode(code, cs); } else if (cs == null && valueset.hasExpansion() && inExpansion) { // we just take the value set as face value then - res = new ValidationResult(new ConceptDefinitionComponent().setCode(code.getCode()).setDisplay(code.getDisplay())); + res = new ValidationResult(system, new ConceptDefinitionComponent().setCode(code.getCode()).setDisplay(code.getDisplay())); } else { // well, we didn't find a code system - try the expansion? // disabled waiting for discussion @@ -193,7 +193,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe Boolean ok = codeInValueSet(system, code.getCode()); if (ok == null || !ok) { if (res == null) { - res = new ValidationResult(null, null); + res = new ValidationResult((IssueSeverity) null, null); } if (!inExpansion && !inInclude) { res.setMessage("Not in value set "+valueset.getUrl()).setSeverity(IssueSeverity.ERROR); @@ -258,7 +258,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe ConceptDefinitionComponent ccd = new ConceptDefinitionComponent(); ccd.setCode(containsComponent.getCode()); ccd.setDisplay(containsComponent.getDisplay()); - ValidationResult res = new ValidationResult(ccd); + ValidationResult res = new ValidationResult(code.getSystem(), ccd); return res; } if (containsComponent.hasContains()) { @@ -300,19 +300,19 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe } } if (code.getDisplay() == null) { - return new ValidationResult(cc); + return new ValidationResult(code.getSystem(), cc); } CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); if (cc.hasDisplay()) { b.append(cc.getDisplay()); if (code.getDisplay().equalsIgnoreCase(cc.getDisplay())) { - return new ValidationResult(cc); + return new ValidationResult(code.getSystem(), cc); } } for (ConceptDefinitionDesignationComponent ds : cc.getDesignation()) { b.append(ds.getValue()); if (code.getDisplay().equalsIgnoreCase(ds.getValue())) { - return new ValidationResult(cc); + return new ValidationResult(code.getSystem(), cc); } } // also check to see if the value set has another display @@ -321,17 +321,17 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe if (vs.hasDisplay()) { b.append(vs.getDisplay()); if (code.getDisplay().equalsIgnoreCase(vs.getDisplay())) { - return new ValidationResult(cc); + return new ValidationResult(code.getSystem(), cc); } } for (ConceptReferenceDesignationComponent ds : vs.getDesignation()) { b.append(ds.getValue()); if (code.getDisplay().equalsIgnoreCase(ds.getValue())) { - return new ValidationResult(cc); + return new ValidationResult(code.getSystem(), cc); } } } - return new ValidationResult(IssueSeverity.WARNING, context.formatMessage(I18nConstants.DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF_, code.getSystem(), code.getCode(), b.toString(), code.getDisplay()), cc); + return new ValidationResult(IssueSeverity.WARNING, context.formatMessage(I18nConstants.DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF_, code.getSystem(), code.getCode(), b.toString(), code.getDisplay()), code.getSystem(), cc); } private ConceptReferenceComponent findValueSetRef(String system, String code) {