Skip to content

Commit f2c11ee

Browse files
committed
Pull request #158: Feature/migration jsv 2.0.0
Merge in ITB/json-validator from feature/migration_jsv_2.0.0 to development * commit '16fc52c19bd93332b54b158accdcbf764b17e78a': Upgrade Spring Boot to v3.5.7 and Tomcat to v10.1.48 Upgraded json-schema-validator to v2.0.0
2 parents e720c92 + 16fc52c commit f2c11ee

28 files changed

Lines changed: 1882 additions & 1796 deletions

NOTICE.md

Lines changed: 40 additions & 40 deletions
Large diffs are not rendered by default.

jsonvalidator-common/src/main/java/eu/europa/ec/itb/json/validation/JSONValidator.java

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@
2424
import com.gitb.vs.ValidateRequest;
2525
import com.gitb.vs.ValidationResponse;
2626
import com.networknt.schema.*;
27+
import com.networknt.schema.Error;
28+
import com.networknt.schema.dialect.Dialects;
2729
import com.networknt.schema.i18n.ResourceBundleMessageSource;
28-
import com.networknt.schema.serialization.JsonNodeReader;
30+
import com.networknt.schema.path.PathType;
31+
import com.networknt.schema.serialization.DefaultNodeReader;
32+
import com.networknt.schema.serialization.NodeReader;
2933
import com.networknt.schema.utils.JsonNodes;
3034
import eu.europa.ec.itb.json.DomainConfig;
3135
import eu.europa.ec.itb.validation.commons.*;
@@ -35,7 +39,7 @@
3539
import eu.europa.ec.itb.validation.plugin.PluginManager;
3640
import eu.europa.ec.itb.validation.plugin.ValidationPlugin;
3741
import org.apache.commons.io.FileUtils;
38-
import org.apache.commons.lang3.Strings;
42+
import org.apache.commons.lang3.StringUtils;
3943
import org.apache.commons.lang3.tuple.Pair;
4044
import org.slf4j.Logger;
4145
import org.slf4j.LoggerFactory;
@@ -311,29 +315,24 @@ private void addBranchErrors(List<Message> aggregatedMessages, List<Message> bra
311315
* @param path The schema path.
312316
* @return The parsed schema and JSON node reader to use.
313317
*/
314-
private Pair<JsonSchema, JsonNodeReader> readSchema(Path path) {
318+
private Pair<Schema, NodeReader> readSchema(Path path) {
315319
try {
316320
var jsonNode = objectMapper.readTree(path.toFile());
317-
var jsonSchemaVersion = JsonSchemaFactory.checkVersion(SpecVersionDetector.detect(jsonNode));
318-
var metaSchema = jsonSchemaVersion.getInstance();
319-
/*
320-
* The schema factory is created per validation. This is done to avoid caching of schemas across validations that
321-
* may be remotely loaded or schemas that are user-provided. In addition, it allows us to treat schemas that
322-
* may use different specification versions.
323-
*/
324321
var jsonReader = getJsonReader();
325-
var schemaFactory = JsonSchemaFactory.builder()
326-
.schemaLoaders(schemaLoaders -> schemaLoaders.add(new LocalSchemaResolver(specs.getDomainConfig(), localSchemaCache)))
327-
.metaSchema(metaSchema)
328-
.defaultMetaSchemaIri(metaSchema.getIri())
329-
.jsonNodeReader(jsonReader)
330-
.build();
331-
var schemaConfig = SchemaValidatorsConfig.builder()
322+
var registryConfig = SchemaRegistryConfig.builder()
323+
.cacheRefs(false)
332324
.pathType(PathType.JSON_POINTER)
333325
.locale(specs.getLocalisationHelper().getLocale())
334326
.messageSource(new ResourceBundleMessageSource("i18n/jsv-messages"))
335327
.build();
336-
return Pair.of(schemaFactory.getSchema(jsonNode, schemaConfig), jsonReader);
328+
var registry = SchemaRegistry.builder()
329+
.defaultDialectId(Dialects.getDraft202012().getId())
330+
.schemaRegistryConfig(registryConfig)
331+
.schemaCacheEnabled(false)
332+
.nodeReader(jsonReader)
333+
.resourceLoaders(builder -> builder.add(new LocalSchemaResolver(specs.getDomainConfig(), localSchemaCache)))
334+
.build();
335+
return Pair.of(registry.getSchema(jsonNode), jsonReader);
337336
} catch (IOException e) {
338337
throw new ValidatorException("validator.label.exception.failedToParseJSONSchema", e, e.getMessage());
339338
}
@@ -344,20 +343,20 @@ private Pair<JsonSchema, JsonNodeReader> readSchema(Path path) {
344343
*
345344
* @return The reader.
346345
*/
347-
private JsonNodeReader getJsonReader() {
348-
var jsonReaderBuilder = JsonNodeReader.builder();
346+
private NodeReader getJsonReader() {
347+
var jsonReaderBuilder = DefaultNodeReader.builder();
349348
if (!specs.isLocationAsPointer()) {
350349
jsonReaderBuilder = jsonReaderBuilder.locationAware();
351350
}
352351
return jsonReaderBuilder.build();
353352
}
354353

355-
private Function<ValidationMessage, String> getLocationMapper() {
354+
private Function<Error, String> getLocationMapper() {
356355
if (specs.isLocationAsPointer()) {
357356
return msg -> msg.getInstanceLocation().toString();
358357
} else {
359358
return msg -> {
360-
var nodeLocation = JsonNodes.tokenLocationOf(msg.getInstanceNode());
359+
var nodeLocation = JsonNodes.tokenStreamLocationOf(msg.getInstanceNode());
361360
int lineNumber = 0;
362361
if (nodeLocation != null && nodeLocation.getLineNr() > 0) {
363362
lineNumber = nodeLocation.getLineNr();
@@ -376,18 +375,30 @@ private Function<ValidationMessage, String> getLocationMapper() {
376375
private List<Message> validateAgainstSchema(File schemaFile) {
377376
var schemaInfo = readSchema(schemaFile.toPath());
378377
var locationMapper = getLocationMapper();
379-
return schemaInfo.getLeft().validate(getContentNode(schemaInfo.getRight())).stream().map(message -> new Message(Strings.CS.removeStart(message.getMessage(), "[] "), locationMapper.apply(message))).toList();
378+
return schemaInfo.getLeft().validate(getContentNode(schemaInfo.getRight())).stream().map(error -> {
379+
String pathPrefix = null;
380+
if (error.getInstanceLocation() != null) {
381+
pathPrefix = error.getInstanceLocation().toString();
382+
} else if (error.getSchemaLocation() != null) {
383+
pathPrefix = error.getSchemaLocation().toString();
384+
}
385+
if (StringUtils.isNotEmpty(pathPrefix)) {
386+
return new Message("["+pathPrefix+"] "+error.getMessage(), locationMapper.apply(error));
387+
} else {
388+
return new Message(error.getMessage(), locationMapper.apply(error));
389+
}
390+
}).toList();
380391
}
381392

382393
/**
383394
* Parse the JSON node for the provided input file.
384395
*
385396
* @return The JSON node.
386397
*/
387-
private JsonNode getContentNode(JsonNodeReader reader) {
398+
private JsonNode getContentNode(NodeReader reader) {
388399
if (contentNode == null) {
389400
if (reader == null) {
390-
reader = JsonNodeReader.builder().build();
401+
reader = DefaultNodeReader.builder().build();
391402
}
392403
try (var input = Files.newInputStream(specs.getInputFileToUse().toPath())) {
393404
contentNode = reader.readTree(input, specs.isYaml()?InputFormat.YAML:InputFormat.JSON);

jsonvalidator-common/src/main/java/eu/europa/ec/itb/json/validation/LocalSchemaResolver.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
import com.networknt.schema.AbsoluteIri;
1919
import com.networknt.schema.resource.InputStreamSource;
20-
import com.networknt.schema.resource.SchemaLoader;
21-
import com.networknt.schema.resource.UriSchemaLoader;
20+
import com.networknt.schema.resource.IriResourceLoader;
21+
import com.networknt.schema.resource.ResourceLoader;
2222
import eu.europa.ec.itb.json.DomainConfig;
2323
import org.apache.commons.lang3.Strings;
2424
import org.slf4j.Logger;
@@ -29,11 +29,10 @@
2929
/**
3030
* Custom schema resolver that loads schemas defined as local references.
3131
*/
32-
public class LocalSchemaResolver implements SchemaLoader {
32+
public class LocalSchemaResolver implements ResourceLoader {
3333

3434
private static final Logger LOG = LoggerFactory.getLogger(LocalSchemaResolver.class);
3535

36-
private final UriSchemaLoader uriSchemaLoader = new UriSchemaLoader();
3736
private final DomainConfig domain;
3837
private final LocalSchemaCache localSchemaCache;
3938

@@ -55,15 +54,16 @@ public LocalSchemaResolver(DomainConfig domain, LocalSchemaCache localSchemaCach
5554
* @return The resolved schema or null if none could be resolved from the configured shared schema references.
5655
*/
5756
@Override
58-
public InputStreamSource getSchema(AbsoluteIri absoluteIri) {
57+
public InputStreamSource getResource(AbsoluteIri absoluteIri) {
5958
String idToCheck = Strings.CS.appendIfMissing(absoluteIri.toString(), "#");
6059
var schema = localSchemaCache.getSchemaForId(domain, idToCheck);
6160
if (schema.isEmpty()) {
6261
LOG.debug("Schema with URI {} not found locally. Looking up remotely.", absoluteIri);
63-
return uriSchemaLoader.getSchema(absoluteIri);
62+
return IriResourceLoader.getInstance().getResource(absoluteIri);
6463
} else {
6564
LOG.debug("Schema with URI {} found locally.", absoluteIri);
6665
return () -> Files.newInputStream(schema.get());
6766
}
6867
}
68+
6969
}
Lines changed: 72 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,73 @@
1-
$ref = [{0}] Error with referenced schema.
2-
const = [{0}] Expected value ''{1}''.
3-
contains=[{0}] No element was found passing these validations: {2}
4-
dependencies = [{0}] Error with dependencies {1}.
5-
dependentRequired = [{0}] Property ''{1}'' is missing which is required because ''{2}'' is present.
6-
dependentSchemas = [{0}] Error with dependent schemas {1}.
7-
enum = [{0}] Unexpected value found. Valid values are {1}.
8-
format = [{0}] Value does not match the {1} pattern {2}
9-
id = [{0}] ''{1}'' is an invalid segment for URI {2}
10-
maxItems = [{0}] The size of the array must be at most {1}.
11-
minItems = [{0}] The size of the array must be at least {1}.
12-
maxLength = [{0}] The value''s length must be at most {1}.
13-
minLength = [{0}] The value''s length must be at least {1}.
14-
maxProperties = [{0}] The number of defined properties must be at most {1}.
15-
minProperties = [{0}] The number of defined properties must be at least {1}.
16-
maximum = [{0}] Value must be less than or equal to {1}.
17-
minimum = [{0}] Value must be greater than or equal to {1}.
18-
exclusiveMaximum = [{0}] Value must be less than {1}.
19-
exclusiveMinimum = [{0}] Value must be greater than {1}.
20-
multipleOf = [{0}] Value must be a multiple of {1}.
21-
pattern = [{0}] Value does not match the regex pattern {1}.
22-
patternProperties = [{0}] The object does not match defined property patterns.
23-
prefixItems = [{0}] No validator found at this index.
24-
properties = [{0}] The object has an error in its defined properties.
25-
readOnly = [{0}] Property is readonly and cannot be changed.
26-
required = [{0}] Missing required property ''{1}''.
27-
type = [{0}] Expected {2} but found {1}.
28-
unionType = [{0}] Expected {2} but found {1}.
29-
uniqueItems = [{0}] The items in the array must be unique.
30-
contains.max = [{0}] Must contain fewer than {1} element(s) that pass these validations: {2}
31-
contains.min = [{0}] Must contain at least {1} element(s) that pass these validations: {2}
32-
maxContains = [{0}] Must be a non-negative integer in {1}.
33-
minContains = [{0}] Must be a non-negative integer in {1}.
34-
minContainsVsMaxContains = [{0}] minContains must less than or equal to maxContains in {1}.
35-
writeOnly = [{0}] Write-only field that cannot appear in the data.
36-
contentEncoding = [{0}] Does not match content encoding {1}.
1+
$ref = Error with referenced schema.
2+
const = Expected value ''{0}''.
3+
contains=No element was found passing these validations: {1}
4+
dependencies = Error with dependencies {0}.
5+
dependentRequired = Property ''{0}'' is missing which is required because ''{1}'' is present.
6+
dependentSchemas = Error with dependent schemas {0}.
7+
enum = Unexpected value found. Valid values are {0}.
8+
format = Value does not match the {0} pattern {1}
9+
id = ''{0}'' is an invalid segment for URI {1}
10+
maxItems = The size of the array must be at most {0}.
11+
minItems = The size of the array must be at least {0}.
12+
maxLength = The value''s length must be at most {0}.
13+
minLength = The value''s length must be at least {0}.
14+
maxProperties = The number of defined properties must be at most {0}.
15+
minProperties = The number of defined properties must be at least {0}.
16+
maximum = Value must be less than or equal to {0}.
17+
minimum = Value must be greater than or equal to {0}.
18+
exclusiveMaximum = Value must be less than {0}.
19+
exclusiveMinimum = Value must be greater than {0}.
20+
multipleOf = Value must be a multiple of {0}.
21+
pattern = Value does not match the regex pattern {0}.
22+
patternProperties = The object does not match defined property patterns.
23+
prefixItems = No validator found at this index.
24+
properties = The object has an error in its defined properties.
25+
readOnly = Property is readonly and cannot be changed.
26+
required = Missing required property ''{0}''.
27+
type = Expected {1} but found {0}.
28+
unionType = Expected {1} but found {0}.
29+
uniqueItems = The items in the array must be unique.
30+
contains.max = Must contain fewer than {0} element(s) that pass these validations: {1}
31+
contains.min = Must contain at least {0} element(s) that pass these validations: {1}
32+
maxContains = Must be a non-negative integer in {0}.
33+
minContains = Must be a non-negative integer in {0}.
34+
minContainsVsMaxContains = minContains must less than or equal to maxContains in {0}.
35+
writeOnly = Write-only field that cannot appear in the data.
36+
contentEncoding = Does not match content encoding {0}.
3737
contentMediaType = {0} is not a content media type.
38-
additionalProperties = [{0}] Property ''{1}'' not defined in the schema and additional properties are not allowed.
39-
allOf = [{0}] Node must be valid for all its defined schemas {1}.
40-
anyOf = [{0}] Node must be valid for any of its defined schemas {1}.
41-
oneOf = [{0}] Node must be valid for only one of its defined schemas, but it was valid for {1} schemas.
42-
oneOf.indexes = [{0}] Node must be valid for only one of its defined schemas, but it was valid for {1} schemas with indexes ''{2}''.
43-
false = [{0}] Considered by default as invalid.
44-
items = [{0}] Index ''{1}'' is not defined in the schema and additional items are not allowed.
45-
not = [{0}] Node must not be valid for the schema {1}.
46-
notAllowed = [{0}] Property ''{1}'' is not allowed here.
47-
propertyNames = [{0}] Property name ''{1}'' is invalid: {2}
48-
unevaluatedProperties = [{0}] Property ''{1}'' must not be unevaluated.
49-
unevaluatedItems=[{0}] Item at index {1} must not be unevaluated or must match the schema for unevaluated items.
50-
additionalItems = [{0}] Index ''{1}'' is not defined in the schema and additional items are not allowed.
51-
format.date = [{0}] Value does not match the {1} pattern (must be a valid RFC 3339 full-date).
52-
format.date-time = [{0}] Value does not match the {1} pattern (must be a valid RFC 3339 date-time).
53-
format.duration = [{0}] Value does not match the {1} pattern (must be a valid ISO 8601 duration).
54-
format.email = [{0}] Value does not match the {1} pattern (must be a valid RFC 5321 Mailbox).
55-
format.ipv4 = [{0}] Value does not match the {1} pattern (must be a valid RFC 2673 IP address).
56-
format.ipv6 = [{0}] Value does not match the {1} pattern (must be a valid RFC 4291 IP address).
57-
format.idn-email = [{0}] Value does not match the {1} pattern (must be a valid RFC 6531 Mailbox).
58-
format.idn-hostname = [{0}] Value does not match the {1} pattern (must be a valid RFC 5890 internationalized hostname).
59-
format.iri = [{0}] Value does not match the {1} pattern (must be a valid RFC 3987 IRI).
60-
format.iri-reference = [{0}] Value does not match the {1} pattern (must be a valid RFC 3987 IRI-reference).
61-
format.uri = [{0}] Value does not match the {1} pattern (must be a valid RFC 3986 URI).
62-
format.uri-reference = [{0}] Value does not match the {1} pattern (must be a valid RFC 3986 URI-reference).
63-
format.uri-template = [{0}] Value does not match the {1} pattern (must be a valid RFC 6570 URI Template).
64-
format.uuid = [{0}] Value does not match the {1} pattern (must be a valid RFC 4122 UUID).
65-
format.regex = [{0}] Value does not match the {1} pattern (must be a valid ECMA-262 regular expression).
66-
format.time = [{0}] Value does not match the {1} pattern (must be a valid RFC 3339 time).
67-
format.hostname = [{0}] Value does not match the {1} pattern (must be a valid RFC 1123 host name).
68-
format.json-pointer = [{0}] Value does not match the {1} pattern (must be a valid RFC 6901 JSON Pointer).
69-
format.relative-json-pointer = [{0}] Value does not match the {1} pattern (must be a valid IETF Relative JSON Pointer).
70-
format.unknown = [{0}] has an unknown format ''{1}''.
38+
additionalProperties = Property ''{0}'' not defined in the schema and additional properties are not allowed.
39+
allOf = Node must be valid for all its defined schemas {0}.
40+
anyOf = Node must be valid for any of its defined schemas {0}.
41+
oneOf = Node must be valid for only one of its defined schemas, but it was valid for {0} schemas.
42+
oneOf.indexes = Node must be valid for only one of its defined schemas, but it was valid for {0} schemas with indexes ''{1}''.
43+
false = Considered by default as invalid.
44+
items = Index ''{0}'' is not defined in the schema and additional items are not allowed.
45+
not = Node must not be valid for the schema {0}.
46+
notAllowed = Property ''{0}'' is not allowed here.
47+
propertyNames = Property name ''{0}'' is invalid: {1}
48+
unevaluatedProperties = Property ''{0}'' must not be unevaluated.
49+
unevaluatedItems=Item at index {0} must not be unevaluated or must match the schema for unevaluated items.
50+
additionalItems = Index ''{0}'' is not defined in the schema and additional items are not allowed.
51+
format.date = Value does not match the {0} pattern (must be a valid RFC 3339 full-date).
52+
format.date-time = Value does not match the {0} pattern (must be a valid RFC 3339 date-time).
53+
format.duration = Value does not match the {0} pattern (must be a valid ISO 8601 duration).
54+
format.email = Value does not match the {0} pattern (must be a valid RFC 5321 Mailbox).
55+
format.ipv4 = Value does not match the {0} pattern (must be a valid RFC 2673 IP address).
56+
format.ipv6 = Value does not match the {0} pattern (must be a valid RFC 4291 IP address).
57+
format.idn-email = Value does not match the {0} pattern (must be a valid RFC 6531 Mailbox).
58+
format.idn-hostname = Value does not match the {0} pattern (must be a valid RFC 5890 internationalized hostname).
59+
format.iri = Value does not match the {0} pattern (must be a valid RFC 3987 IRI).
60+
format.iri-reference = Value does not match the {0} pattern (must be a valid RFC 3987 IRI-reference).
61+
format.uri = Value does not match the {0} pattern (must be a valid RFC 3986 URI).
62+
format.uri-reference = Value does not match the {0} pattern (must be a valid RFC 3986 URI-reference).
63+
format.uri-template = Value does not match the {0} pattern (must be a valid RFC 6570 URI Template).
64+
format.uuid = Value does not match the {0} pattern (must be a valid RFC 4122 UUID).
65+
format.regex = Value does not match the {0} pattern (must be a valid ECMA-262 regular expression).
66+
format.time = Value does not match the {0} pattern (must be a valid RFC 3339 time).
67+
format.hostname = Value does not match the {0} pattern (must be a valid RFC 1123 host name).
68+
format.json-pointer = Value does not match the {0} pattern (must be a valid RFC 6901 JSON Pointer).
69+
format.relative-json-pointer = Value does not match the {0} pattern (must be a valid IETF Relative JSON Pointer).
70+
format.unknown = has an unknown format ''{0}''.
71+
discriminator.missing_discriminating_value = Required property ''{0}'' for discriminator not found.
72+
discriminator.anyOf.no_match_found = No matching schema found for discriminator value ''{0}''.
73+
discriminator.oneOf.no_match_found = No matching schema found for discriminator value ''{0}''.

0 commit comments

Comments
 (0)