From e7010d7af08c098a7f0dcab4fea3d07e1e4a4f0e Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 15 Sep 2023 22:01:12 -0700 Subject: [PATCH 1/5] Add support for .index.db --- .../misc/NpmPackageVersionConverter.java | 14 +++- .../fhir/r4b/utils/NPMPackageGenerator.java | 8 ++- .../fhir/r5/utils/NPMPackageGenerator.java | 7 +- .../hl7/fhir/utilities/npm/NpmPackage.java | 15 ++++- .../utilities/npm/NpmPackageIndexBuilder.java | 66 +++++++++++++++++-- 5 files changed, 98 insertions(+), 12 deletions(-) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java index 62aa048cd..7684e55a7 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java @@ -2,6 +2,7 @@ package org.hl7.fhir.convertors.misc; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @@ -10,6 +11,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.Map.Entry; import javax.annotation.Nonnull; @@ -35,6 +37,7 @@ import org.hl7.fhir.r5.model.Enumerations.FHIRVersionEnumFactory; import org.hl7.fhir.r5.model.ImplementationGuide; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.utilities.TextFile; +import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonObject; @@ -118,11 +121,11 @@ public class NpmPackageVersionConverter { NpmPackageIndexBuilder indexer = indexers.get(n); if (indexer == null) { indexer = new NpmPackageIndexBuilder(); - indexer.start(); + indexer.start(Utilities.path("[tmp]", "tmp-"+UUID.randomUUID().toString()+".db")); indexers.put(n, indexer); } indexer.seeFile(s, b); - if (!s.equals(".index.json") && !s.equals("package.json")) { + if (!s.equals(".index.json") && !s.equals("package.json") && !s.equals(".index.db")) { TarArchiveEntry entry = new TarArchiveEntry(e.getKey()); entry.setSize(b.length); tar.putArchiveEntry(entry); @@ -137,6 +140,13 @@ public class NpmPackageVersionConverter { tar.putArchiveEntry(entry); tar.write(cnt); tar.closeArchiveEntry(); + cnt = TextFile.fileToBytes(e.getValue().getDbFilename()); + new File(e.getValue().getDbFilename()).delete(); + entry = new TarArchiveEntry(e.getKey() + "/.index.db"); + entry.setSize(cnt.length); + tar.putArchiveEntry(entry); + tar.write(cnt); + tar.closeArchiveEntry(); } byte[] cnt = output.get("package/package.json"); diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/NPMPackageGenerator.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/NPMPackageGenerator.java index 76f569691..ab57c0878 100644 --- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/NPMPackageGenerator.java +++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/NPMPackageGenerator.java @@ -57,6 +57,7 @@ import org.hl7.fhir.r4b.model.Enumeration; import org.hl7.fhir.r4b.model.Enumerations.FHIRVersion; import org.hl7.fhir.r4b.model.ImplementationGuide; import org.hl7.fhir.r4b.model.ImplementationGuide.ImplementationGuideDependsOnComponent; +import org.hl7.fhir.r4b.utils.NPMPackageGenerator.Category; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; @@ -110,6 +111,7 @@ public class NPMPackageGenerator { private JsonObject packageManifest; private NpmPackageIndexBuilder indexer; private String igVersion; + private String indexdb; public NPMPackageGenerator(String destFile, String canonical, String url, PackageType kind, ImplementationGuide ig, Date date, boolean notForPublication) throws FHIRException, IOException { @@ -324,8 +326,9 @@ public class NPMPackageGenerator { bufferedOutputStream = new BufferedOutputStream(OutputStream); gzipOutputStream = new GzipCompressorOutputStream(bufferedOutputStream); tar = new TarArchiveOutputStream(gzipOutputStream); + indexdb = Utilities.path("[tmp]", "tmp-"+UUID.randomUUID().toString()+".db"); indexer = new NpmPackageIndexBuilder(); - indexer.start(); + indexer.start(indexdb); } public void addFile(Category cat, String name, byte[] content) throws IOException { @@ -367,6 +370,9 @@ public class NPMPackageGenerator { private void buildIndexJson() throws IOException { byte[] content = TextFile.stringToBytes(indexer.build(), false); addFile(Category.RESOURCE, ".index.json", content); + content = TextFile.fileToBytes(indexdb); + new File(indexdb).delete(); + addFile(Category.RESOURCE, ".index.db", content); } public String filename() { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java index c036d836a..e7cef5ab5 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java @@ -101,6 +101,7 @@ public class NPMPackageGenerator { private JsonObject packageManifest; private NpmPackageIndexBuilder indexer; private String igVersion; + private String indexdb; public NPMPackageGenerator(String destFile, String canonical, String url, PackageType kind, ImplementationGuide ig, Date date, boolean notForPublication) throws FHIRException, IOException { @@ -315,8 +316,9 @@ public class NPMPackageGenerator { bufferedOutputStream = new BufferedOutputStream(OutputStream); gzipOutputStream = new GzipCompressorOutputStream(bufferedOutputStream); tar = new TarArchiveOutputStream(gzipOutputStream); + indexdb = Utilities.path("[tmp]", "tmp-"+UUID.randomUUID().toString()+".db"); indexer = new NpmPackageIndexBuilder(); - indexer.start(); + indexer.start(indexdb); } @@ -383,6 +385,9 @@ public class NPMPackageGenerator { private void buildIndexJson() throws IOException { byte[] content = TextFile.stringToBytes(indexer.build(), false); addFile(Category.RESOURCE, ".index.json", content); + content = TextFile.fileToBytes(indexdb); + new File(indexdb).delete(); + addFile(Category.RESOURCE, ".index.db", content); } public String filename() { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java index 56f8899b1..d267cb867 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java @@ -52,6 +52,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -598,7 +599,7 @@ public class NpmPackage { public void indexFolder(String desc, NpmPackageFolder folder) throws FileNotFoundException, IOException { List remove = new ArrayList<>(); NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder(); - indexer.start(); + indexer.start(folder.folder != null ? Utilities.path(folder.folder.getAbsolutePath(), ".index.db") : null); for (String n : folder.listFiles()) { if (!indexer.seeFile(n, folder.fetchFile(n))) { remove.add(n); @@ -1076,7 +1077,7 @@ public class NpmPackage { Utilities.createDirectory(pd.getAbsolutePath()); } NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder(); - indexer.start(); + indexer.start(Utilities.path(dir.getAbsolutePath(), n, ".index.db")); for (String s : folder.content.keySet()) { byte[] b = folder.content.get(s); indexer.seeFile(s, b); @@ -1112,7 +1113,8 @@ public class NpmPackage { n = "package/"+n; } NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder(); - indexer.start(); + String filename = Utilities.path("[tmp]", "tmp-"+UUID.randomUUID().toString()+".db"); + indexer.start(filename); for (String s : folder.content.keySet()) { byte[] b = folder.content.get(s); String name = n+"/"+s; @@ -1135,6 +1137,13 @@ public class NpmPackage { tar.putArchiveEntry(entry); tar.write(cnt); tar.closeArchiveEntry(); + cnt = TextFile.fileToBytes(filename); + new File(filename).delete(); + entry = new TarArchiveEntry(n+"/.index.db"); + entry.setSize(cnt.length); + tar.putArchiveEntry(entry); + tar.write(cnt); + tar.closeArchiveEntry(); } byte[] cnt = TextFile.stringToBytes(JsonParser.compose(npm, true), false); TarArchiveEntry entry = new TarArchiveEntry("package/package.json"); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackageIndexBuilder.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackageIndexBuilder.java index 9fcfde2c3..405366add 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackageIndexBuilder.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackageIndexBuilder.java @@ -2,6 +2,11 @@ package org.hl7.fhir.utilities.npm; import java.io.File; import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.TextFile; @@ -13,6 +18,8 @@ import org.hl7.fhir.utilities.json.parser.JsonParser; /** * This class builds the .index.json for a package * + * it also builds a .index.db since that may provide faster access + * * @author grahame * */ @@ -21,14 +28,42 @@ public class NpmPackageIndexBuilder { public static final Integer CURRENT_INDEX_VERSION = 2; private JsonObject index; private JsonArray files; + private Connection conn; + private PreparedStatement psql; + private String dbFilename; - public void start() { + public void start(String filename) { index = new JsonObject(); index.add("index-version", CURRENT_INDEX_VERSION); files = new JsonArray(); index.add("files", files); + + + dbFilename = filename; + if (filename != null) { + try { + new File(filename).delete(); + conn = DriverManager.getConnection("jdbc:sqlite:"+filename); + Statement stmt = conn.createStatement(); + stmt.execute("CREATE TABLE index (\r\n"+ + "FileName nvarchar NOT NULL,\r\n"+ + "ResourceType nvarchar NOT NULL,\r\n"+ + "Id nvarchar NULL,\r\n"+ + "Url nvarchar NULL,\r\n"+ + "Version nvarchar NULL,\r\n"+ + "Kind nvarchar NULL,\r\n"+ + "Type nvarchar NULL,\r\n"+ + "Supplements nvarchar NULL,\r\n"+ + "Content nvarchar NULL,\r\n"+ + "PRIMARY KEY (FileName))\r\n"); + + psql = conn.prepareStatement("Insert into index (FileName, ResourceType, Id, Url, Version, Kind, Type, Supplements, Content) values (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + } catch (Exception e) { + conn = null; + } + } } - + public boolean seeFile(String name, byte[] content) { if (name.endsWith(".json")) { try { @@ -60,6 +95,18 @@ public class NpmPackageIndexBuilder { if (json.hasPrimitive("content")) { fi.add("content", json.asString("content")); } + if (psql != null) { + psql.setString(1, name); // FileName); + psql.setString(2, json.asString("resourceType")); // ResourceType"); + psql.setString(3, json.asString("id")); // Id"); + psql.setString(4, json.asString("url")); // Url"); + psql.setString(5, json.asString("version")); // Version"); + psql.setString(6, json.asString("kind")); // Kind"); + psql.setString(7, json.asString("type")); // Type"); + psql.setString(8, json.asString("supplements")); // Supplements"); + psql.setString(9, json.asString("content")); // Content"); + psql.execute(); + } } } catch (Exception e) { System.out.println("Error parsing "+name+": "+e.getMessage()); @@ -72,6 +119,13 @@ public class NpmPackageIndexBuilder { } public String build() { + try { + if (conn != null) { + conn.close(); + } + } catch (Exception e) { + // nothing + } String res = JsonParser.compose(index, true); index = null; files = null; @@ -95,7 +149,7 @@ public class NpmPackageIndexBuilder { if (!existsFile(folder, "package.json")) { throw new FHIRException("Not a proper package? (can't find package.json)"); } - start(); + start(Utilities.path(folder, ".index.db")); File dir = new File(folder); for (File f : dir.listFiles()) { seeFile(f.getName(), TextFile.fileToBytes(f)); @@ -103,7 +157,6 @@ public class NpmPackageIndexBuilder { TextFile.stringToFile(build(), Utilities.path(folder, ".index.json")); } - private boolean existsFolder(String... args) throws IOException { File f = new File(Utilities.path(args)); return f.exists() && f.isDirectory(); @@ -114,7 +167,6 @@ public class NpmPackageIndexBuilder { return f.exists() && !f.isDirectory(); } - public static void main(String[] args) throws IOException { new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r4.core"); new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r4.examples"); @@ -143,4 +195,8 @@ public class NpmPackageIndexBuilder { new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.core#4.0.1"); } + public String getDbFilename() { + return dbFilename; + } + } \ No newline at end of file From 4d2868f21ea03962b4fed499631da779a2d31adf Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 15 Sep 2023 22:01:30 -0700 Subject: [PATCH 2/5] Add support for validating WG info in HL7 resources --- .../fhir/utilities/i18n/I18nConstants.java | 5 + .../src/main/resources/Messages.properties | 7 +- .../hl7/fhir/validation/BaseValidator.java | 5 + .../instance/InstanceValidator.java | 127 +++++++++++++++--- pom.xml | 2 +- 5 files changed, 128 insertions(+), 18 deletions(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index 2ab5a576a..2f1a15746 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -992,6 +992,11 @@ public class I18nConstants { public static final String BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH = "BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH"; public static final String BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_MULTIPLE_MATCHES = "BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_MULTIPLE_MATCHES"; public static final String BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH_REASON = "BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH_REASON"; + public static final String VALIDATION_HL7_WG_NEEDED = "VALIDATION_HL7_WG_NEEDED"; + public static final String VALIDATION_HL7_WG_UNKNOWN = "VALIDATION_HL7_WG_UNKNOWN"; + public static final String VALIDATION_HL7_PUBLISHER_MISMATCH = "VALIDATION_HL7_PUBLISHER_MISMATCH"; + public static final String VALIDATION_HL7_WG_URL = "VALIDATION_HL7_WG_URL"; + public static final String VALIDATION_HL7_PUBLISHER_MISSING = "VALIDATION_HL7_PUBLISHER_MISSING"; } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 69e3a73b0..1604a41b0 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -1050,5 +1050,8 @@ VALUESET_INC_TOO_MANY_CODES = The value set include has too many codes to valida BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH = The {1} resource did not match any of the allowed profiles (Type {2}: {3}) BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_MULTIPLE_MATCHES = The {1} resource matched more than one of the allowed profiles ({3}) BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH_REASON = The {1} resource did not math the profile {2} because: {3} - - +VALIDATION_HL7_WG_NEEDED = When HL7 is publishing a resource, the owning committee must be stated using the {0} extension +VALIDATION_HL7_WG_UNKNOWN = The nominated WG ''{0}'' is unknown +VALIDATION_HL7_PUBLISHER_MISMATCH = The nominated WG ''{0}'' means that the publisher should be ''{1}'' but ''{2}'' was found +VALIDATION_HL7_WG_URL = The nominated WG ''{0}'' means that the contact url should be ''{1}'' but it was not found +VALIDATION_HL7_PUBLISHER_MISSING = When HL7 is publishing a resource, the publisher must be provided, and for WG ''{0}'' it should be ''{1}'' diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java index 27dad2be2..2dea489eb 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java @@ -1330,6 +1330,11 @@ public class BaseValidator implements IValidationContextResourceLoader { return url != null && url.contains("hl7"); } + protected boolean isHL7Core(Element cr) { + String url = cr.getChildValue("url"); + return url != null && url.startsWith("http://hl7.org/fhir/") && !url.startsWith("http://hl7.org/fhir/test"); + } + public boolean isAllowExamples() { return this.allowExamples; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index a2fffda9e..7412c7263 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -5338,7 +5338,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } public boolean checkSpecials(ValidatorHostContext hostContext, List errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) { - + boolean ok = true; + long t = System.nanoTime(); try { if (VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(element.getType())) { @@ -5350,41 +5351,137 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus); } } + + if (isHL7Core(element)) { + ok = checkPublisherConsistency(errors, element, stack) && ok; + } } if (element.getType().equals(BUNDLE)) { - return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode); + return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode) && ok; } else if (element.getType().equals("Observation")) { - return validateObservation(errors, element, stack); + return validateObservation(errors, element, stack) && ok; } else if (element.getType().equals("Questionnaire")) { - return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaire(errors, element, element, stack); + return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaire(errors, element, element, stack) && ok; } else if (element.getType().equals("QuestionnaireResponse")) { - return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack); + return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack) && ok; } else if (element.getType().equals("Measure")) { - return new MeasureValidator(this).validateMeasure(hostContext, errors, element, stack); + return new MeasureValidator(this).validateMeasure(hostContext, errors, element, stack) && ok; } else if (element.getType().equals("MeasureReport")) { - return new MeasureValidator(this).validateMeasureReport(hostContext, errors, element, stack); + return new MeasureValidator(this).validateMeasureReport(hostContext, errors, element, stack) && ok; } else if (element.getType().equals("CapabilityStatement")) { - return validateCapabilityStatement(errors, element, stack); + return validateCapabilityStatement(errors, element, stack) && ok; } else if (element.getType().equals("CodeSystem")) { - return new CodeSystemValidator(this).validateCodeSystem(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())); + return new CodeSystemValidator(this).validateCodeSystem(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())) && ok; } else if (element.getType().equals("ConceptMap")) { - return new ConceptMapValidator(this).validateConceptMap(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())); + return new ConceptMapValidator(this).validateConceptMap(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())) && ok; } else if (element.getType().equals("SearchParameter")) { - return new SearchParameterValidator(this, fpe).validateSearchParameter(errors, element, stack); + return new SearchParameterValidator(this, fpe).validateSearchParameter(errors, element, stack) && ok; } else if (element.getType().equals("StructureDefinition")) { - return new StructureDefinitionValidator(this, fpe, wantCheckSnapshotUnchanged).validateStructureDefinition(errors, element, stack); + return new StructureDefinitionValidator(this, fpe, wantCheckSnapshotUnchanged).validateStructureDefinition(errors, element, stack) && ok; } else if (element.getType().equals("StructureMap")) { - return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(errors, element, stack); + return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(errors, element, stack) && ok; } else if (element.getType().equals("ValueSet")) { - return new ValueSetValidator(this).validateValueSet(errors, element, stack); + return new ValueSetValidator(this).validateValueSet(errors, element, stack) && ok; } else { - return true; + return ok; } } finally { timeTracker.spec(t); } } + private boolean checkPublisherConsistency(List errors, Element element, NodeStack stack) { + + String pub = element.getNamedChildValue("publisher"); + Base wgT = element.getExtensionValue(ToolingExtensions.EXT_WORKGROUP); + String wg = wgT == null ? null : wgT.primitiveValue(); + List urls = new ArrayList<>(); + for (Element c : element.getChildren("contact")) { + for (Element t : c.getChildren("telecom")) { + if ("url".equals(t.getNamedChildValue("system")) && t.getNamedChildValue("value") != null) { + urls.add(t.getNamedChildValue("value")); + } + } + } + if (rule(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), wg != null, I18nConstants.VALIDATION_HL7_WG_NEEDED, ToolingExtensions.EXT_WORKGROUP)) { + String name = nameForWG(wg); + String url = urlForWG(wg); + if (rule(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), name != null, I18nConstants.VALIDATION_HL7_WG_UNKNOWN, wg)) { + String rpub = "HL7 International / "+name; + if (warning(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), pub != null, I18nConstants.VALIDATION_HL7_PUBLISHER_MISSING, wg, rpub)) { + warningOrError(pub.contains("/"), errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), rpub.equals(pub), I18nConstants.VALIDATION_HL7_PUBLISHER_MISMATCH, wg, rpub, pub); + } + warning(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), + Utilities.startsWithInList(url, urls), I18nConstants.VALIDATION_HL7_WG_URL, wg, url); + return true; + } + } + return false; + } + + private String urlForWG(String wg) { + switch (wg) { + case "cbcc": return "http://www.hl7.org/Special/committees/homehealth"; + case "cds": return "http://www.hl7.org/Special/committees/dss"; + case "cqi": return "http://www.hl7.org/Special/committees/cqi"; + case "cg": return "http://www.hl7.org/Special/committees/clingenomics"; + case "dev": return "http://www.hl7.org/Special/committees/healthcaredevices"; + case "ehr": return "http://www.hl7.org/special/committees/ehr"; + case "fhir": return "http://www.hl7.org/Special/committees/fiwg"; + case "fm": return "http://www.hl7.org/Special/committees/fm"; + case "hsi": return "http://www.hl7.org/Special/committees/hsi"; + case "ii": return "http://www.hl7.org/Special/committees/imagemgt"; + case "inm": return "http://www.hl7.org/special/committees/inm"; + case "mnm": return "http://www.hl7.org/special/committees/mnm"; + case "its": return "http://www.hl7.org/special/committees/xml"; + case "oo": return "http://www.hl7.org/Special/committees/orders"; + case "pa": return "http://www.hl7.org/Special/committees/pafm"; + case "pc": return "http://www.hl7.org/Special/committees/patientcare"; + case "pe": return "http://www.hl7.org/Special/committees/patientempowerment"; + case "pher": return "http://www.hl7.org/Special/committees/pher"; + case "phx": return "http://www.hl7.org/Special/committees/medication"; + case "brr": return "http://www.hl7.org/Special/committees/rcrim"; + case "sd": return "http://www.hl7.org/Special/committees/structure"; + case "sec": return "http://www.hl7.org/Special/committees/secure"; + case "us": return "http://www.hl7.org/Special/Committees/usrealm"; + case "vocab": return "http://www.hl7.org/Special/committees/Vocab"; + case "aid": return "http://www.hl7.org/Special/committees/java"; + } + return null; + } + + private String nameForWG(String wg) { + switch (wg) { + + case "cbcc": return "Community Based Collaborative Care"; + case "cds": return "Clinical Decision Support"; + case "cqi": return "Clinical Quality Information"; + case "cg": return "Clinical Genomics"; + case "dev": return "Health Care Devices"; + case "ehr": return "Electronic Health Records"; + case "fhir": return "FHIR Infrastructure"; + case "fm": return "Financial Management"; + case "hsi": return "Health Standards Integration"; + case "ii": return "Imaging Integration"; + case "inm": return "Infrastructure And Messaging"; + case "mnm": return "Modeling and Methodology"; + case "its": return "Implementable Technology Specifications"; + case "oo": return "Orders and Observations"; + case "pa": return "Patient Administration"; + case "pc": return "Patient Care"; + case "pe": return "Patient Empowerment"; + case "pher": return "Public Health and Emergency Response"; + case "phx": return "Pharmacy"; + case "brr": return "Biomedical Research and Regulation"; + case "sd": return "Structured Documents"; + case "sec": return "Security"; + case "us": return "US Realm Taskforce"; + case "vocab": return "Terminology Infrastructure"; + case "aid": return "Application Implementation and Design"; + } + return null; + } + private boolean statusCodesConsistent(String status, String standardsStatus) { switch (standardsStatus) { case "draft": return Utilities.existsInList(status, "draft"); diff --git a/pom.xml b/pom.xml index 9598fa2c4..b35dce8b1 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 32.0.1-jre 6.4.1 - 1.4.4 + 1.4.5-SNAPSHOT 2.15.2 5.9.2 1.8.2 From 3681614ce348a8c74ae5626725288fc25667305b Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 15 Sep 2023 22:08:35 -0700 Subject: [PATCH 3/5] bug fix --- .../org/hl7/fhir/utilities/npm/NpmPackage.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java index d267cb867..b56b9a8c2 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java @@ -1137,13 +1137,16 @@ public class NpmPackage { tar.putArchiveEntry(entry); tar.write(cnt); tar.closeArchiveEntry(); - cnt = TextFile.fileToBytes(filename); - new File(filename).delete(); - entry = new TarArchiveEntry(n+"/.index.db"); - entry.setSize(cnt.length); - tar.putArchiveEntry(entry); - tar.write(cnt); - tar.closeArchiveEntry(); + var file = new File(filename); + if (file.exists()) { + cnt = TextFile.fileToBytes(file); + file.delete(); + entry = new TarArchiveEntry(n+"/.index.db"); + entry.setSize(cnt.length); + tar.putArchiveEntry(entry); + tar.write(cnt); + tar.closeArchiveEntry(); + } } byte[] cnt = TextFile.stringToBytes(JsonParser.compose(npm, true), false); TarArchiveEntry entry = new TarArchiveEntry("package/package.json"); From ea7cd290a85f386f4c3b18103c53ddb20d153c54 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 17 Sep 2023 15:45:02 +1000 Subject: [PATCH 4/5] More performance improvements for JsonParser --- .../hl7/fhir/r5/elementmodel/JsonParser.java | 102 ++++++++++-------- .../utilities/json/model/JsonProperty.java | 10 +- 2 files changed, 67 insertions(+), 45 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java index a447095f0..8a2463608 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java @@ -213,55 +213,77 @@ public class JsonParser extends ParserBase { // save time refetching these if we're in a loop properties = element.getProperty().getChildProperties(element.getName(), null); } - Map recognisedChildren = processChildren(errors, path, object); + processChildren(errors, path, object); - // note that we do not trouble ourselves to maintain the wire format order here // first pass: process the properties for (Property property : properties) { - parseChildItem(errors, path, recognisedChildren, element, property); + parseChildItem(errors, path, object.getProperties(), element, property); } - // second pass: check for things not processed - checkNotProcessed(errors, path, element, hasResourceType, recognisedChildren); + // second pass: check for things not processed (including duplicates) + checkNotProcessed(errors, path, element, hasResourceType, object.getProperties()); if (object.isExtraComma()) { logError(errors, "2022-11-26", object.getEnd().getLine(), object.getEnd().getCol(), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR); } return properties; } - private void checkNotProcessed(List errors, String path, Element element, boolean hasResourceType, Map recognisedChildren) { + private void checkNotProcessed(List errors, String path, Element element, boolean hasResourceType, List children) { if (policy != ValidationPolicy.NONE) { - for (Entry e : recognisedChildren.entrySet()) { - if (e.getValue().getTag() == 0) { - StructureDefinition sd = element.getProperty().isLogical() ? contextUtilities.fetchByJsonName(e.getKey()) : null; + for (JsonProperty e : children) { + if (e.getTag() == 0) { + StructureDefinition sd = element.getProperty().isLogical() ? contextUtilities.fetchByJsonName(e.getName()) : null; if (sd != null) { Property property = new Property(context, sd.getSnapshot().getElementFirstRep(), sd, element.getProperty().getUtils()); - parseChildItem(errors, path, recognisedChildren, element, property); - } else if ("fhir_comments".equals(e.getKey()) && (VersionUtilities.isR2BVer(context.getVersion()) || VersionUtilities.isR2Ver(context.getVersion()))) { - if (!e.getValue().getValue().isJsonArray()) { - logError(errors, "2022-12-17", line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, e.getValue().getValue().type().toName()), IssueSeverity.ERROR); + parseChildItem(errors, path, children, element, property); + } else if ("fhir_comments".equals(e.getName()) && (VersionUtilities.isR2BVer(context.getVersion()) || VersionUtilities.isR2Ver(context.getVersion()))) { + if (!e.getValue().isJsonArray()) { + logError(errors, "2022-12-17", line(e.getValue()), col(e.getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, e.getValue().type().toName()), IssueSeverity.ERROR); } else { - for (JsonElement c : e.getValue().getValue().asJsonArray()) { + for (JsonElement c : e.getValue().asJsonArray()) { if (!c.isJsonString()) { - logError(errors, "2022-12-17", line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, c.type().toName()), IssueSeverity.ERROR); + logError(errors, "2022-12-17", line(e.getValue()), col(e.getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, c.type().toName()), IssueSeverity.ERROR); } else { element.getComments().add(c.asString()); } } } - } else if (hasResourceType && "resourceType".equals(e.getKey())) { + } else if (hasResourceType && "resourceType".equals(e.getName())) { // nothing } else { - logError(errors, ValidationMessage.NO_RULE_DATE, line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_, e.getKey()), IssueSeverity.ERROR); + JsonProperty p = getFoundJsonPropertyByName(e.getName(), children); + if (p != null) { + logError(errors, "2022-11-26", line(e.getValue()), col(e.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.DUPLICATE_JSON_PROPERTY, e.getName()), IssueSeverity.ERROR); + } else { + logError(errors, ValidationMessage.NO_RULE_DATE, line(e.getValue()), col(e.getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_, e.getName()), IssueSeverity.ERROR); + } } } } - } + } } - private Map processChildren(List errors, String path, JsonObject object) { - Map recognisedChildren = new HashMap<>(); - Set unique = new HashSet<>(); + private JsonProperty getFoundJsonPropertyByName(String name, List children) { + int hash = name.hashCode(); + for (JsonProperty p : children) { + if (p.getTag() == 1 && hash == p.getNameHash()) { + return p; + } + } + return null; + } + + private JsonProperty getJsonPropertyByName(String name, List children) { + int hash = name.hashCode(); + for (JsonProperty p : children) { + if (p.getTag() == 0 && hash == p.getNameHash()) { + return p; + } + } + return null; + } + + private void processChildren(List errors, String path, JsonObject object) { for (JsonProperty p : object.getProperties()) { if (p.isUnquotedName()) { logError(errors, "2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_NO_QUOTES, p.getName()), IssueSeverity.ERROR); @@ -269,20 +291,13 @@ public class JsonParser extends ParserBase { if (p.isNoComma()) { logError(errors, "2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_MISSING), IssueSeverity.ERROR); } - if (unique.contains(p.getName())) { - logError(errors, "2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.DUPLICATE_JSON_PROPERTY, p.getName()), IssueSeverity.ERROR); - } else { - unique.add(p.getName()); - recognisedChildren.put(p.getName(), p); - } } - return recognisedChildren; } - public void parseChildItem(List errors, String path, Map children, Element context, Property property) { + public void parseChildItem(List errors, String path, List children, Element context, Property property) { + JsonProperty jp = getJsonPropertyByName(property.getJsonName(), children); if (property.isChoice() || property.getDefinition().getPath().endsWith("data[x]")) { if (property.isJsonPrimitiveChoice()) { - JsonProperty jp = children.get(property.getJsonName()); if (jp != null) { jp.setTag(1); JsonElement je = jp.getValue(); @@ -291,7 +306,7 @@ public class JsonParser extends ParserBase { logError(errors, ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE, describeType(je), property.getName(), property.typeSummary()), IssueSeverity.ERROR); } else if (property.hasType(type)) { Property np = new Property(property.getContext(), property.getDefinition(), property.getStructure(), property.getUtils(), type); - parseChildPrimitive(errors, children, context, np, path, property.getName(), false); + parseChildPrimitive(errors, jp, getJsonPropertyByName("_"+property.getJsonName(), children), context, np, path, property.getName(), false); } else { logError(errors, ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE_WRONG, describeType(je), property.getName(), type, property.typeSummary()), IssueSeverity.ERROR); } @@ -299,19 +314,21 @@ public class JsonParser extends ParserBase { } else { for (TypeRefComponent type : property.getDefinition().getType()) { String eName = property.getJsonName().substring(0, property.getName().length()-3) + Utilities.capitalize(type.getWorkingCode()); - if (!isPrimitive(type.getWorkingCode()) && children.containsKey(eName)) { - parseChildComplex(errors, path, children, context, property, eName, false); + jp = getJsonPropertyByName(eName, children); + JsonProperty jp1 = getJsonPropertyByName("_"+eName, children); + if (!isPrimitive(type.getWorkingCode()) && jp != null) { + parseChildComplex(errors, path, jp, context, property, eName, false); break; - } else if (isPrimitive(type.getWorkingCode()) && (children.containsKey(eName) || children.containsKey("_"+eName))) { - parseChildPrimitive(errors, children, context, property, path, eName, false); + } else if (isPrimitive(type.getWorkingCode()) && (jp != null || jp1 != null)) { + parseChildPrimitive(errors, jp, jp1, context, property, path, eName, false); break; } } } } else if (property.isPrimitive(property.getType(null))) { - parseChildPrimitive(errors, children, context, property, path, property.getJsonName(), property.hasJsonName()); - } else if (children.containsKey(property.getJsonName())) { - parseChildComplex(errors, path, children, context, property, property.getJsonName(), property.hasJsonName()); + parseChildPrimitive(errors, jp, getJsonPropertyByName("_"+property.getJsonName(), children), context, property, path, property.getJsonName(), property.hasJsonName()); + } else if (jp != null) { + parseChildComplex(errors, path, jp, context, property, property.getJsonName(), property.hasJsonName()); } } @@ -335,10 +352,9 @@ public class JsonParser extends ParserBase { } } - private void parseChildComplex(List errors, String path, Map children, Element element, Property property, String name, boolean isJsonName) throws FHIRException { + private void parseChildComplex(List errors, String path, JsonProperty p, Element element, Property property, String name, boolean isJsonName) throws FHIRException { String npath = path+"."+property.getName(); String fpath = element.getPath()+"."+property.getName(); - JsonProperty p = children.get(name); if (p != null) { p.setTag(1); } JsonElement e = p == null ? null : p.getValue(); if (property.isList() && !property.isJsonKeyArray() && (e instanceof JsonArray)) { @@ -533,11 +549,11 @@ public class JsonParser extends ParserBase { return e.type().toName(); } - private void parseChildPrimitive(List errors, Map children, Element element, Property property, String path, String name, boolean isJsonName) throws FHIRException { +// JsonProperty main = children.containsKey(name) ? children.get(name) : null; +// JsonProperty fork = children.containsKey("_"+name) ? children.get("_"+name) : null; + private void parseChildPrimitive(List errors, JsonProperty main, JsonProperty fork, Element element, Property property, String path, String name, boolean isJsonName) throws FHIRException { String npath = path+"."+property.getName(); String fpath = element.getPath()+"."+property.getName(); - JsonProperty main = children.containsKey(name) ? children.get(name) : null; - JsonProperty fork = children.containsKey("_"+name) ? children.get("_"+name) : null; if (main != null) { main.setTag(1); } if (fork != null) { fork.setTag(1); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/model/JsonProperty.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/model/JsonProperty.java index c18431d97..61daaabf8 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/model/JsonProperty.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/model/JsonProperty.java @@ -3,16 +3,18 @@ package org.hl7.fhir.utilities.json.model; public class JsonProperty { private String name; private JsonElement value; + private int nameHash; // for faster name comparison boolean noComma; // parse in Json5 mode, but records this so the validator can complain boolean unquotedName; boolean unquotedValue; - private int tag; + private int tag; // used for status in validator - faster parsing public JsonProperty(String name, JsonElement value) { super(); this.name = name; + this.nameHash = name.hashCode(); this.value = value; } @@ -64,5 +66,9 @@ public class JsonProperty { public void setTag(int tag) { this.tag = tag; } - + + public int getNameHash() { + return nameHash; + } + } From 0565b27f02eb5201160d81e1a2df5c49be3a18d2 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 17 Sep 2023 16:54:47 +1000 Subject: [PATCH 5/5] more performance improvements --- .../hl7/fhir/r5/elementmodel/JsonParser.java | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java index 8a2463608..103423969 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java @@ -121,7 +121,7 @@ public class JsonParser extends ParserBase { @Override public List parse(InputStream inStream) throws IOException, FHIRException { -// long start = System.currentTimeMillis(); + long start = System.currentTimeMillis(); byte[] content = TextFile.streamToBytes(inStream); NamedElement ctxt = new NamedElement("focus", "json", content); @@ -145,8 +145,8 @@ public class JsonParser extends ParserBase { List res = new ArrayList<>(); res.add(ctxt); -// long t=System.currentTimeMillis()-start; -// System.out.println("json parser: "+(t)+": "+content.length+(t == 0 ? "" : " @ "+(content.length / t))); + long t=System.currentTimeMillis()-start; + System.out.println("json parser: "+(t)+"ms, "+(content.length/1024)+"kb "+(t == 0 ? "" : " @ "+(content.length / t)+"kb/s")); return res; } @@ -222,6 +222,8 @@ public class JsonParser extends ParserBase { // second pass: check for things not processed (including duplicates) checkNotProcessed(errors, path, element, hasResourceType, object.getProperties()); + + if (object.isExtraComma()) { logError(errors, "2022-11-26", object.getEnd().getLine(), object.getEnd().getCol(), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR); } @@ -282,7 +284,16 @@ public class JsonParser extends ParserBase { } return null; } - + + private JsonProperty getJsonPropertyByBaseName(String name, List children) { + for (JsonProperty p : children) { + if (p.getTag() == 0 && p.getName().startsWith(name)) { + return p; + } + } + return null; + } + private void processChildren(List errors, String path, JsonObject object) { for (JsonProperty p : object.getProperties()) { if (p.isUnquotedName()) { @@ -311,17 +322,22 @@ public class JsonParser extends ParserBase { logError(errors, ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE_WRONG, describeType(je), property.getName(), type, property.typeSummary()), IssueSeverity.ERROR); } } - } else { - for (TypeRefComponent type : property.getDefinition().getType()) { - String eName = property.getJsonName().substring(0, property.getName().length()-3) + Utilities.capitalize(type.getWorkingCode()); - jp = getJsonPropertyByName(eName, children); - JsonProperty jp1 = getJsonPropertyByName("_"+eName, children); - if (!isPrimitive(type.getWorkingCode()) && jp != null) { - parseChildComplex(errors, path, jp, context, property, eName, false); - break; - } else if (isPrimitive(type.getWorkingCode()) && (jp != null || jp1 != null)) { - parseChildPrimitive(errors, jp, jp1, context, property, path, eName, false); - break; + } else { + String baseName = property.getJsonName().substring(0, property.getName().length()-3); + jp = getJsonPropertyByBaseName(baseName, children); + if (jp != null) { + for (TypeRefComponent type : property.getDefinition().getType()) { + String eName = baseName + Utilities.capitalize(type.getWorkingCode()); + if (jp.getName().equals(eName)) { + JsonProperty jp1 = getJsonPropertyByName("_"+eName, children); + if (!isPrimitive(type.getWorkingCode()) && jp != null) { + parseChildComplex(errors, path, jp, context, property, eName, false); + break; + } else if (isPrimitive(type.getWorkingCode()) && (jp != null || jp1 != null)) { + parseChildPrimitive(errors, jp, jp1, context, property, path, eName, false); + break; + } + } } } } @@ -332,6 +348,7 @@ public class JsonParser extends ParserBase { } } + private String getTypeFromJsonType(JsonElement je) { if (je.isJsonPrimitive()) { JsonPrimitive p = je.asJsonPrimitive();