Merge pull request #709 from hapifhir/gg-202201-rendering-fixes

fix NPE in validator & rendering fixes: concept map display + name re…
This commit is contained in:
dotasek 2022-01-10 17:59:35 -05:00 committed by GitHub
commit 5ef72e2eea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 125 additions and 275 deletions

View File

@ -1 +1,2 @@
* fix bug for NullPointerException in Bundle convertors when resource is not available. * fix bug for NullPointerException in Bundle convertors when resource is not available.
* fix Java locale backward compatibility in surefire

View File

@ -106,7 +106,7 @@ public class NarrativeGenerationTests {
} }
public static Stream<Arguments> data() throws ParserConfigurationException, IOException, FHIRFormatError, SAXException { public static Stream<Arguments> data() throws ParserConfigurationException, IOException, FHIRFormatError, SAXException {
Document tests = XMLUtil.parseToDom(TestingUtilities.loadTestResource("r5", "narrative", "manifest.xml")); Document tests = XMLUtil.parseToDom(TestingUtilities.loadTestResource("r4b", "narrative", "manifest.xml"));
Element test = XMLUtil.getFirstChild(tests.getDocumentElement()); Element test = XMLUtil.getFirstChild(tests.getDocumentElement());
List<Arguments> objects = new ArrayList<>(); List<Arguments> objects = new ArrayList<>();
while (test != null && test.getNodeName().equals("test")) { while (test != null && test.getNodeName().equals("test")) {

View File

@ -59,7 +59,7 @@ public class ConceptMapRenderer extends TerminologyRenderer {
p.addText(Utilities.capitalize(cm.getStatus().toString())+" (not intended for production usage). "); p.addText(Utilities.capitalize(cm.getStatus().toString())+" (not intended for production usage). ");
else else
p.addText(Utilities.capitalize(cm.getStatus().toString())+". "); p.addText(Utilities.capitalize(cm.getStatus().toString())+". ");
p.tx("Published on "+(cm.hasDate() ? cm.getDateElement().toHumanDisplay() : "?ngen-10?")+" by "+cm.getPublisher()); p.tx("Published on "+(cm.hasDate() ? display(cm.getDateElement()) : "?ngen-10?")+" by "+cm.getPublisher());
if (!cm.getContact().isEmpty()) { if (!cm.getContact().isEmpty()) {
p.tx(" ("); p.tx(" (");
boolean firsti = true; boolean firsti = true;
@ -132,11 +132,25 @@ public class ConceptMapRenderer extends TerminologyRenderer {
tr.td().b().tx("Destination Code"); tr.td().b().tx("Destination Code");
if (comment) if (comment)
tr.td().b().tx("Comment"); tr.td().b().tx("Comment");
tr = tbl.tr();
XhtmlNode td = tr.td().colspan(comment ? "4" : "3");
td.tx("Mapping from ");
if (grp.hasSource()) {
renderCanonical(cm, td, grp.getSource());
} else {
td.code("unspecified code system");
}
td.tx(" to ");
if (grp.hasTarget()) {
renderCanonical(cm, td, grp.getTarget());
} else {
td.code("unspecified code system");
}
for (SourceElementComponent ccl : grp.getElement()) { for (SourceElementComponent ccl : grp.getElement()) {
tr = tbl.tr(); tr = tbl.tr();
XhtmlNode td = tr.td(); td = tr.td();
td.addText(ccl.getCode()); td.addText(ccl.getCode());
display = getDisplayForConcept(systemFromCanonical(grp.getSource()), versionFromCanonical(grp.getSource()), ccl.getCode()); display = ccl.hasDisplay() ? ccl.getDisplay() : getDisplayForConcept(systemFromCanonical(grp.getSource()), versionFromCanonical(grp.getSource()), ccl.getCode());
if (display != null && !isSameCodeAndDisplay(ccl.getCode(), display)) if (display != null && !isSameCodeAndDisplay(ccl.getCode(), display))
td.tx(" ("+display+")"); td.tx(" ("+display+")");
TargetElementComponent ccm = ccl.getTarget().get(0); TargetElementComponent ccm = ccl.getTarget().get(0);
@ -152,7 +166,7 @@ public class ConceptMapRenderer extends TerminologyRenderer {
} }
td = tr.td(); td = tr.td();
td.addText(ccm.getCode()); td.addText(ccm.getCode());
display = getDisplayForConcept(systemFromCanonical(grp.getTarget()), versionFromCanonical(grp.getTarget()), ccm.getCode()); display = ccm.hasDisplay() ? ccm.getDisplay() : getDisplayForConcept(systemFromCanonical(grp.getTarget()), versionFromCanonical(grp.getTarget()), ccm.getCode());
if (display != null && !isSameCodeAndDisplay(ccm.getCode(), display)) if (display != null && !isSameCodeAndDisplay(ccm.getCode(), display))
td.tx(" ("+display+")"); td.tx(" ("+display+")");
if (comment) if (comment)

View File

@ -158,9 +158,8 @@ public abstract class ResourceRenderer extends DataRenderer {
if (target.hasUserData("path")) { if (target.hasUserData("path")) {
x.ah(target.getUserString("path")).tx(cr.present()); x.ah(target.getUserString("path")).tx(cr.present());
} else { } else {
url = url.substring(0, url.indexOf("|"));
x.code().tx(url); x.code().tx(url);
x.tx(": "+cr.present()); x.tx(" ("+cr.present()+")");
} }
} }
} }

View File

@ -173,7 +173,8 @@ public class ElementWrappers {
s = s + " " + family.getValues().get(0).primitiveValue().toUpperCase(); s = s + " " + family.getValues().get(0).primitiveValue().toUpperCase();
return s; return s;
} else { } else {
throw new Error("Now what? ("+b.fhirType()+")"); // well, we couldn't get a name from that
return null;
} }
} }
return null; return null;

View File

@ -0,0 +1,66 @@
package org.hl7.fhir.r5.utils;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* This clas smaps between the jurisdictions defined for CanonicalResource.jurisdiction
* and Java Locale
* @author graha
*
*/
public class JurisdictionLocales {
private Map<String, String> map = new HashMap<>();
public JurisdictionLocales() {
super();
register();
}
private void register() {
register("USA", "US", "en-US");
register("AUS", "AU", "en-AU");
register("NZL", "NZ", "en-NZ");
register("GBR", "GB", "en-GB");
register("IND", "IN", "en-IN");
register("AUT", "AT", "de-AT");
register("CHE", "CH", "de-CH");
register("DEU", "DE", "de-DE");
register("NOR", "NO", "no-NO");
register("SWE", "SE", "sv-SE");
register("FIN", "FI", "fi-FI");
register("DNK", "DK", "da-DK");
register("NLD", "NL", "nl-NL");
register("BEL", "BE", "nl-BE"); // but will be fr-BE if lang is specified
register("FRA", "FR", "fr-FR");
register("ITA", "IT", "it-IT");
register("RUS", "RU", "ru-RU");
register("ESP", "ES", "es-ES");
register("ARG", "AR", "es-AR");
register("UGY", "UY", "es-UY");
register("PRT", "PT", "pt-PT");
register("BRA", "BR", "pt-BR");
register("CHN", "CN", "zh-CN");
register("TWN", "TW", "zh-TW");
register("JPN", "JP", "ja-JP");
register("KOR", "KR", "ko-KR");
register("VNM", "VN", "vn-VN");
}
private void register(String code3, String code2, String locale) {
map.put(code3, locale);
map.put(code2, locale);
}
public String get(String c) {
return map.get(c.toUpperCase());
}
}

View File

@ -31,10 +31,13 @@ package org.hl7.fhir.r5.utils;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r5.model.Bundle.BundleLinkComponent; import org.hl7.fhir.r5.model.Bundle.BundleLinkComponent;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeableConcept; import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ContactPoint; import org.hl7.fhir.r5.model.ContactPoint;
@ -61,6 +64,7 @@ import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
public class ResourceUtilities { public class ResourceUtilities {
public final static String FHIR_LANGUAGE = "urn:ietf:bcp:47"; public final static String FHIR_LANGUAGE = "urn:ietf:bcp:47";
private static JurisdictionLocales jl = new JurisdictionLocales();
public static boolean isAnError(OperationOutcome error) { public static boolean isAnError(OperationOutcome error) {
for (OperationOutcomeIssueComponent t : error.getIssue()) for (OperationOutcomeIssueComponent t : error.getIssue())
@ -121,274 +125,36 @@ public class ResourceUtilities {
return resource.getMeta(); return resource.getMeta();
} }
// public static String representDataElementCollection(IWorkerContext context, Bundle bundle, boolean profileLink, String linkBase) { public static Locale getLocale(CanonicalResource cr) {
// StringBuilder b = new StringBuilder(); return getLocale(cr.getLanguage(), cr.getJurisdiction());
// DataElement common = showDECHeader(b, bundle); }
// b.append("<table class=\"grid\">\r\n");
// List<String> cols = chooseColumns(bundle, common, b, profileLink);
// for (BundleEntryComponent e : bundle.getEntry()) {
// DataElement de = (DataElement) e.getResource();
// renderDE(de, cols, b, profileLink, linkBase);
// }
// b.append("</table>\r\n");
// return b.toString();
// }
//
//
// private static void renderDE(DataElement de, List<String> cols, StringBuilder b, boolean profileLink, String linkBase) {
// b.append("<tr>");
// for (String col : cols) {
// String v;
// ElementDefinition dee = de.getElement().get(0);
// if (col.equals("DataElement.name")) {
// v = de.hasName() ? Utilities.escapeXml(de.getName()) : "";
// } else if (col.equals("DataElement.status")) {
// v = de.hasStatusElement() ? de.getStatusElement().asStringValue() : "";
// } else if (col.equals("DataElement.code")) {
// v = renderCoding(dee.getCode());
// } else if (col.equals("DataElement.type")) {
// v = dee.hasType() ? Utilities.escapeXml(dee.getType().get(0).getCode()) : "";
// } else if (col.equals("DataElement.units")) {
// v = renderDEUnits(ToolingExtensions.getAllowedUnits(dee));
// } else if (col.equals("DataElement.binding")) {
// v = renderBinding(dee.getBinding());
// } else if (col.equals("DataElement.minValue")) {
// v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/minValue") ? Utilities.escapeXml(ToolingExtensions.readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/minValue").asStringValue()) : "";
// } else if (col.equals("DataElement.maxValue")) {
// v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/maxValue") ? Utilities.escapeXml(ToolingExtensions.readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/maxValue").asStringValue()) : "";
// } else if (col.equals("DataElement.maxLength")) {
// v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/maxLength") ? Utilities.escapeXml(ToolingExtensions.readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/maxLength").asStringValue()) : "";
// } else if (col.equals("DataElement.mask")) {
// v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/mask") ? Utilities.escapeXml(ToolingExtensions.readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/mask").asStringValue()) : "";
// } else
// throw new Error("Unknown column name: "+col);
//
// b.append("<td>"+v+"</td>");
// }
// if (profileLink) {
// b.append("<td><a href=\""+linkBase+"-"+de.getId()+".html\">Profile</a>, <a href=\"http://www.opencem.org/#/20140917/Intermountain/"+de.getId()+"\">CEM</a>");
// if (ToolingExtensions.hasExtension(de, ToolingExtensions.EXT_CIMI_REFERENCE))
// b.append(", <a href=\""+ToolingExtensions.readStringExtension(de, ToolingExtensions.EXT_CIMI_REFERENCE)+"\">CIMI</a>");
// b.append("</td>");
// }
// b.append("</tr>\r\n");
// }
public static Locale getLocale(String lang, List<CodeableConcept> jurisdictions) {
if (lang != null && lang.contains("-")) {
private static String renderBinding(ElementDefinitionBindingComponent binding) { return new Locale(lang);
// TODO Auto-generated method stub }
for (CodeableConcept cc : jurisdictions) {
Locale locale = getLocale(lang, cc);
if (locale != null) {
return locale;
}
}
return null; return null;
} }
private static String renderDEUnits(DataType units) {
if (units == null || units.isEmpty())
return "";
if (units instanceof CodeableConcept)
return renderCodeable((CodeableConcept) units);
else
return "<a href=\""+Utilities.escapeXml(((Reference) units).getReference())+"\">"+Utilities.escapeXml(((Reference) units).getReference())+"</a>";
} private static Locale getLocale(String lang, CodeableConcept cc) {
if (cc.hasCoding("http://unstats.un.org/unsd/methods/m49/m49.htm", "001")) {
private static String renderCodeable(CodeableConcept units) { return new Locale("en-US");
if (units == null || units.isEmpty())
return "";
String v = renderCoding(units.getCoding());
if (units.hasText())
v = v + " " +Utilities.escapeXml(units.getText());
return v;
}
private static String renderCoding(List<Coding> codes) {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (Coding c : codes)
b.append(renderCoding(c));
return b.toString();
}
private static String renderCoding(Coding code) {
if (code == null || code.isEmpty())
return "";
else
return "<span title=\""+Utilities.escapeXml(code.getSystem())+"\">"+Utilities.escapeXml(code.getCode())+"</span>";
}
// private static List<String> chooseColumns(Bundle bundle, DataElement common, StringBuilder b, boolean profileLink) {
// b.append("<tr>");
// List<String> results = new ArrayList<String>();
// results.add("DataElement.name");
// b.append("<td width=\"250\"><b>Name</b></td>");
// if (!common.hasStatus()) {
// results.add("DataElement.status");
// b.append("<td><b>Status</b></td>");
// }
// if (hasCode(bundle)) {
// results.add("DataElement.code");
// b.append("<td><b>Code</b></td>");
// }
// if (!common.getElement().get(0).hasType() && hasType(bundle)) {
// results.add("DataElement.type");
// b.append("<td><b>Type</b></td>");
// }
// if (hasUnits(bundle)) {
// results.add("DataElement.units");
// b.append("<td><b>Units</b></td>");
// }
// if (hasBinding(bundle)) {
// results.add("DataElement.binding");
// b.append("<td><b>Binding</b></td>");
// }
// if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/minValue")) {
// results.add("DataElement.minValue");
// b.append("<td><b>Min Value</b></td>");
// }
// if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/maxValue")) {
// results.add("DataElement.maxValue");
// b.append("<td><b>Max Value</b></td>");
// }
// if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/maxLength")) {
// results.add("DataElement.maxLength");
// b.append("<td><b>Max Length</b></td>");
// }
// if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/mask")) {
// results.add("DataElement.mask");
// b.append("<td><b>Mask</b></td>");
// }
// if (profileLink)
// b.append("<td><b>Links</b></td>");
// b.append("</tr>\r\n");
// return results;
// }
//
// private static boolean hasExtension(Bundle bundle, String url) {
// for (BundleEntryComponent e : bundle.getEntry()) {
// DataElement de = (DataElement) e.getResource();
// if (ToolingExtensions.hasExtension(de, url))
// return true;
// }
// return false;
// }
//
// private static boolean hasBinding(Bundle bundle) {
// for (BundleEntryComponent e : bundle.getEntry()) {
// DataElement de = (DataElement) e.getResource();
// if (de.getElement().get(0).hasBinding())
// return true;
// }
// return false;
// }
//
// private static boolean hasCode(Bundle bundle) {
// for (BundleEntryComponent e : bundle.getEntry()) {
// DataElement de = (DataElement) e.getResource();
// if (de.getElement().get(0).hasCode())
// return true;
// }
// return false;
// }
//
// private static boolean hasType(Bundle bundle) {
// for (BundleEntryComponent e : bundle.getEntry()) {
// DataElement de = (DataElement) e.getResource();
// if (de.getElement().get(0).hasType())
// return true;
// }
// return false;
// }
//
// private static boolean hasUnits(Bundle bundle) {
// for (BundleEntryComponent e : bundle.getEntry()) {
// DataElement de = (DataElement) e.getResource();
// if (ToolingExtensions.getAllowedUnits(de.getElement().get(0)) != null)
// return true;
// }
// return false;
// }
//
// private static DataElement showDECHeader(StringBuilder b, Bundle bundle) {
// DataElement meta = new DataElement();
// DataElement prototype = (DataElement) bundle.getEntry().get(0).getResource();
// meta.setPublisher(prototype.getPublisher());
// meta.getContact().addAll(prototype.getContact());
// meta.setStatus(prototype.getStatus());
// meta.setDate(prototype.getDate());
// meta.addElement().getType().addAll(prototype.getElement().get(0).getType());
//
// for (BundleEntryComponent e : bundle.getEntry()) {
// DataElement de = (DataElement) e.getResource();
// if (!Base.compareDeep(de.getPublisherElement(), meta.getPublisherElement(), false))
// meta.setPublisherElement(null);
// if (!Base.compareDeep(de.getContact(), meta.getContact(), false))
// meta.getContact().clear();
// if (!Base.compareDeep(de.getStatusElement(), meta.getStatusElement(), false))
// meta.setStatusElement(null);
// if (!Base.compareDeep(de.getDateElement(), meta.getDateElement(), false))
// meta.setDateElement(null);
// if (!Base.compareDeep(de.getElement().get(0).getType(), meta.getElement().get(0).getType(), false))
// meta.getElement().get(0).getType().clear();
// }
// if (meta.hasPublisher() || meta.hasContact() || meta.hasStatus() || meta.hasDate() /* || meta.hasType() */) {
// b.append("<table class=\"grid\">\r\n");
// if (meta.hasPublisher())
// b.append("<tr><td>Publisher:</td><td>"+meta.getPublisher()+"</td></tr>\r\n");
// if (meta.hasContact()) {
// b.append("<tr><td>Contacts:</td><td>");
// boolean firsti = true;
// for (ContactDetail c : meta.getContact()) {
// if (firsti)
// firsti = false;
// else
// b.append("<br/>");
// if (c.hasName())
// b.append(Utilities.escapeXml(c.getName())+": ");
// boolean first = true;
// for (ContactPoint cp : c.getTelecom()) {
// if (first)
// first = false;
// else
// b.append(", ");
// renderContactPoint(b, cp);
// }
// }
// b.append("</td></tr>\r\n");
// }
// if (meta.hasStatus())
// b.append("<tr><td>Status:</td><td>"+meta.getStatus().toString()+"</td></tr>\r\n");
// if (meta.hasDate())
// b.append("<tr><td>Date:</td><td>"+meta.getDateElement().asStringValue()+"</td></tr>\r\n");
// if (meta.getElement().get(0).hasType())
// b.append("<tr><td>Type:</td><td>"+renderType(meta.getElement().get(0).getType())+"</td></tr>\r\n");
// b.append("</table>\r\n");
// }
// return meta;
// }
private static String renderType(List<TypeRefComponent> type) {
if (type == null || type.isEmpty())
return "";
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (TypeRefComponent c : type)
b.append(renderType(c));
return b.toString();
}
private static String renderType(TypeRefComponent type) {
if (type == null || type.isEmpty())
return "";
return type.getWorkingCode();
}
public static void renderContactPoint(StringBuilder b, ContactPoint cp) {
if (cp != null && !cp.isEmpty()) {
if (cp.getSystem() == ContactPointSystem.EMAIL)
b.append("<a href=\"mailto:"+cp.getValue()+"\">"+cp.getValue()+"</a>");
else if (cp.getSystem() == ContactPointSystem.FAX)
b.append("Fax: "+cp.getValue());
else if (cp.getSystem() == ContactPointSystem.OTHER)
b.append("<a href=\""+cp.getValue()+"\">"+cp.getValue()+"</a>");
else
b.append(cp.getValue());
} }
} String c = cc.getCode("urn:iso:std:iso:3166:-2");
String l = jl.get(c);
if (l == null) {
return null;
} else if (lang != null) {
return new Locale(lang+"-"+l.substring(l.indexOf("-")+1));
} else {
return new Locale(l);
}
}
} }

View File

@ -4656,7 +4656,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
timeTracker.sd(t); timeTracker.sd(t);
trackUsage(profile, hostContext, element); trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special.toHuman(), resourceName)) { profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special == null ? "??" : special.toHuman(), resourceName)) {
validateResource(hc, errors, resource, element, profile, idstatus, stack); validateResource(hc, errors, resource, element, profile, idstatus, stack);
} }
} else { } else {

View File

@ -19,7 +19,7 @@
<properties> <properties>
<hapi_fhir_version>5.1.0</hapi_fhir_version> <hapi_fhir_version>5.1.0</hapi_fhir_version>
<validator_test_case_version>1.1.84-SNAPSHOT</validator_test_case_version> <validator_test_case_version>1.1.86</validator_test_case_version>
<junit_jupiter_version>5.7.1</junit_jupiter_version> <junit_jupiter_version>5.7.1</junit_jupiter_version>
<junit_platform_launcher_version>1.7.1</junit_platform_launcher_version> <junit_platform_launcher_version>1.7.1</junit_platform_launcher_version>
<maven_surefire_version>3.0.0-M5</maven_surefire_version> <maven_surefire_version>3.0.0-M5</maven_surefire_version>
@ -397,6 +397,9 @@
Surefire testing run. This may appear as an error in some IDEs, but it will run regardless. Surefire testing run. This may appear as an error in some IDEs, but it will run regardless.
--> -->
<argLine>${argLine} -Xmx4096m</argLine> <argLine>${argLine} -Xmx4096m</argLine>
<systemPropertyVariables>
<java.locale.providers>COMPAT</java.locale.providers>
</systemPropertyVariables>
<redirectTestOutputToFile>false</redirectTestOutputToFile> <redirectTestOutputToFile>false</redirectTestOutputToFile>
<excludes> <excludes>
<exclude>org/hl7/fhir/validation/cli/**</exclude> <exclude>org/hl7/fhir/validation/cli/**</exclude>