diff --git a/src/main/java/com/networknt/schema/AbstractJsonValidator.java b/src/main/java/com/networknt/schema/AbstractJsonValidator.java index a38100962..f87a6d806 100644 --- a/src/main/java/com/networknt/schema/AbstractJsonValidator.java +++ b/src/main/java/com/networknt/schema/AbstractJsonValidator.java @@ -23,15 +23,15 @@ public abstract class AbstractJsonValidator implements JsonValidator { - public Set validate(JsonNode node) { - return validate(node, node, PathType.LEGACY.getRoot()); + public Set validate(ExecutionContext executionContext, JsonNode node) { + return validate(executionContext, node, node, PathType.LEGACY.getRoot()); } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { Set validationMessages = Collections.emptySet(); if (shouldValidateSchema) { - validationMessages = validate(node, rootNode, at); + validationMessages = validate(executionContext, node, rootNode, at); } return validationMessages; } diff --git a/src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java b/src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java index d3e2a2948..c124ea943 100644 --- a/src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java @@ -64,9 +64,9 @@ public AdditionalPropertiesValidator(String schemaPath, JsonNode schemaNode, Jso parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = executionContext.getCollectorContext(); Set errors = new LinkedHashSet(); if (!node.isObject()) { @@ -102,9 +102,9 @@ public Set validate(JsonNode node, JsonNode rootNode, String if (additionalPropertiesSchema != null) { ValidatorState state = (ValidatorState) collectorContext.get(ValidatorState.VALIDATOR_STATE_KEY); if (state != null && state.isWalkEnabled()) { - errors.addAll(additionalPropertiesSchema.walk(node.get(pname), rootNode, atPath(at, pname), state.isValidationEnabled())); + errors.addAll(additionalPropertiesSchema.walk(executionContext, node.get(pname), rootNode, atPath(at, pname), state.isValidationEnabled())); } else { - errors.addAll(additionalPropertiesSchema.validate(node.get(pname), rootNode, atPath(at, pname))); + errors.addAll(additionalPropertiesSchema.validate(executionContext, node.get(pname), rootNode, atPath(at, pname))); } } } @@ -114,9 +114,9 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { if (shouldValidateSchema) { - return validate(node, rootNode, at); + return validate(executionContext, node, rootNode, at); } if (node == null || !node.isObject()) { @@ -142,9 +142,9 @@ public Set walk(JsonNode node, JsonNode rootNode, String at, if (!allowedProperties.contains(pname) && !handledByPatternProperties) { if (allowAdditionalProperties) { if (additionalPropertiesSchema != null) { - ValidatorState state = (ValidatorState) CollectorContext.getInstance().get(ValidatorState.VALIDATOR_STATE_KEY); + ValidatorState state = (ValidatorState) executionContext.getCollectorContext().get(ValidatorState.VALIDATOR_STATE_KEY); if (state != null && state.isWalkEnabled()) { - additionalPropertiesSchema.walk(node.get(pname), rootNode, atPath(at, pname), state.isValidationEnabled()); + additionalPropertiesSchema.walk(executionContext, node.get(pname), rootNode, atPath(at, pname), state.isValidationEnabled()); } } } diff --git a/src/main/java/com/networknt/schema/AllOfValidator.java b/src/main/java/com/networknt/schema/AllOfValidator.java index 1c7171981..294c1fb8b 100644 --- a/src/main/java/com/networknt/schema/AllOfValidator.java +++ b/src/main/java/com/networknt/schema/AllOfValidator.java @@ -40,9 +40,9 @@ public AllOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = executionContext.getCollectorContext(); // get the Validator state object storing validation data ValidatorState state = (ValidatorState) collectorContext.get(ValidatorState.VALIDATOR_STATE_KEY); @@ -55,9 +55,9 @@ public Set validate(JsonNode node, JsonNode rootNode, String Scope parentScope = collectorContext.enterDynamicScope(); try { if (!state.isWalkEnabled()) { - localErrors = schema.validate(node, rootNode, at); + localErrors = schema.validate(executionContext, node, rootNode, at); } else { - localErrors = schema.walk(node, rootNode, at, true); + localErrors = schema.walk(executionContext, node, rootNode, at, true); } childSchemaErrors.addAll(localErrors); @@ -105,13 +105,13 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { if (shouldValidateSchema) { - return validate(node, rootNode, at); + return validate(executionContext, node, rootNode, at); } for (JsonSchema schema : this.schemas) { // Walk through the schema - schema.walk(node, rootNode, at, false); + schema.walk(executionContext, node, rootNode, at, false); } return Collections.emptySet(); } diff --git a/src/main/java/com/networknt/schema/AnyOfValidator.java b/src/main/java/com/networknt/schema/AnyOfValidator.java index 24d90d387..efd1850f7 100644 --- a/src/main/java/com/networknt/schema/AnyOfValidator.java +++ b/src/main/java/com/networknt/schema/AnyOfValidator.java @@ -48,9 +48,9 @@ public AnyOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = executionContext.getCollectorContext(); // get the Validator state object storing validation data ValidatorState state = (ValidatorState) collectorContext.get(ValidatorState.VALIDATOR_STATE_KEY); @@ -82,9 +82,9 @@ public Set validate(JsonNode node, JsonNode rootNode, String } } if (!state.isWalkEnabled()) { - errors = schema.validate(node, rootNode, at); + errors = schema.validate(executionContext, node, rootNode, at); } else { - errors = schema.walk(node, rootNode, at, true); + errors = schema.walk(executionContext, node, rootNode, at, true); } // check if any validation errors have occurred @@ -151,12 +151,12 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { if (shouldValidateSchema) { - return validate(node, rootNode, at); + return validate(executionContext, node, rootNode, at); } for (JsonSchema schema : this.schemas) { - schema.walk(node, rootNode, at, false); + schema.walk(executionContext, node, rootNode, at, false); } return new LinkedHashSet<>(); } diff --git a/src/main/java/com/networknt/schema/BaseJsonValidator.java b/src/main/java/com/networknt/schema/BaseJsonValidator.java index cb1bf8748..71a9992fb 100644 --- a/src/main/java/com/networknt/schema/BaseJsonValidator.java +++ b/src/main/java/com/networknt/schema/BaseJsonValidator.java @@ -226,8 +226,8 @@ protected JsonSchema fetchSubSchemaNode(ValidationContext validationContext) { } @Override - public Set validate(JsonNode node) { - return validate(node, node, atRoot()); + public Set validate(ExecutionContext executionContext, JsonNode node) { + return validate(executionContext, node, node, atRoot()); } protected String getNodeFieldType() { diff --git a/src/main/java/com/networknt/schema/CollectorContext.java b/src/main/java/com/networknt/schema/CollectorContext.java index 651eca6c4..66157f171 100644 --- a/src/main/java/com/networknt/schema/CollectorContext.java +++ b/src/main/java/com/networknt/schema/CollectorContext.java @@ -32,16 +32,6 @@ * implementations. */ public class CollectorContext { - - // Using a namespace string as key in ThreadLocal so that it is unique in - // ThreadLocal. - static final String COLLECTOR_CONTEXT_THREAD_LOCAL_KEY = "com.networknt.schema.CollectorKey"; - - // Get an instance from thread info (which uses ThreadLocal). - public static CollectorContext getInstance() { - return (CollectorContext) ThreadInfo.get(COLLECTOR_CONTEXT_THREAD_LOCAL_KEY); - } - /** * Map for holding the name and {@link Collector} or a simple Object. */ @@ -212,16 +202,6 @@ public void combineWithCollector(String name, Object data) { } } - /** - * Reset the context - */ - public void reset() { - this.collectorMap = new HashMap<>(); - this.collectorLoadMap = new HashMap<>(); - this.dynamicScopes.clear(); - this.dynamicScopes.push(newTopScope()); - } - /** * Loads data from all collectors. */ diff --git a/src/main/java/com/networknt/schema/ConstValidator.java b/src/main/java/com/networknt/schema/ConstValidator.java index fd3f82552..4e8c7196a 100644 --- a/src/main/java/com/networknt/schema/ConstValidator.java +++ b/src/main/java/com/networknt/schema/ConstValidator.java @@ -32,7 +32,7 @@ public ConstValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS this.schemaNode = schemaNode; } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet(); diff --git a/src/main/java/com/networknt/schema/ContainsValidator.java b/src/main/java/com/networknt/schema/ContainsValidator.java index 6ab87b746..737135627 100644 --- a/src/main/java/com/networknt/schema/ContainsValidator.java +++ b/src/main/java/com/networknt/schema/ContainsValidator.java @@ -67,18 +67,18 @@ public ContainsValidator(String schemaPath, JsonNode schemaNode, JsonSchema pare } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); // ignores non-arrays if (null != this.schema && node.isArray()) { - Collection evaluatedItems = CollectorContext.getInstance().getEvaluatedItems(); + Collection evaluatedItems = executionContext.getCollectorContext().getEvaluatedItems(); int actual = 0, i = 0; for (JsonNode n : node) { String path = atPath(at, i); - if (this.schema.validate(n, rootNode, path).isEmpty()) { + if (this.schema.validate(executionContext, n, rootNode, path).isEmpty()) { ++actual; evaluatedItems.add(path); } diff --git a/src/main/java/com/networknt/schema/DependenciesValidator.java b/src/main/java/com/networknt/schema/DependenciesValidator.java index 0a3678512..5f4d82657 100644 --- a/src/main/java/com/networknt/schema/DependenciesValidator.java +++ b/src/main/java/com/networknt/schema/DependenciesValidator.java @@ -51,7 +51,7 @@ public DependenciesValidator(String schemaPath, JsonNode schemaNode, JsonSchema parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet(); @@ -68,7 +68,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String } JsonSchema schema = schemaDeps.get(pname); if (schema != null) { - errors.addAll(schema.validate(node, rootNode, at)); + errors.addAll(schema.validate(executionContext, node, rootNode, at)); } } diff --git a/src/main/java/com/networknt/schema/DependentRequired.java b/src/main/java/com/networknt/schema/DependentRequired.java index 65ac22c47..197ddbffe 100644 --- a/src/main/java/com/networknt/schema/DependentRequired.java +++ b/src/main/java/com/networknt/schema/DependentRequired.java @@ -45,7 +45,7 @@ public DependentRequired(String schemaPath, JsonNode schemaNode, JsonSchema pare parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet(); diff --git a/src/main/java/com/networknt/schema/DependentSchemas.java b/src/main/java/com/networknt/schema/DependentSchemas.java index fb0d440bc..ea341aa19 100644 --- a/src/main/java/com/networknt/schema/DependentSchemas.java +++ b/src/main/java/com/networknt/schema/DependentSchemas.java @@ -42,7 +42,7 @@ public DependentSchemas(String schemaPath, JsonNode schemaNode, JsonSchema paren } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet<>(); @@ -51,7 +51,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String String pname = it.next(); JsonSchema schema = this.schemaDependencies.get(pname); if (schema != null) { - errors.addAll(schema.validate(node, rootNode, at)); + errors.addAll(schema.validate(executionContext, node, rootNode, at)); } } @@ -64,12 +64,12 @@ public void preloadJsonSchema() { } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { if (shouldValidateSchema) { - return validate(node, rootNode, at); + return validate(executionContext, node, rootNode, at); } for (JsonSchema schema : this.schemaDependencies.values()) { - schema.walk(node, rootNode, at, false); + schema.walk(executionContext, node, rootNode, at, false); } return Collections.emptySet(); } diff --git a/src/main/java/com/networknt/schema/EnumValidator.java b/src/main/java/com/networknt/schema/EnumValidator.java index 39b409d9e..48d022650 100644 --- a/src/main/java/com/networknt/schema/EnumValidator.java +++ b/src/main/java/com/networknt/schema/EnumValidator.java @@ -78,7 +78,7 @@ public EnumValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSc parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet(); diff --git a/src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java b/src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java index 33c28d07c..a1b8fe97b 100644 --- a/src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java +++ b/src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java @@ -98,7 +98,7 @@ public String thresholdValue() { } } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (!JsonNodeUtil.isNumber(node, validationContext.getConfig())) { diff --git a/src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java b/src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java index 9b296ab5e..e7e8ca85b 100644 --- a/src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java +++ b/src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java @@ -105,7 +105,7 @@ public String thresholdValue() { } } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (!JsonNodeUtil.isNumber(node, this.validationContext.getConfig())) { diff --git a/src/main/java/com/networknt/schema/ExecutionContext.java b/src/main/java/com/networknt/schema/ExecutionContext.java new file mode 100644 index 000000000..acbf69bcb --- /dev/null +++ b/src/main/java/com/networknt/schema/ExecutionContext.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema; + +/** + * Stores the execution context for the validation run. + */ +public class ExecutionContext { + private CollectorContext collectorContext; + + public ExecutionContext() { + this(new CollectorContext()); + } + + public ExecutionContext(CollectorContext collectorContext) { + this.collectorContext = collectorContext; + } + + public CollectorContext getCollectorContext() { + return collectorContext; + } + + public void setCollectorContext(CollectorContext collectorContext) { + this.collectorContext = collectorContext; + } +} diff --git a/src/main/java/com/networknt/schema/FalseValidator.java b/src/main/java/com/networknt/schema/FalseValidator.java index a1bca6eb2..8bde058ca 100644 --- a/src/main/java/com/networknt/schema/FalseValidator.java +++ b/src/main/java/com/networknt/schema/FalseValidator.java @@ -30,7 +30,7 @@ public FalseValidator(String schemaPath, final JsonNode schemaNode, JsonSchema p super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.FALSE, validationContext); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); // For the false validator, it is always not valid Set errors = new LinkedHashSet(); diff --git a/src/main/java/com/networknt/schema/Format.java b/src/main/java/com/networknt/schema/Format.java index 43eb20d3f..3120cbcdf 100644 --- a/src/main/java/com/networknt/schema/Format.java +++ b/src/main/java/com/networknt/schema/Format.java @@ -22,7 +22,7 @@ public interface Format { */ String getName(); - boolean matches(String value); + boolean matches(ExecutionContext executionContext, String value); String getErrorMessageDescription(); } diff --git a/src/main/java/com/networknt/schema/FormatValidator.java b/src/main/java/com/networknt/schema/FormatValidator.java index a8afa147d..11851dbeb 100644 --- a/src/main/java/com/networknt/schema/FormatValidator.java +++ b/src/main/java/com/networknt/schema/FormatValidator.java @@ -37,7 +37,7 @@ public FormatValidator(String schemaPath, JsonNode schemaNode, JsonSchema parent parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet(); @@ -58,7 +58,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String } } try { - if (!format.matches(node.textValue())) { + if (!format.matches(executionContext, node.textValue())) { errors.add(buildValidationMessage(at, format.getName(), format.getErrorMessageDescription())); } } catch (PatternSyntaxException pse) { diff --git a/src/main/java/com/networknt/schema/IfValidator.java b/src/main/java/com/networknt/schema/IfValidator.java index 049baf795..a3a511aa8 100644 --- a/src/main/java/com/networknt/schema/IfValidator.java +++ b/src/main/java/com/networknt/schema/IfValidator.java @@ -58,9 +58,9 @@ public IfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSche } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = executionContext.getCollectorContext(); Set errors = new LinkedHashSet<>(); @@ -68,7 +68,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String boolean ifConditionPassed = false; try { try { - ifConditionPassed = this.ifSchema.validate(node, rootNode, at).isEmpty(); + ifConditionPassed = this.ifSchema.validate(executionContext, node, rootNode, at).isEmpty(); } catch (JsonSchemaException ex) { // When failFast is enabled, validations are thrown as exceptions. // An exception means the condition failed @@ -76,13 +76,13 @@ public Set validate(JsonNode node, JsonNode rootNode, String } if (ifConditionPassed && this.thenSchema != null) { - errors.addAll(this.thenSchema.validate(node, rootNode, at)); + errors.addAll(this.thenSchema.validate(executionContext, node, rootNode, at)); } else if (!ifConditionPassed && this.elseSchema != null) { // discard ifCondition results collectorContext.exitDynamicScope(); collectorContext.enterDynamicScope(); - errors.addAll(this.elseSchema.validate(node, rootNode, at)); + errors.addAll(this.elseSchema.validate(executionContext, node, rootNode, at)); } } finally { @@ -109,19 +109,19 @@ public void preloadJsonSchema() { } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { if (shouldValidateSchema) { - return validate(node, rootNode, at); + return validate(executionContext, node, rootNode, at); } if (null != this.ifSchema) { - this.ifSchema.walk(node, rootNode, at, false); + this.ifSchema.walk(executionContext, node, rootNode, at, false); } if (null != this.thenSchema) { - this.thenSchema.walk(node, rootNode, at, false); + this.thenSchema.walk(executionContext, node, rootNode, at, false); } if (null != this.elseSchema) { - this.elseSchema.walk(node, rootNode, at, false); + this.elseSchema.walk(executionContext, node, rootNode, at, false); } return Collections.emptySet(); diff --git a/src/main/java/com/networknt/schema/ItemsValidator.java b/src/main/java/com/networknt/schema/ItemsValidator.java index 88f012c35..7ca1692cb 100644 --- a/src/main/java/com/networknt/schema/ItemsValidator.java +++ b/src/main/java/com/networknt/schema/ItemsValidator.java @@ -70,7 +70,7 @@ public ItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet<>(); @@ -82,23 +82,23 @@ public Set validate(JsonNode node, JsonNode rootNode, String if (node.isArray()) { int i = 0; for (JsonNode n : node) { - doValidate(errors, i, n, rootNode, at); + doValidate(executionContext, errors, i, n, rootNode, at); i++; } } else { - doValidate(errors, 0, node, rootNode, at); + doValidate(executionContext, errors, 0, node, rootNode, at); } return Collections.unmodifiableSet(errors); } - private void doValidate(Set errors, int i, JsonNode node, JsonNode rootNode, String at) { - Collection evaluatedItems = CollectorContext.getInstance().getEvaluatedItems(); + private void doValidate(ExecutionContext executionContext, Set errors, int i, JsonNode node, JsonNode rootNode, String at) { + Collection evaluatedItems = executionContext.getCollectorContext().getEvaluatedItems(); String path = atPath(at, i); if (this.schema != null) { // validate with item schema (the whole array has the same item // schema) - Set results = this.schema.validate(node, rootNode, path); + Set results = this.schema.validate(executionContext, node, rootNode, path); if (results.isEmpty()) { evaluatedItems.add(path); } else { @@ -107,7 +107,7 @@ private void doValidate(Set errors, int i, JsonNode node, Jso } else if (this.tupleSchema != null) { if (i < this.tupleSchema.size()) { // validate against tuple schema - Set results = this.tupleSchema.get(i).validate(node, rootNode, path); + Set results = this.tupleSchema.get(i).validate(executionContext, node, rootNode, path); if (results.isEmpty()) { evaluatedItems.add(path); } else { @@ -116,7 +116,7 @@ private void doValidate(Set errors, int i, JsonNode node, Jso } else { if (this.additionalSchema != null) { // validate against additional item schema - Set results = this.additionalSchema.validate(node, rootNode, path); + Set results = this.additionalSchema.validate(executionContext, node, rootNode, path); if (results.isEmpty()) { evaluatedItems.add(path); } else { @@ -137,7 +137,7 @@ private void doValidate(Set errors, int i, JsonNode node, Jso } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { HashSet validationMessages = new LinkedHashSet<>(); if (node instanceof ArrayNode) { ArrayNode arrayNode = (ArrayNode) node; @@ -151,48 +151,48 @@ public Set walk(JsonNode node, JsonNode rootNode, String at, arrayNode.set(i, defaultNode); n = defaultNode; } - doWalk(validationMessages, i, n, rootNode, at, shouldValidateSchema); + doWalk(executionContext, validationMessages, i, n, rootNode, at, shouldValidateSchema); i++; } } else { - doWalk(validationMessages, 0, node, rootNode, at, shouldValidateSchema); + doWalk(executionContext, validationMessages, 0, node, rootNode, at, shouldValidateSchema); } return validationMessages; } - private void doWalk(HashSet validationMessages, int i, JsonNode node, JsonNode rootNode, - String at, boolean shouldValidateSchema) { + private void doWalk(ExecutionContext executionContext, HashSet validationMessages, int i, JsonNode node, + JsonNode rootNode, String at, boolean shouldValidateSchema) { if (this.schema != null) { // Walk the schema. - walkSchema(this.schema, node, rootNode, atPath(at, i), shouldValidateSchema, validationMessages); + walkSchema(executionContext, this.schema, node, rootNode, atPath(at, i), shouldValidateSchema, validationMessages); } if (this.tupleSchema != null) { if (i < this.tupleSchema.size()) { // walk tuple schema - walkSchema(this.tupleSchema.get(i), node, rootNode, atPath(at, i), shouldValidateSchema, - validationMessages); + walkSchema(executionContext, this.tupleSchema.get(i), node, rootNode, atPath(at, i), + shouldValidateSchema, validationMessages); } else { if (this.additionalSchema != null) { // walk additional item schema - walkSchema(this.additionalSchema, node, rootNode, atPath(at, i), shouldValidateSchema, - validationMessages); + walkSchema(executionContext, this.additionalSchema, node, rootNode, atPath(at, i), + shouldValidateSchema, validationMessages); } } } } - private void walkSchema(JsonSchema walkSchema, JsonNode node, JsonNode rootNode, String at, - boolean shouldValidateSchema, Set validationMessages) { - boolean executeWalk = this.arrayItemWalkListenerRunner.runPreWalkListeners(ValidatorTypeCode.ITEMS.getValue(), node, - rootNode, at, walkSchema.getSchemaPath(), walkSchema.getSchemaNode(), walkSchema.getParentSchema(), - this.validationContext, this.validationContext.getJsonSchemaFactory()); + private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema, JsonNode node, JsonNode rootNode, + String at, boolean shouldValidateSchema, Set validationMessages) { + boolean executeWalk = this.arrayItemWalkListenerRunner.runPreWalkListeners(executionContext, ValidatorTypeCode.ITEMS.getValue(), + node, rootNode, at, walkSchema.getSchemaPath(), walkSchema.getSchemaNode(), + walkSchema.getParentSchema(), this.validationContext, this.validationContext.getJsonSchemaFactory()); if (executeWalk) { - validationMessages.addAll(walkSchema.walk(node, rootNode, at, shouldValidateSchema)); + validationMessages.addAll(walkSchema.walk(executionContext, node, rootNode, at, shouldValidateSchema)); } - this.arrayItemWalkListenerRunner.runPostWalkListeners(ValidatorTypeCode.ITEMS.getValue(), node, rootNode, at, - walkSchema.getSchemaPath(), walkSchema.getSchemaNode(), walkSchema.getParentSchema(), - this.validationContext, this.validationContext.getJsonSchemaFactory(), validationMessages); + this.arrayItemWalkListenerRunner.runPostWalkListeners(executionContext, ValidatorTypeCode.ITEMS.getValue(), node, rootNode, + at, walkSchema.getSchemaPath(), walkSchema.getSchemaNode(), + walkSchema.getParentSchema(), this.validationContext, this.validationContext.getJsonSchemaFactory(), validationMessages); } diff --git a/src/main/java/com/networknt/schema/ItemsValidator202012.java b/src/main/java/com/networknt/schema/ItemsValidator202012.java index cf350aeca..a1e63e542 100644 --- a/src/main/java/com/networknt/schema/ItemsValidator202012.java +++ b/src/main/java/com/networknt/schema/ItemsValidator202012.java @@ -59,18 +59,18 @@ public ItemsValidator202012(String schemaPath, JsonNode schemaNode, JsonSchema p } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet<>(); // ignores non-arrays if (node.isArray()) { - Collection evaluatedItems = CollectorContext.getInstance().getEvaluatedItems(); + Collection evaluatedItems = executionContext.getCollectorContext().getEvaluatedItems(); for (int i = this.prefixCount; i < node.size(); ++i) { String path = atPath(at, i); // validate with item schema (the whole array has the same item schema) - Set results = this.schema.validate(node.get(i), rootNode, path); + Set results = this.schema.validate(executionContext, node.get(i), rootNode, path); if (results.isEmpty()) { evaluatedItems.add(path); } else { @@ -83,7 +83,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { Set validationMessages = new LinkedHashSet<>(); if (node instanceof ArrayNode) { @@ -99,18 +99,19 @@ public Set walk(JsonNode node, JsonNode rootNode, String at, n = defaultNode; } // Walk the schema. - walkSchema(this.schema, n, rootNode, atPath(at, i), shouldValidateSchema, validationMessages); + walkSchema(executionContext, this.schema, n, rootNode, atPath(at, i), shouldValidateSchema, validationMessages); } } else { - walkSchema(this.schema, node, rootNode, at, shouldValidateSchema, validationMessages); + walkSchema(executionContext, this.schema, node, rootNode, at, shouldValidateSchema, validationMessages); } return validationMessages; } - private void walkSchema(JsonSchema walkSchema, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema, Set validationMessages) { + private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema, Set validationMessages) { //@formatter:off boolean executeWalk = this.arrayItemWalkListenerRunner.runPreWalkListeners( + executionContext, ValidatorTypeCode.ITEMS.getValue(), node, rootNode, @@ -118,13 +119,13 @@ private void walkSchema(JsonSchema walkSchema, JsonNode node, JsonNode rootNode, walkSchema.getSchemaPath(), walkSchema.getSchemaNode(), walkSchema.getParentSchema(), - this.validationContext, - this.validationContext.getJsonSchemaFactory() + this.validationContext, this.validationContext.getJsonSchemaFactory() ); if (executeWalk) { - validationMessages.addAll(walkSchema.walk(node, rootNode, at, shouldValidateSchema)); + validationMessages.addAll(walkSchema.walk(executionContext, node, rootNode, at, shouldValidateSchema)); } this.arrayItemWalkListenerRunner.runPostWalkListeners( + executionContext, ValidatorTypeCode.ITEMS.getValue(), node, rootNode, @@ -133,8 +134,7 @@ private void walkSchema(JsonSchema walkSchema, JsonNode node, JsonNode rootNode, walkSchema.getSchemaNode(), walkSchema.getParentSchema(), this.validationContext, - this.validationContext.getJsonSchemaFactory(), - validationMessages + this.validationContext.getJsonSchemaFactory(), validationMessages ); //@formatter:on } diff --git a/src/main/java/com/networknt/schema/JsonSchema.java b/src/main/java/com/networknt/schema/JsonSchema.java index 423d54adb..84d8c3186 100644 --- a/src/main/java/com/networknt/schema/JsonSchema.java +++ b/src/main/java/com/networknt/schema/JsonSchema.java @@ -376,176 +376,186 @@ private JsonNode getMessageNode(JsonNode schemaNode, JsonSchema parentSchema, St /************************ START OF VALIDATE METHODS **********************************/ @Override - public Set validate(JsonNode jsonNode, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode jsonNode, JsonNode rootNode, String at) { SchemaValidatorsConfig config = this.validationContext.getConfig(); Set errors = new LinkedHashSet<>(); // Get the collector context. - CollectorContext collectorContext = getCollectorContext(); + CollectorContext collectorContext = executionContext.getCollectorContext(); // Set the walkEnabled and isValidationEnabled flag in internal validator state. - setValidatorState(false, true); + setValidatorState(executionContext, false, true); - try { - for (JsonValidator v : getValidators().values()) { - Set results = Collections.emptySet(); - - Scope parentScope = collectorContext.enterDynamicScope(this); - try { - results = v.validate(jsonNode, rootNode, at); - } finally { - Scope scope = collectorContext.exitDynamicScope(); - if (results.isEmpty()) { - parentScope.mergeWith(scope); - } else { - errors.addAll(results); - if (v instanceof PrefixItemsValidator || v instanceof ItemsValidator - || v instanceof ItemsValidator202012 || v instanceof ContainsValidator) { - collectorContext.getEvaluatedItems().addAll(scope.getEvaluatedItems()); - } - if (v instanceof PropertiesValidator || v instanceof AdditionalPropertiesValidator - || v instanceof PatternPropertiesValidator) { - collectorContext.getEvaluatedProperties().addAll(scope.getEvaluatedProperties()); - } - } + for (JsonValidator v : getValidators().values()) { + Set results = Collections.emptySet(); + Scope parentScope = collectorContext.enterDynamicScope(this); + try { + results = v.validate(executionContext, jsonNode, rootNode, at); + } finally { + Scope scope = collectorContext.exitDynamicScope(); + if (results.isEmpty()) { + parentScope.mergeWith(scope); + } else { + errors.addAll(results); + if (v instanceof PrefixItemsValidator || v instanceof ItemsValidator + || v instanceof ItemsValidator202012 || v instanceof ContainsValidator) { + collectorContext.getEvaluatedItems().addAll(scope.getEvaluatedItems()); + } + if (v instanceof PropertiesValidator || v instanceof AdditionalPropertiesValidator + || v instanceof PatternPropertiesValidator) { + collectorContext.getEvaluatedProperties().addAll(scope.getEvaluatedProperties()); + } } + } + } - if (config.isOpenAPI3StyleDiscriminators()) { - ObjectNode discriminator = (ObjectNode) this.schemaNode.get("discriminator"); - if (null != discriminator) { - final DiscriminatorContext discriminatorContext = this.validationContext - .getCurrentDiscriminatorContext(); - if (null != discriminatorContext) { - final ObjectNode discriminatorToUse; - final ObjectNode discriminatorFromContext = discriminatorContext - .getDiscriminatorForPath(this.schemaPath); - if (null == discriminatorFromContext) { - // register the current discriminator. This can only happen when the current context discriminator - // was not registered via allOf. In that case we have a $ref to the schema with discriminator that gets - // used for validation before allOf validation has kicked in - discriminatorContext.registerDiscriminator(this.schemaPath, discriminator); - discriminatorToUse = discriminator; - } else { - discriminatorToUse = discriminatorFromContext; - } - - final String discriminatorPropertyName = discriminatorToUse.get("propertyName").asText(); - final JsonNode discriminatorNode = jsonNode.get(discriminatorPropertyName); - final String discriminatorPropertyValue = discriminatorNode == null ? null - : discriminatorNode.asText(); - checkDiscriminatorMatch(discriminatorContext, discriminatorToUse, discriminatorPropertyValue, - this); + if (config.isOpenAPI3StyleDiscriminators()) { + ObjectNode discriminator = (ObjectNode) this.schemaNode.get("discriminator"); + if (null != discriminator) { + final DiscriminatorContext discriminatorContext = this.validationContext + .getCurrentDiscriminatorContext(); + if (null != discriminatorContext) { + final ObjectNode discriminatorToUse; + final ObjectNode discriminatorFromContext = discriminatorContext + .getDiscriminatorForPath(this.schemaPath); + if (null == discriminatorFromContext) { + // register the current discriminator. This can only happen when the current context discriminator + // was not registered via allOf. In that case we have a $ref to the schema with discriminator that gets + // used for validation before allOf validation has kicked in + discriminatorContext.registerDiscriminator(this.schemaPath, discriminator); + discriminatorToUse = discriminator; + } else { + discriminatorToUse = discriminatorFromContext; } - } - } - return errors; - } finally { - if (collectorContext.getDynamicScope().isTop() && config.isResetCollectorContext()) { - collectorContext.reset(); + final String discriminatorPropertyName = discriminatorToUse.get("propertyName").asText(); + final JsonNode discriminatorNode = jsonNode.get(discriminatorPropertyName); + final String discriminatorPropertyValue = discriminatorNode == null ? null + : discriminatorNode.asText(); + checkDiscriminatorMatch(discriminatorContext, discriminatorToUse, discriminatorPropertyValue, + this); + } } } + + return errors; } - public ValidationResult validateAndCollect(JsonNode node) { - return validateAndCollect(node, node, atRoot()); + /** + * Validate the given root JsonNode, starting at the root of the data path. + * @param rootNode JsonNode + * + * @return A list of ValidationMessage if there is any validation error, or an empty + * list if there is no error. + */ + public Set validate(JsonNode rootNode) { + return validate(createExecutionContext(), rootNode); + } + + public ValidationResult validateAndCollect(ExecutionContext executionContext, JsonNode node) { + return validateAndCollect(executionContext, node, node, atRoot()); } /** * This method both validates and collects the data in a CollectorContext. * Unlike others this methods cleans and removes everything from collector * context before returning. - * + * @param executionContext ExecutionContext * @param jsonNode JsonNode * @param rootNode JsonNode * @param at String path + * * @return ValidationResult */ - private ValidationResult validateAndCollect(JsonNode jsonNode, JsonNode rootNode, String at) { + private ValidationResult validateAndCollect(ExecutionContext executionContext, JsonNode jsonNode, JsonNode rootNode, String at) { // Get the config. SchemaValidatorsConfig config = this.validationContext.getConfig(); // Get the collector context from the thread local. - CollectorContext collectorContext = getCollectorContext(); + CollectorContext collectorContext = executionContext.getCollectorContext(); // Set the walkEnabled and isValidationEnabled flag in internal validator state. - setValidatorState(false, true); + setValidatorState(executionContext, false, true); // Validate. - Set errors = validate(jsonNode, rootNode, at); + Set errors = validate(executionContext, jsonNode, rootNode, at); // When walk is called in series of nested call we don't want to load the collectors every time. Leave to the API to decide when to call collectors. if (config.doLoadCollectors()) { // Load all the data from collectors into the context. collectorContext.loadCollectors(); } // Collect errors and collector context into validation result. - ValidationResult validationResult = new ValidationResult(errors, collectorContext); + ValidationResult validationResult = new ValidationResult(errors, executionContext); return validationResult; } + public ValidationResult validateAndCollect(JsonNode node) { + return validateAndCollect(createExecutionContext(), node, node, atRoot()); + } + /************************ END OF VALIDATE METHODS **********************************/ /*********************** START OF WALK METHODS **********************************/ /** * Walk the JSON node - * + * @param executionContext ExecutionContext * @param node JsonNode * @param shouldValidateSchema indicator on validation + * * @return result of ValidationResult */ + public ValidationResult walk(ExecutionContext executionContext, JsonNode node, boolean shouldValidateSchema) { + return walkAtNodeInternal(executionContext, node, node, atRoot(), shouldValidateSchema); + } + public ValidationResult walk(JsonNode node, boolean shouldValidateSchema) { - return walkAtNodeInternal(node, node, atRoot(), shouldValidateSchema); + return walk(createExecutionContext(), node, shouldValidateSchema); } - public ValidationResult walkAtNode(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { - return walkAtNodeInternal(node, rootNode, at, shouldValidateSchema); + public ValidationResult walkAtNode(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + return walkAtNodeInternal(executionContext, node, rootNode, at, shouldValidateSchema); } - private ValidationResult walkAtNodeInternal(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { - try { - // Get the config. - SchemaValidatorsConfig config = this.validationContext.getConfig(); - // Get the collector context from the thread local. - CollectorContext collectorContext = getCollectorContext(); - // Set the walkEnabled flag in internal validator state. - setValidatorState(true, shouldValidateSchema); - // Walk through the schema. - Set errors = walk(node, rootNode, at, shouldValidateSchema); - // When walk is called in series of nested call we don't want to load the collectors every time. Leave to the API to decide when to call collectors. - if (config.doLoadCollectors()) { - // Load all the data from collectors into the context. - collectorContext.loadCollectors(); - } - - ValidationResult validationResult = new ValidationResult(errors, collectorContext); - return validationResult; - } finally { - if (this.validationContext.getConfig().isResetCollectorContext()) { - CollectorContext.getInstance().reset(); - } + private ValidationResult walkAtNodeInternal(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + // Get the config. + SchemaValidatorsConfig config = this.validationContext.getConfig(); + // Get the collector context. + CollectorContext collectorContext = executionContext.getCollectorContext(); + // Set the walkEnabled flag in internal validator state. + setValidatorState(executionContext, true, shouldValidateSchema); + // Walk through the schema. + Set errors = walk(executionContext, node, rootNode, at, shouldValidateSchema); + // When walk is called in series of nested call we don't want to load the collectors every time. Leave to the API to decide when to call collectors. + if (config.doLoadCollectors()) { + // Load all the data from collectors into the context. + collectorContext.loadCollectors(); } + + ValidationResult validationResult = new ValidationResult(errors, executionContext); + return validationResult; } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { Set validationMessages = new LinkedHashSet<>(); // Walk through all the JSONWalker's. getValidators().forEach((String schemaPathWithKeyword, JsonSchemaWalker jsonWalker) -> { try { // Call all the pre-walk listeners. If at least one of the pre walk listeners // returns SKIP, then skip the walk. - if (this.keywordWalkListenerRunner.runPreWalkListeners(schemaPathWithKeyword, + if (this.keywordWalkListenerRunner.runPreWalkListeners(executionContext, + schemaPathWithKeyword, node, rootNode, at, this.schemaPath, this.schemaNode, this.parentSchema, - this.validationContext, - this.validationContext.getJsonSchemaFactory())) { - validationMessages.addAll(jsonWalker.walk(node, rootNode, at, shouldValidateSchema)); + this.validationContext, this.validationContext.getJsonSchemaFactory())) { + validationMessages.addAll(jsonWalker.walk(executionContext, node, rootNode, at, shouldValidateSchema)); } } finally { // Call all the post-walk listeners. - this.keywordWalkListenerRunner.runPostWalkListeners(schemaPathWithKeyword, + this.keywordWalkListenerRunner.runPostWalkListeners(executionContext, + schemaPathWithKeyword, node, rootNode, at, @@ -553,8 +563,7 @@ public Set walk(JsonNode node, JsonNode rootNode, String at, this.schemaNode, this.parentSchema, this.validationContext, - this.validationContext.getJsonSchemaFactory(), - validationMessages); + this.validationContext.getJsonSchemaFactory(), validationMessages); } }); @@ -563,10 +572,9 @@ public Set walk(JsonNode node, JsonNode rootNode, String at, /************************ END OF WALK METHODS **********************************/ - private static void setValidatorState(boolean isWalkEnabled, boolean shouldValidateSchema) { - CollectorContext collectorContext = CollectorContext.getInstance(); - + private static void setValidatorState(ExecutionContext executionContext, boolean isWalkEnabled, boolean shouldValidateSchema) { // Get the Validator state object storing validation data + CollectorContext collectorContext = executionContext.getCollectorContext(); Object stateObj = collectorContext.get(ValidatorState.VALIDATOR_STATE_KEY); // if one has not been created, instantiate one if (stateObj == null) { @@ -577,18 +585,6 @@ private static void setValidatorState(boolean isWalkEnabled, boolean shouldValid } } - public CollectorContext getCollectorContext() { - return (CollectorContext) ThreadInfo.computeIfAbsent( - CollectorContext.COLLECTOR_CONTEXT_THREAD_LOCAL_KEY, - k -> Optional.ofNullable(this.validationContext.getConfig()) - .map(SchemaValidatorsConfig::getCollectorContext) - .orElseGet(() -> Optional.ofNullable(this.validationContext.getConfig()) - .map(config -> new CollectorContext(config.isUnevaluatedItemsAnalysisDisabled(), config.isUnevaluatedPropertiesAnalysisDisabled())) - .orElseGet(() -> new CollectorContext(false, false)) - ) - ); - } - @Override public String toString() { return "\"" + getSchemaPath() + "\" : " + getSchemaNode().toString(); @@ -639,4 +635,18 @@ public boolean isDynamicAnchor() { return this.dynamicAnchor; } + /** + * Creates an execution context. + * + * @return the execution context + */ + public ExecutionContext createExecutionContext() { + SchemaValidatorsConfig config = validationContext.getConfig(); + if(config.getExecutionContextSupplier() != null) { + return config.getExecutionContextSupplier().get(); + } + CollectorContext collectorContext = new CollectorContext(config.isUnevaluatedItemsAnalysisDisabled(), + config.isUnevaluatedPropertiesAnalysisDisabled()); + return new ExecutionContext(collectorContext); + } } diff --git a/src/main/java/com/networknt/schema/JsonSchemaRef.java b/src/main/java/com/networknt/schema/JsonSchemaRef.java index 8acedf432..c07dc3e26 100644 --- a/src/main/java/com/networknt/schema/JsonSchemaRef.java +++ b/src/main/java/com/networknt/schema/JsonSchemaRef.java @@ -34,15 +34,15 @@ public JsonSchemaRef(JsonSchema schema) { this.schema = schema; } - public Set validate(JsonNode node, JsonNode rootNode, String at) { - return schema.validate(node, rootNode, at); + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { + return schema.validate(executionContext, node, rootNode, at); } public JsonSchema getSchema() { return schema; } - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { - return schema.walk(node, rootNode, at, shouldValidateSchema); + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + return schema.walk(executionContext, node, rootNode, at, shouldValidateSchema); } } diff --git a/src/main/java/com/networknt/schema/JsonValidator.java b/src/main/java/com/networknt/schema/JsonValidator.java index afdc37b2f..9040211f4 100644 --- a/src/main/java/com/networknt/schema/JsonValidator.java +++ b/src/main/java/com/networknt/schema/JsonValidator.java @@ -29,26 +29,28 @@ public interface JsonValidator extends JsonSchemaWalker { /** * Validate the given root JsonNode, starting at the root of the data path. - * + * @param executionContext ExecutionContext * @param rootNode JsonNode + * * @return A list of ValidationMessage if there is any validation error, or an empty * list if there is no error. */ - default Set validate(JsonNode rootNode) { - return validate(rootNode, rootNode, PathType.DEFAULT.getRoot()); // TODO: This is not valid when using JSON Pointer. + default Set validate(ExecutionContext executionContext, JsonNode rootNode) { + return validate(executionContext, rootNode, rootNode, PathType.DEFAULT.getRoot()); // TODO: This is not valid when using JSON Pointer. } /** * Validate the given JsonNode, the given node is the child node of the root node at given * data path. - * + * @param executionContext ExecutionContext * @param node JsonNode * @param rootNode JsonNode * @param at String + * * @return A list of ValidationMessage if there is any validation error, or an empty * list if there is no error. */ - Set validate(JsonNode node, JsonNode rootNode, String at); + Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at); /** * In case the {@link com.networknt.schema.JsonValidator} has a related {@link com.networknt.schema.JsonSchema} or several @@ -67,10 +69,10 @@ default void preloadJsonSchema() throws JsonSchemaException { * validate method if shouldValidateSchema is enabled. */ @Override - default Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + default Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { Set validationMessages = new LinkedHashSet(); if (shouldValidateSchema) { - validationMessages = validate(node, rootNode, at); + validationMessages = validate(executionContext, node, rootNode, at); } return validationMessages; } diff --git a/src/main/java/com/networknt/schema/MaxItemsValidator.java b/src/main/java/com/networknt/schema/MaxItemsValidator.java index 18e194472..eac94cdcf 100644 --- a/src/main/java/com/networknt/schema/MaxItemsValidator.java +++ b/src/main/java/com/networknt/schema/MaxItemsValidator.java @@ -39,7 +39,7 @@ public MaxItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema pare parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (node.isArray()) { diff --git a/src/main/java/com/networknt/schema/MaxLengthValidator.java b/src/main/java/com/networknt/schema/MaxLengthValidator.java index 80eb2adfd..3ae48cf29 100644 --- a/src/main/java/com/networknt/schema/MaxLengthValidator.java +++ b/src/main/java/com/networknt/schema/MaxLengthValidator.java @@ -38,7 +38,7 @@ public MaxLengthValidator(String schemaPath, JsonNode schemaNode, JsonSchema par parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); diff --git a/src/main/java/com/networknt/schema/MaxPropertiesValidator.java b/src/main/java/com/networknt/schema/MaxPropertiesValidator.java index b1363a19e..cc39eb321 100644 --- a/src/main/java/com/networknt/schema/MaxPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/MaxPropertiesValidator.java @@ -38,7 +38,7 @@ public MaxPropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSchema parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (node.isObject()) { diff --git a/src/main/java/com/networknt/schema/MaximumValidator.java b/src/main/java/com/networknt/schema/MaximumValidator.java index 2e7f216f1..1bb6b4819 100644 --- a/src/main/java/com/networknt/schema/MaximumValidator.java +++ b/src/main/java/com/networknt/schema/MaximumValidator.java @@ -107,7 +107,7 @@ public String thresholdValue() { } } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (!JsonNodeUtil.isNumber(node, this.validationContext.getConfig())) { diff --git a/src/main/java/com/networknt/schema/MinItemsValidator.java b/src/main/java/com/networknt/schema/MinItemsValidator.java index 0c9bf08b9..370348757 100644 --- a/src/main/java/com/networknt/schema/MinItemsValidator.java +++ b/src/main/java/com/networknt/schema/MinItemsValidator.java @@ -37,7 +37,7 @@ public MinItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema pare parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (node.isArray()) { diff --git a/src/main/java/com/networknt/schema/MinLengthValidator.java b/src/main/java/com/networknt/schema/MinLengthValidator.java index 7629005f8..629a3db30 100644 --- a/src/main/java/com/networknt/schema/MinLengthValidator.java +++ b/src/main/java/com/networknt/schema/MinLengthValidator.java @@ -38,7 +38,7 @@ public MinLengthValidator(String schemaPath, JsonNode schemaNode, JsonSchema par parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); diff --git a/src/main/java/com/networknt/schema/MinMaxContainsValidator.java b/src/main/java/com/networknt/schema/MinMaxContainsValidator.java index c1f67929a..5356e0ceb 100644 --- a/src/main/java/com/networknt/schema/MinMaxContainsValidator.java +++ b/src/main/java/com/networknt/schema/MinMaxContainsValidator.java @@ -49,7 +49,7 @@ private void report(String messageKey, String at) { } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { return this.analysis; } diff --git a/src/main/java/com/networknt/schema/MinPropertiesValidator.java b/src/main/java/com/networknt/schema/MinPropertiesValidator.java index d57ab31c6..ee963e4d2 100644 --- a/src/main/java/com/networknt/schema/MinPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/MinPropertiesValidator.java @@ -38,7 +38,7 @@ public MinPropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSchema parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (node.isObject()) { diff --git a/src/main/java/com/networknt/schema/MinimumValidator.java b/src/main/java/com/networknt/schema/MinimumValidator.java index 47b902f27..b1e938b8d 100644 --- a/src/main/java/com/networknt/schema/MinimumValidator.java +++ b/src/main/java/com/networknt/schema/MinimumValidator.java @@ -114,7 +114,7 @@ public String thresholdValue() { this.validationContext = validationContext; } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (!JsonNodeUtil.isNumber(node, this.validationContext.getConfig())) { diff --git a/src/main/java/com/networknt/schema/MultipleOfValidator.java b/src/main/java/com/networknt/schema/MultipleOfValidator.java index 4b7933b61..15981b194 100644 --- a/src/main/java/com/networknt/schema/MultipleOfValidator.java +++ b/src/main/java/com/networknt/schema/MultipleOfValidator.java @@ -39,7 +39,7 @@ public MultipleOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema pa parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (node.isNumber()) { diff --git a/src/main/java/com/networknt/schema/NonValidationKeyword.java b/src/main/java/com/networknt/schema/NonValidationKeyword.java index 4bb6e390b..f0c239db9 100644 --- a/src/main/java/com/networknt/schema/NonValidationKeyword.java +++ b/src/main/java/com/networknt/schema/NonValidationKeyword.java @@ -28,7 +28,7 @@ public class NonValidationKeyword extends AbstractKeyword { private static final class Validator extends AbstractJsonValidator { @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { return Collections.emptySet(); } } diff --git a/src/main/java/com/networknt/schema/NotAllowedValidator.java b/src/main/java/com/networknt/schema/NotAllowedValidator.java index 1bf141f11..5b6d9250c 100644 --- a/src/main/java/com/networknt/schema/NotAllowedValidator.java +++ b/src/main/java/com/networknt/schema/NotAllowedValidator.java @@ -40,7 +40,7 @@ public NotAllowedValidator(String schemaPath, JsonNode schemaNode, JsonSchema pa parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet(); diff --git a/src/main/java/com/networknt/schema/NotValidator.java b/src/main/java/com/networknt/schema/NotValidator.java index 528e2553a..696cf49e8 100644 --- a/src/main/java/com/networknt/schema/NotValidator.java +++ b/src/main/java/com/networknt/schema/NotValidator.java @@ -37,14 +37,14 @@ public NotValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSch } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { - CollectorContext collectorContext = CollectorContext.getInstance(); + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { + CollectorContext collectorContext = executionContext.getCollectorContext(); Set errors = new HashSet<>(); Scope parentScope = collectorContext.enterDynamicScope(); try { debug(logger, node, rootNode, at); - errors = this.schema.validate(node, rootNode, at); + errors = this.schema.validate(executionContext, node, rootNode, at); if (errors.isEmpty()) { return Collections.singleton(buildValidationMessage(at, this.schema.toString())); } @@ -58,12 +58,12 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { if (shouldValidateSchema) { - return validate(node, rootNode, at); + return validate(executionContext, node, rootNode, at); } - Set errors = this.schema.walk(node, rootNode, at, shouldValidateSchema); + Set errors = this.schema.walk(executionContext, node, rootNode, at, shouldValidateSchema); if (errors.isEmpty()) { return Collections.singleton(buildValidationMessage(at, this.schema.toString())); } diff --git a/src/main/java/com/networknt/schema/OneOfValidator.java b/src/main/java/com/networknt/schema/OneOfValidator.java index a44c17093..ccfe0a675 100644 --- a/src/main/java/com/networknt/schema/OneOfValidator.java +++ b/src/main/java/com/networknt/schema/OneOfValidator.java @@ -40,9 +40,9 @@ public OneOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { Set errors = new LinkedHashSet<>(); - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = executionContext.getCollectorContext(); Scope grandParentScope = collectorContext.enterDynamicScope(); try { @@ -65,9 +65,9 @@ public Set validate(JsonNode node, JsonNode rootNode, String state.setMatchedNode(true); if (!state.isWalkEnabled()) { - schemaErrors = schema.validate(node, rootNode, at); + schemaErrors = schema.validate(executionContext, node, rootNode, at); } else { - schemaErrors = schema.walk(node, rootNode, at, state.isValidationEnabled()); + schemaErrors = schema.walk(executionContext, node, rootNode, at, state.isValidationEnabled()); } // check if any validation errors have occurred @@ -109,8 +109,8 @@ public Set validate(JsonNode node, JsonNode rootNode, String if (errors.isEmpty()) state.setMatchedNode(true); - // reset the ValidatorState object in the ThreadLocal - resetValidatorState(); + // reset the ValidatorState object + resetValidatorState(collectorContext); return Collections.unmodifiableSet(errors); } finally { @@ -121,20 +121,20 @@ public Set validate(JsonNode node, JsonNode rootNode, String } } - private static void resetValidatorState() { - ValidatorState state = (ValidatorState) CollectorContext.getInstance().get(ValidatorState.VALIDATOR_STATE_KEY); + private static void resetValidatorState(CollectorContext collectorContext) { + ValidatorState state = (ValidatorState) collectorContext.get(ValidatorState.VALIDATOR_STATE_KEY); state.setComplexValidator(false); state.setMatchedNode(true); } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { HashSet validationMessages = new LinkedHashSet<>(); if (shouldValidateSchema) { - validationMessages.addAll(validate(node, rootNode, at)); + validationMessages.addAll(validate(executionContext, node, rootNode, at)); } else { for (JsonSchema schema : this.schemas) { - schema.walk(node, rootNode, at, shouldValidateSchema); + schema.walk(executionContext, node, rootNode, at, shouldValidateSchema); } } return validationMessages; diff --git a/src/main/java/com/networknt/schema/PatternPropertiesValidator.java b/src/main/java/com/networknt/schema/PatternPropertiesValidator.java index 384071b58..c90fd92cf 100644 --- a/src/main/java/com/networknt/schema/PatternPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/PatternPropertiesValidator.java @@ -42,7 +42,7 @@ public PatternPropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSc } } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet(); @@ -57,9 +57,9 @@ public Set validate(JsonNode node, JsonNode rootNode, String JsonNode n = node.get(name); for (Map.Entry entry : schemas.entrySet()) { if (entry.getKey().matches(name)) { - Set results = entry.getValue().validate(n, rootNode, atPath(at, name)); + Set results = entry.getValue().validate(executionContext, n, rootNode, atPath(at, name)); if (results.isEmpty()) { - CollectorContext.getInstance().getEvaluatedProperties().add(atPath(at, name)); + executionContext.getCollectorContext().getEvaluatedProperties().add(atPath(at, name)); } errors.addAll(results); } diff --git a/src/main/java/com/networknt/schema/PatternValidator.java b/src/main/java/com/networknt/schema/PatternValidator.java index 6fcea0dbf..628422808 100644 --- a/src/main/java/com/networknt/schema/PatternValidator.java +++ b/src/main/java/com/networknt/schema/PatternValidator.java @@ -50,7 +50,7 @@ private boolean matches(String value) { } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); diff --git a/src/main/java/com/networknt/schema/PrefixItemsValidator.java b/src/main/java/com/networknt/schema/PrefixItemsValidator.java index 3bf99297d..c3362254f 100644 --- a/src/main/java/com/networknt/schema/PrefixItemsValidator.java +++ b/src/main/java/com/networknt/schema/PrefixItemsValidator.java @@ -57,16 +57,16 @@ public PrefixItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema p } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet<>(); // ignores non-arrays if (node.isArray()) { - Collection evaluatedItems = CollectorContext.getInstance().getEvaluatedItems(); + Collection evaluatedItems = executionContext.getCollectorContext().getEvaluatedItems(); for (int i = 0; i < Math.min(node.size(), this.tupleSchema.size()); ++i) { String path = atPath(at, i); - Set results = this.tupleSchema.get(i).validate(node.get(i), rootNode, path); + Set results = this.tupleSchema.get(i).validate(executionContext, node.get(i), rootNode, path); if (results.isEmpty()) { evaluatedItems.add(path); } else { @@ -79,7 +79,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { Set validationMessages = new LinkedHashSet<>(); if (this.applyDefaultsStrategy.shouldApplyArrayDefaults() && node.isArray()) { @@ -91,20 +91,21 @@ public Set walk(JsonNode node, JsonNode rootNode, String at, array.set(i, defaultNode); n = defaultNode; } - doWalk(validationMessages, i, n, rootNode, at, shouldValidateSchema); + doWalk(executionContext, validationMessages, i, n, rootNode, at, shouldValidateSchema); } } return validationMessages; } - private void doWalk(Set validationMessages, int i, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { - walkSchema(this.tupleSchema.get(i), node, rootNode, atPath(at, i), shouldValidateSchema, validationMessages); + private void doWalk(ExecutionContext executionContext, Set validationMessages, int i, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + walkSchema(executionContext, this.tupleSchema.get(i), node, rootNode, atPath(at, i), shouldValidateSchema, validationMessages); } - private void walkSchema(JsonSchema walkSchema, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema, Set validationMessages) { + private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema, Set validationMessages) { //@formatter:off boolean executeWalk = this.arrayItemWalkListenerRunner.runPreWalkListeners( + executionContext, ValidatorTypeCode.PREFIX_ITEMS.getValue(), node, rootNode, @@ -112,13 +113,13 @@ private void walkSchema(JsonSchema walkSchema, JsonNode node, JsonNode rootNode, walkSchema.getSchemaPath(), walkSchema.getSchemaNode(), walkSchema.getParentSchema(), - this.validationContext, - this.validationContext.getJsonSchemaFactory() + this.validationContext, this.validationContext.getJsonSchemaFactory() ); if (executeWalk) { - validationMessages.addAll(walkSchema.walk(node, rootNode, at, shouldValidateSchema)); + validationMessages.addAll(walkSchema.walk(executionContext, node, rootNode, at, shouldValidateSchema)); } this.arrayItemWalkListenerRunner.runPostWalkListeners( + executionContext, ValidatorTypeCode.PREFIX_ITEMS.getValue(), node, rootNode, @@ -127,8 +128,7 @@ private void walkSchema(JsonSchema walkSchema, JsonNode node, JsonNode rootNode, walkSchema.getSchemaNode(), walkSchema.getParentSchema(), this.validationContext, - this.validationContext.getJsonSchemaFactory(), - validationMessages + this.validationContext.getJsonSchemaFactory(), validationMessages ); //@formatter:on } diff --git a/src/main/java/com/networknt/schema/PropertiesValidator.java b/src/main/java/com/networknt/schema/PropertiesValidator.java index ac0ded532..31003284e 100644 --- a/src/main/java/com/networknt/schema/PropertiesValidator.java +++ b/src/main/java/com/networknt/schema/PropertiesValidator.java @@ -41,9 +41,9 @@ public PropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSchema pa } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = executionContext.getCollectorContext(); WalkListenerRunner propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(this.validationContext.getConfig().getPropertyWalkListeners()); @@ -68,10 +68,10 @@ public Set validate(JsonNode node, JsonNode rootNode, String if (!state.isWalkEnabled()) { //validate the child element(s) - errors.addAll(propertySchema.validate(propertyNode, rootNode, atPath(at, entry.getKey()))); + errors.addAll(propertySchema.validate(executionContext, propertyNode, rootNode, atPath(at, entry.getKey()))); } else { // check if walker is enabled. If it is enabled it is upto the walker implementation to decide about the validation. - walkSchema(entry, node, rootNode, at, state.isValidationEnabled(), errors, propertyWalkListenerRunner); + walkSchema(executionContext, entry, node, rootNode, at, state.isValidationEnabled(), errors, propertyWalkListenerRunner); } // reset the complex flag to the original value before the recursive call @@ -83,7 +83,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String } else { // check whether the node which has not matched was mandatory or not if (getParentSchema().hasRequiredValidator()) { - Set requiredErrors = getParentSchema().getRequiredValidator().validate(node, rootNode, at); + Set requiredErrors = getParentSchema().getRequiredValidator().validate(executionContext, node, rootNode, at); if (!requiredErrors.isEmpty()) { // the node was mandatory, decide which behavior to employ when validator has not matched @@ -102,17 +102,17 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { HashSet validationMessages = new LinkedHashSet<>(); if (this.applyDefaultsStrategy.shouldApplyPropertyDefaults() && null != node && node.getNodeType() == JsonNodeType.OBJECT) { applyPropertyDefaults((ObjectNode) node); } if (shouldValidateSchema) { - validationMessages.addAll(validate(node, rootNode, at)); + validationMessages.addAll(validate(executionContext, node, rootNode, at)); } else { WalkListenerRunner propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(this.validationContext.getConfig().getPropertyWalkListeners()); for (Map.Entry entry : this.schemas.entrySet()) { - walkSchema(entry, node, rootNode, at, shouldValidateSchema, validationMessages, propertyWalkListenerRunner); + walkSchema(executionContext, entry, node, rootNode, at, shouldValidateSchema, validationMessages, propertyWalkListenerRunner); } } return validationMessages; @@ -139,21 +139,21 @@ private static JsonNode getDefaultNode(final Map.Entry entry return propertySchema.getSchemaNode().get("default"); } - private void walkSchema(Map.Entry entry, JsonNode node, JsonNode rootNode, String at, + private void walkSchema(ExecutionContext executionContext, Map.Entry entry, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema, Set validationMessages, WalkListenerRunner propertyWalkListenerRunner) { JsonSchema propertySchema = entry.getValue(); JsonNode propertyNode = (node == null ? null : node.get(entry.getKey())); - boolean executeWalk = propertyWalkListenerRunner.runPreWalkListeners(ValidatorTypeCode.PROPERTIES.getValue(), - propertyNode, rootNode, atPath(at, entry.getKey()), propertySchema.getSchemaPath(), - propertySchema.getSchemaNode(), propertySchema.getParentSchema(), this.validationContext, - this.validationContext.getJsonSchemaFactory()); + boolean executeWalk = propertyWalkListenerRunner.runPreWalkListeners(executionContext, + ValidatorTypeCode.PROPERTIES.getValue(), propertyNode, rootNode, atPath(at, entry.getKey()), + propertySchema.getSchemaPath(), propertySchema.getSchemaNode(), propertySchema.getParentSchema(), + this.validationContext, this.validationContext.getJsonSchemaFactory()); if (executeWalk) { validationMessages.addAll( - propertySchema.walk(propertyNode, rootNode, atPath(at, entry.getKey()), shouldValidateSchema)); + propertySchema.walk(executionContext, propertyNode, rootNode, atPath(at, entry.getKey()), shouldValidateSchema)); } - propertyWalkListenerRunner.runPostWalkListeners(ValidatorTypeCode.PROPERTIES.getValue(), propertyNode, rootNode, - atPath(at, entry.getKey()), propertySchema.getSchemaPath(), propertySchema.getSchemaNode(), - propertySchema.getParentSchema(), this.validationContext, this.validationContext.getJsonSchemaFactory(), validationMessages); + propertyWalkListenerRunner.runPostWalkListeners(executionContext, ValidatorTypeCode.PROPERTIES.getValue(), propertyNode, + rootNode, atPath(at, entry.getKey()), propertySchema.getSchemaPath(), + propertySchema.getSchemaNode(), propertySchema.getParentSchema(), this.validationContext, this.validationContext.getJsonSchemaFactory(), validationMessages); } diff --git a/src/main/java/com/networknt/schema/PropertyNamesValidator.java b/src/main/java/com/networknt/schema/PropertyNamesValidator.java index 5b394636b..40f750a4b 100644 --- a/src/main/java/com/networknt/schema/PropertyNamesValidator.java +++ b/src/main/java/com/networknt/schema/PropertyNamesValidator.java @@ -34,14 +34,14 @@ public PropertyNamesValidator(String schemaPath, JsonNode schemaNode, JsonSchema innerSchema = validationContext.newSchema(schemaPath, schemaNode, parentSchema); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet(); for (Iterator it = node.fieldNames(); it.hasNext(); ) { final String pname = it.next(); final TextNode pnameText = TextNode.valueOf(pname); - final Set schemaErrors = innerSchema.validate(pnameText, node, atPath(at, pname)); + final Set schemaErrors = innerSchema.validate(executionContext, pnameText, node, atPath(at, pname)); for (final ValidationMessage schemaError : schemaErrors) { final String path = schemaError.getPath(); String msg = schemaError.getMessage(); diff --git a/src/main/java/com/networknt/schema/ReadOnlyValidator.java b/src/main/java/com/networknt/schema/ReadOnlyValidator.java index 2981d7dd6..719c1632e 100644 --- a/src/main/java/com/networknt/schema/ReadOnlyValidator.java +++ b/src/main/java/com/networknt/schema/ReadOnlyValidator.java @@ -38,7 +38,7 @@ public ReadOnlyValidator(String schemaPath, JsonNode schemaNode, JsonSchema pare } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors= new HashSet<>(); if (this.readOnly) { diff --git a/src/main/java/com/networknt/schema/RecursiveRefValidator.java b/src/main/java/com/networknt/schema/RecursiveRefValidator.java index 358562e13..b43105d24 100644 --- a/src/main/java/com/networknt/schema/RecursiveRefValidator.java +++ b/src/main/java/com/networknt/schema/RecursiveRefValidator.java @@ -44,8 +44,8 @@ public RecursiveRefValidator(String schemaPath, JsonNode schemaNode, JsonSchema } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { - CollectorContext collectorContext = CollectorContext.getInstance(); + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { + CollectorContext collectorContext = executionContext.getCollectorContext(); Set errors = new HashSet<>(); @@ -59,7 +59,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String // these schemas will be cached along with config. We have to replace the config for cached $ref references // with the latest config. Reset the config. schema.getValidationContext().setConfig(getParentSchema().getValidationContext().getConfig()); - errors = schema.validate(node, rootNode, at); + errors = schema.validate(executionContext, node, rootNode, at); } } finally { Scope scope = collectorContext.exitDynamicScope(); @@ -72,8 +72,8 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { - CollectorContext collectorContext = CollectorContext.getInstance(); + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + CollectorContext collectorContext = executionContext.getCollectorContext(); Set errors = new HashSet<>(); @@ -87,7 +87,7 @@ public Set walk(JsonNode node, JsonNode rootNode, String at, // these schemas will be cached along with config. We have to replace the config for cached $ref references // with the latest config. Reset the config. schema.getValidationContext().setConfig(getParentSchema().getValidationContext().getConfig()); - errors = schema.walk(node, rootNode, at, shouldValidateSchema); + errors = schema.walk(executionContext, node, rootNode, at, shouldValidateSchema); } } finally { Scope scope = collectorContext.exitDynamicScope(); diff --git a/src/main/java/com/networknt/schema/RefValidator.java b/src/main/java/com/networknt/schema/RefValidator.java index 2867e996e..356ffbabc 100644 --- a/src/main/java/com/networknt/schema/RefValidator.java +++ b/src/main/java/com/networknt/schema/RefValidator.java @@ -130,8 +130,8 @@ private static URI determineSchemaUrn(final URNFactory urnFactory, final String } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { - CollectorContext collectorContext = CollectorContext.getInstance(); + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { + CollectorContext collectorContext = executionContext.getCollectorContext(); Set errors = new HashSet<>(); @@ -143,7 +143,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String // with the latest config. Reset the config. this.schema.getSchema().getValidationContext().setConfig(this.parentSchema.getValidationContext().getConfig()); if (this.schema != null) { - errors = this.schema.validate(node, rootNode, at); + errors = this.schema.validate(executionContext, node, rootNode, at); } else { errors = Collections.emptySet(); } @@ -157,8 +157,8 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { - CollectorContext collectorContext = CollectorContext.getInstance(); + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + CollectorContext collectorContext = executionContext.getCollectorContext(); Set errors = new HashSet<>(); @@ -170,7 +170,7 @@ public Set walk(JsonNode node, JsonNode rootNode, String at, // with the latest config. Reset the config. this.schema.getSchema().getValidationContext().setConfig(this.parentSchema.getValidationContext().getConfig()); if (this.schema != null) { - errors = this.schema.walk(node, rootNode, at, shouldValidateSchema); + errors = this.schema.walk(executionContext, node, rootNode, at, shouldValidateSchema); } return errors; } finally { diff --git a/src/main/java/com/networknt/schema/RequiredValidator.java b/src/main/java/com/networknt/schema/RequiredValidator.java index 5d605f084..0a1cbebd7 100644 --- a/src/main/java/com/networknt/schema/RequiredValidator.java +++ b/src/main/java/com/networknt/schema/RequiredValidator.java @@ -39,7 +39,7 @@ public RequiredValidator(String schemaPath, JsonNode schemaNode, JsonSchema pare parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (!node.isObject()) { diff --git a/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java b/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java index e9eee30d2..24e42b5c5 100644 --- a/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java +++ b/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java @@ -22,6 +22,7 @@ import com.networknt.schema.walk.JsonSchemaWalkListener; import java.util.*; +import java.util.function.Supplier; public class SchemaValidatorsConfig { @@ -103,12 +104,6 @@ public class SchemaValidatorsConfig { */ private boolean handleNullableField = true; - /** - * When set to true resets the {@link CollectorContext} by calling - * {@link CollectorContext#reset()}. - */ - private boolean resetCollectorContext = true; - /** * When set to true assumes that schema is used to validate incoming data from an API. */ @@ -133,7 +128,7 @@ public class SchemaValidatorsConfig { private final List itemWalkListeners = new ArrayList<>(); - private CollectorContext collectorContext; + private Supplier executionContextSupplier; private boolean loadCollectors = true; @@ -218,8 +213,8 @@ public void setTypeLoose(boolean typeLoose) { } /** - * When enabled, {@link JsonValidator#validate(JsonNode, JsonNode, String)} or - * {@link JsonValidator#validate(JsonNode)} doesn't return any + * When enabled, {@link JsonValidator#validate(ExecutionContext, JsonNode, JsonNode, String)} or + * {@link JsonValidator#validate(ExecutionContext, JsonNode)} doesn't return any * {@link Set}<{@link ValidationMessage}>, instead a * {@link JsonSchemaException} is thrown as soon as a validation errors is * discovered. @@ -367,12 +362,12 @@ public List getArrayItemWalkListeners() { public SchemaValidatorsConfig() { } - public CollectorContext getCollectorContext() { - return this.collectorContext; + public Supplier getExecutionContextSupplier() { + return this.executionContextSupplier; } - public void setCollectorContext(CollectorContext collectorContext) { - this.collectorContext = collectorContext; + public void setExecutionContextSupplier(Supplier executionContextSupplier) { + this.executionContextSupplier = executionContextSupplier; } public boolean isLosslessNarrowing() { @@ -438,14 +433,6 @@ public boolean doLoadCollectors() { return this.loadCollectors; } - public boolean isResetCollectorContext() { - return this.resetCollectorContext; - } - - public void setResetCollectorContext(boolean resetCollectorContext) { - this.resetCollectorContext = resetCollectorContext; - } - public boolean isReadOnly() { return null != this.readOnly && this.readOnly; } diff --git a/src/main/java/com/networknt/schema/ThreadInfo.java b/src/main/java/com/networknt/schema/ThreadInfo.java deleted file mode 100644 index d0a98b4f0..000000000 --- a/src/main/java/com/networknt/schema/ThreadInfo.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2020 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -public class ThreadInfo { - - private static ThreadLocal> threadLocal = new ThreadLocal>() { - @Override - protected java.util.Map initialValue() { - return new HashMap<>(); - } - }; - - public static Object get(String key) { - return threadLocal.get().get(key); - } - - public static Object computeIfAbsent(String key, Function mappingFunction) { - return threadLocal.get().computeIfAbsent(key, mappingFunction); - } - - public static void set(String key, Object value) { - Map threadLocalMap = threadLocal.get(); - threadLocalMap.put(key, value); - } - - public static void remove(String key) { - Map threadLocalMap = threadLocal.get(); - threadLocalMap.remove(key); - } - -} diff --git a/src/main/java/com/networknt/schema/TrueValidator.java b/src/main/java/com/networknt/schema/TrueValidator.java index 54f33f21b..23f981636 100644 --- a/src/main/java/com/networknt/schema/TrueValidator.java +++ b/src/main/java/com/networknt/schema/TrueValidator.java @@ -29,7 +29,7 @@ public TrueValidator(String schemaPath, final JsonNode schemaNode, JsonSchema pa super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.TRUE, validationContext); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); // For the true validator, it is always valid which means there is no ValidationMessage. return Collections.emptySet(); diff --git a/src/main/java/com/networknt/schema/TypeValidator.java b/src/main/java/com/networknt/schema/TypeValidator.java index 3e20d1c72..1a2b9f8af 100644 --- a/src/main/java/com/networknt/schema/TypeValidator.java +++ b/src/main/java/com/networknt/schema/TypeValidator.java @@ -51,11 +51,11 @@ public boolean equalsToSchemaType(JsonNode node) { } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (this.schemaType == JsonType.UNION) { - return this.unionTypeValidator.validate(node, rootNode, at); + return this.unionTypeValidator.validate(executionContext, node, rootNode, at); } if (!equalsToSchemaType(node)) { @@ -68,9 +68,9 @@ public Set validate(JsonNode node, JsonNode rootNode, String // Hack to catch patternProperties like "^foo":"value" if (this.schemaPath.endsWith("/type")) { if (rootNode.isArray()) { - CollectorContext.getInstance().getEvaluatedItems().add(at); + executionContext.getCollectorContext().getEvaluatedItems().add(at); } else if (rootNode.isObject()) { - CollectorContext.getInstance().getEvaluatedProperties().add(at); + executionContext.getCollectorContext().getEvaluatedProperties().add(at); } } return Collections.emptySet(); diff --git a/src/main/java/com/networknt/schema/UnevaluatedItemsValidator.java b/src/main/java/com/networknt/schema/UnevaluatedItemsValidator.java index ea073f8ea..3d55421c4 100644 --- a/src/main/java/com/networknt/schema/UnevaluatedItemsValidator.java +++ b/src/main/java/com/networknt/schema/UnevaluatedItemsValidator.java @@ -40,11 +40,11 @@ public UnevaluatedItemsValidator(String schemaPath, JsonNode schemaNode, JsonSch } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { if (this.disabled || !node.isArray()) return Collections.emptySet(); debug(logger, node, rootNode, at); - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = executionContext.getCollectorContext(); collectorContext.exitDynamicScope(); try { @@ -56,7 +56,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String return Collections.emptySet(); } - Set unevaluatedPaths = unevaluatedPaths(allPaths); + Set unevaluatedPaths = unevaluatedPaths(collectorContext, allPaths); // Short-circuit since schema is 'false' if (super.schemaNode.isBoolean() && !super.schemaNode.asBoolean() && !unevaluatedPaths.isEmpty()) { @@ -67,7 +67,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String unevaluatedPaths.forEach(path -> { String pointer = getPathType().convertToJsonPointer(path); JsonNode property = rootNode.at(pointer); - if (!this.schema.validate(property, rootNode, path).isEmpty()) { + if (!this.schema.validate(executionContext, property, rootNode, path).isEmpty()) { failingPaths.add(path); } }); @@ -101,9 +101,9 @@ private Set reportUnevaluatedPaths(Set unevaluatedPat return Collections.singleton(buildValidationMessage(String.join("\n ", paths))); } - private static Set unevaluatedPaths(Set allPaths) { + private static Set unevaluatedPaths(CollectorContext collectorContext, Set allPaths) { Set unevaluatedProperties = new HashSet<>(allPaths); - unevaluatedProperties.removeAll(CollectorContext.getInstance().getEvaluatedItems()); + unevaluatedProperties.removeAll(collectorContext.getEvaluatedItems()); return unevaluatedProperties; } diff --git a/src/main/java/com/networknt/schema/UnevaluatedPropertiesValidator.java b/src/main/java/com/networknt/schema/UnevaluatedPropertiesValidator.java index 82998a882..3b0d04487 100644 --- a/src/main/java/com/networknt/schema/UnevaluatedPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/UnevaluatedPropertiesValidator.java @@ -40,11 +40,11 @@ public UnevaluatedPropertiesValidator(String schemaPath, JsonNode schemaNode, Js } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { if (this.disabled || !node.isObject()) return Collections.emptySet(); debug(logger, node, rootNode, at); - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = executionContext.getCollectorContext(); collectorContext.exitDynamicScope(); try { @@ -56,7 +56,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String return Collections.emptySet(); } - Set unevaluatedPaths = unevaluatedPaths(allPaths); + Set unevaluatedPaths = unevaluatedPaths(collectorContext, allPaths); // Short-circuit since schema is 'false' if (super.schemaNode.isBoolean() && !super.schemaNode.asBoolean() && !unevaluatedPaths.isEmpty()) { @@ -67,7 +67,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String unevaluatedPaths.forEach(path -> { String pointer = getPathType().convertToJsonPointer(path); JsonNode property = rootNode.at(pointer); - if (!this.schema.validate(property, rootNode, path).isEmpty()) { + if (!this.schema.validate(executionContext, property, rootNode, path).isEmpty()) { failingPaths.add(path); } }); @@ -100,9 +100,9 @@ private Set reportUnevaluatedPaths(Set unevaluatedPat return Collections.singleton(buildValidationMessage(String.join("\n ", paths))); } - private static Set unevaluatedPaths(Set allPaths) { + private static Set unevaluatedPaths(CollectorContext collectorContext, Set allPaths) { Set unevaluatedProperties = new HashSet<>(allPaths); - unevaluatedProperties.removeAll(CollectorContext.getInstance().getEvaluatedProperties()); + unevaluatedProperties.removeAll(collectorContext.getEvaluatedProperties()); return unevaluatedProperties; } } diff --git a/src/main/java/com/networknt/schema/UnionTypeValidator.java b/src/main/java/com/networknt/schema/UnionTypeValidator.java index 2841916d8..07d1704a3 100644 --- a/src/main/java/com/networknt/schema/UnionTypeValidator.java +++ b/src/main/java/com/networknt/schema/UnionTypeValidator.java @@ -62,7 +62,7 @@ public UnionTypeValidator(String schemaPath, JsonNode schemaNode, JsonSchema par error = errorBuilder.toString(); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); JsonType nodeType = TypeFactory.getValueNodeType(node, validationContext.getConfig()); @@ -70,7 +70,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String boolean valid = false; for (JsonValidator schema : schemas) { - Set errors = schema.validate(node, rootNode, at); + Set errors = schema.validate(executionContext, node, rootNode, at); if (errors == null || errors.isEmpty()) { valid = true; break; diff --git a/src/main/java/com/networknt/schema/UniqueItemsValidator.java b/src/main/java/com/networknt/schema/UniqueItemsValidator.java index e34489090..e84567342 100644 --- a/src/main/java/com/networknt/schema/UniqueItemsValidator.java +++ b/src/main/java/com/networknt/schema/UniqueItemsValidator.java @@ -38,7 +38,7 @@ public UniqueItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema p parseErrorCode(getValidatorType().getErrorCodeKey()); } - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); if (unique) { diff --git a/src/main/java/com/networknt/schema/ValidationResult.java b/src/main/java/com/networknt/schema/ValidationResult.java index 1b247fbfb..7c04196ad 100644 --- a/src/main/java/com/networknt/schema/ValidationResult.java +++ b/src/main/java/com/networknt/schema/ValidationResult.java @@ -21,20 +21,23 @@ public class ValidationResult { private Set validationMessages; - private CollectorContext collectorContext; + private ExecutionContext executionContext; - public ValidationResult(Set validationMessages, CollectorContext collectorContext) { + public ValidationResult(Set validationMessages, ExecutionContext executionContext) { super(); this.validationMessages = validationMessages; - this.collectorContext = collectorContext; + this.executionContext = executionContext; } public Set getValidationMessages() { return validationMessages; } - public CollectorContext getCollectorContext() { - return collectorContext; + public ExecutionContext getExecutionContext() { + return executionContext; } + public CollectorContext getCollectorContext() { + return getExecutionContext().getCollectorContext(); + } } diff --git a/src/main/java/com/networknt/schema/WriteOnlyValidator.java b/src/main/java/com/networknt/schema/WriteOnlyValidator.java index b86bab57a..4dcd63872 100644 --- a/src/main/java/com/networknt/schema/WriteOnlyValidator.java +++ b/src/main/java/com/networknt/schema/WriteOnlyValidator.java @@ -22,7 +22,7 @@ public WriteOnlyValidator(String schemaPath, JsonNode schemaNode, JsonSchema par } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors= new HashSet<>(); if (this.writeOnly) { diff --git a/src/main/java/com/networknt/schema/format/AbstractFormat.java b/src/main/java/com/networknt/schema/format/AbstractFormat.java index 12bc6c623..d0b9f270b 100644 --- a/src/main/java/com/networknt/schema/format/AbstractFormat.java +++ b/src/main/java/com/networknt/schema/format/AbstractFormat.java @@ -16,24 +16,20 @@ package com.networknt.schema.format; -import com.networknt.schema.Format; - -public abstract class AbstractFormat implements Format { - private final String name; - private final String errorMessageDescription; +import com.networknt.schema.ExecutionContext; +/** + * Used for Formats that do not need to use the {@link ExecutionContext}. + */ +public abstract class AbstractFormat extends BaseFormat { public AbstractFormat(String name, String errorMessageDescription) { - this.name = name; - this.errorMessageDescription = errorMessageDescription; + super(name, errorMessageDescription); } @Override - public String getName() { - return name; + public boolean matches(ExecutionContext executionContext, String value) { + return matches(value); } - @Override - public String getErrorMessageDescription() { - return errorMessageDescription; - } + abstract public boolean matches(String value); } diff --git a/src/main/java/com/networknt/schema/format/BaseFormat.java b/src/main/java/com/networknt/schema/format/BaseFormat.java new file mode 100644 index 000000000..da720fff4 --- /dev/null +++ b/src/main/java/com/networknt/schema/format/BaseFormat.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.format; + +import com.networknt.schema.Format; + +/** + * Base implementation of {@link Format}. + */ +public abstract class BaseFormat implements Format { + private final String name; + private final String errorMessageDescription; + + public BaseFormat(String name, String errorMessageDescription) { + this.name = name; + this.errorMessageDescription = errorMessageDescription; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getErrorMessageDescription() { + return errorMessageDescription; + } +} diff --git a/src/main/java/com/networknt/schema/format/DateTimeValidator.java b/src/main/java/com/networknt/schema/format/DateTimeValidator.java index a1ffe9012..cc4fd7d0f 100644 --- a/src/main/java/com/networknt/schema/format/DateTimeValidator.java +++ b/src/main/java/com/networknt/schema/format/DateTimeValidator.java @@ -20,6 +20,7 @@ import com.ethlo.time.LeapSecondException; import com.fasterxml.jackson.databind.JsonNode; import com.networknt.schema.BaseJsonValidator; +import com.networknt.schema.ExecutionContext; import com.networknt.schema.JsonSchema; import com.networknt.schema.JsonType; import com.networknt.schema.TypeFactory; @@ -46,7 +47,7 @@ public DateTimeValidator(String schemaPath, JsonNode schemaNode, JsonSchema pare } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); Set errors = new LinkedHashSet<>(); diff --git a/src/main/java/com/networknt/schema/walk/AbstractWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/AbstractWalkListenerRunner.java index 96bb9950f..761c8e429 100644 --- a/src/main/java/com/networknt/schema/walk/AbstractWalkListenerRunner.java +++ b/src/main/java/com/networknt/schema/walk/AbstractWalkListenerRunner.java @@ -1,6 +1,7 @@ package com.networknt.schema.walk; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; import com.networknt.schema.JsonSchema; import com.networknt.schema.JsonSchemaFactory; import com.networknt.schema.ValidationContext; @@ -11,11 +12,11 @@ public abstract class AbstractWalkListenerRunner implements WalkListenerRunner { - protected WalkEvent constructWalkEvent(String keyWordName, JsonNode node, JsonNode rootNode, String at, - String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, - JsonSchemaFactory currentJsonSchemaFactory) { - return WalkEvent.builder().at(at).keyWordName(keyWordName).node(node).parentSchema(parentSchema) - .rootNode(rootNode).schemaNode(schemaNode).schemaPath(schemaPath) + protected WalkEvent constructWalkEvent(ExecutionContext executionContext, String keyWordName, JsonNode node, JsonNode rootNode, + String at, String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, + ValidationContext validationContext, JsonSchemaFactory currentJsonSchemaFactory) { + return WalkEvent.builder().executionContext(executionContext).at(at).keyWordName(keyWordName).node(node) + .parentSchema(parentSchema).rootNode(rootNode).schemaNode(schemaNode).schemaPath(schemaPath) .currentJsonSchemaFactory(currentJsonSchemaFactory).validationContext(validationContext).build(); } diff --git a/src/main/java/com/networknt/schema/walk/DefaultItemWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/DefaultItemWalkListenerRunner.java index 76b33ef26..eb4360a70 100644 --- a/src/main/java/com/networknt/schema/walk/DefaultItemWalkListenerRunner.java +++ b/src/main/java/com/networknt/schema/walk/DefaultItemWalkListenerRunner.java @@ -1,6 +1,7 @@ package com.networknt.schema.walk; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; import com.networknt.schema.JsonSchema; import com.networknt.schema.JsonSchemaFactory; import com.networknt.schema.ValidationContext; @@ -18,20 +19,20 @@ public DefaultItemWalkListenerRunner(List itemWalkListen } @Override - public boolean runPreWalkListeners(String keyWordPath, JsonNode node, JsonNode rootNode, String at, - String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, - JsonSchemaFactory currentJsonSchemaFactory) { - WalkEvent walkEvent = constructWalkEvent(keyWordPath, node, rootNode, at, schemaPath, schemaNode, parentSchema, validationContext, - currentJsonSchemaFactory); + public boolean runPreWalkListeners(ExecutionContext executionContext, String keyWordPath, JsonNode node, JsonNode rootNode, + String at, String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, + ValidationContext validationContext, JsonSchemaFactory currentJsonSchemaFactory) { + WalkEvent walkEvent = constructWalkEvent(executionContext, keyWordPath, node, rootNode, at, schemaPath, schemaNode, parentSchema, + validationContext, currentJsonSchemaFactory); return runPreWalkListeners(itemWalkListeners, walkEvent); } @Override - public void runPostWalkListeners(String keyWordPath, JsonNode node, JsonNode rootNode, String at, String schemaPath, - JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, JsonSchemaFactory currentJsonSchemaFactory, - Set validationMessages) { - WalkEvent walkEvent = constructWalkEvent(keyWordPath, node, rootNode, at, schemaPath, schemaNode, parentSchema, - validationContext, currentJsonSchemaFactory); + public void runPostWalkListeners(ExecutionContext executionContext, String keyWordPath, JsonNode node, JsonNode rootNode, String at, + String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, + JsonSchemaFactory currentJsonSchemaFactory, Set validationMessages) { + WalkEvent walkEvent = constructWalkEvent(executionContext, keyWordPath, node, rootNode, at, schemaPath, schemaNode, + parentSchema, validationContext, currentJsonSchemaFactory); runPostWalkListeners(itemWalkListeners, walkEvent, validationMessages); } diff --git a/src/main/java/com/networknt/schema/walk/DefaultKeywordWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/DefaultKeywordWalkListenerRunner.java index f94b99db2..7aaa729e3 100644 --- a/src/main/java/com/networknt/schema/walk/DefaultKeywordWalkListenerRunner.java +++ b/src/main/java/com/networknt/schema/walk/DefaultKeywordWalkListenerRunner.java @@ -20,14 +20,14 @@ protected String getKeywordName(String keyWordPath) { } @Override - public boolean runPreWalkListeners(String keyWordPath, JsonNode node, JsonNode rootNode, String at, - String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, - ValidationContext validationContext, - JsonSchemaFactory currentJsonSchemaFactory) { + public boolean runPreWalkListeners(ExecutionContext executionContext, String keyWordPath, JsonNode node, JsonNode rootNode, + String at, String schemaPath, JsonNode schemaNode, + JsonSchema parentSchema, + ValidationContext validationContext, JsonSchemaFactory currentJsonSchemaFactory) { String keyword = getKeywordName(keyWordPath); boolean continueRunningListenersAndWalk = true; - WalkEvent keywordWalkEvent = constructWalkEvent(keyword, node, rootNode, at, schemaPath, schemaNode, - parentSchema, validationContext, currentJsonSchemaFactory); + WalkEvent keywordWalkEvent = constructWalkEvent(executionContext, keyword, node, rootNode, at, schemaPath, + schemaNode, parentSchema, validationContext, currentJsonSchemaFactory); // Run Listeners that are setup only for this keyword. List currentKeywordListeners = keywordWalkListenersMap.get(keyword); continueRunningListenersAndWalk = runPreWalkListeners(currentKeywordListeners, keywordWalkEvent); @@ -41,14 +41,14 @@ public boolean runPreWalkListeners(String keyWordPath, JsonNode node, JsonNode r } @Override - public void runPostWalkListeners(String keyWordPath, JsonNode node, JsonNode rootNode, String at, String schemaPath, - JsonNode schemaNode, JsonSchema parentSchema, + public void runPostWalkListeners(ExecutionContext executionContext, String keyWordPath, JsonNode node, JsonNode rootNode, String at, + String schemaPath, JsonNode schemaNode, + JsonSchema parentSchema, ValidationContext validationContext, - JsonSchemaFactory currentJsonSchemaFactory, - Set validationMessages) { + JsonSchemaFactory currentJsonSchemaFactory, Set validationMessages) { String keyword = getKeywordName(keyWordPath); - WalkEvent keywordWalkEvent = constructWalkEvent(keyword, node, rootNode, at, schemaPath, schemaNode, - parentSchema, validationContext, currentJsonSchemaFactory); + WalkEvent keywordWalkEvent = constructWalkEvent(executionContext, keyword, node, rootNode, at, schemaPath, + schemaNode, parentSchema, validationContext, currentJsonSchemaFactory); // Run Listeners that are setup only for this keyword. List currentKeywordListeners = keywordWalkListenersMap.get(keyword); runPostWalkListeners(currentKeywordListeners, keywordWalkEvent, validationMessages); diff --git a/src/main/java/com/networknt/schema/walk/DefaultPropertyWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/DefaultPropertyWalkListenerRunner.java index 58b78cb3f..0ea6a7c5d 100644 --- a/src/main/java/com/networknt/schema/walk/DefaultPropertyWalkListenerRunner.java +++ b/src/main/java/com/networknt/schema/walk/DefaultPropertyWalkListenerRunner.java @@ -1,6 +1,7 @@ package com.networknt.schema.walk; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; import com.networknt.schema.JsonSchema; import com.networknt.schema.JsonSchemaFactory; import com.networknt.schema.ValidationContext; @@ -18,20 +19,20 @@ public DefaultPropertyWalkListenerRunner(List propertyWa } @Override - public boolean runPreWalkListeners(String keyWordPath, JsonNode node, JsonNode rootNode, String at, - String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, - JsonSchemaFactory currentJsonSchemaFactory) { - WalkEvent walkEvent = constructWalkEvent(keyWordPath, node, rootNode, at, schemaPath, schemaNode, parentSchema, - validationContext, currentJsonSchemaFactory); + public boolean runPreWalkListeners(ExecutionContext executionContext, String keyWordPath, JsonNode node, JsonNode rootNode, + String at, String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, + ValidationContext validationContext, JsonSchemaFactory currentJsonSchemaFactory) { + WalkEvent walkEvent = constructWalkEvent(executionContext, keyWordPath, node, rootNode, at, schemaPath, schemaNode, + parentSchema, validationContext, currentJsonSchemaFactory); return runPreWalkListeners(propertyWalkListeners, walkEvent); } @Override - public void runPostWalkListeners(String keyWordPath, JsonNode node, JsonNode rootNode, String at, String schemaPath, - JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, JsonSchemaFactory currentJsonSchemaFactory, - Set validationMessages) { - WalkEvent walkEvent = constructWalkEvent(keyWordPath, node, rootNode, at, schemaPath, schemaNode, parentSchema, - validationContext, currentJsonSchemaFactory); + public void runPostWalkListeners(ExecutionContext executionContext, String keyWordPath, JsonNode node, JsonNode rootNode, String at, + String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, + JsonSchemaFactory currentJsonSchemaFactory, Set validationMessages) { + WalkEvent walkEvent = constructWalkEvent(executionContext, keyWordPath, node, rootNode, at, schemaPath, schemaNode, + parentSchema, validationContext, currentJsonSchemaFactory); runPostWalkListeners(propertyWalkListeners, walkEvent, validationMessages); } diff --git a/src/main/java/com/networknt/schema/walk/JsonSchemaWalker.java b/src/main/java/com/networknt/schema/walk/JsonSchemaWalker.java index bb940b222..5d6d9d043 100644 --- a/src/main/java/com/networknt/schema/walk/JsonSchemaWalker.java +++ b/src/main/java/com/networknt/schema/walk/JsonSchemaWalker.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.networknt.schema.BaseJsonValidator; +import com.networknt.schema.ExecutionContext; import com.networknt.schema.ValidationMessage; import java.util.Set; @@ -14,16 +15,17 @@ public interface JsonSchemaWalker { * cutting concerns like logging or instrumentation. This method also performs * the validation if {@code shouldValidateSchema} is set to true.
*
- * {@link BaseJsonValidator#walk(JsonNode, JsonNode, String, boolean)} provides + * {@link BaseJsonValidator#walk(ExecutionContext, JsonNode, JsonNode, String, boolean)} provides * a default implementation of this method. However validators that parse * sub-schemas should override this method to call walk method on those * sub-schemas. * + * @param executionContext ExecutionContext * @param node JsonNode * @param rootNode JsonNode * @param at String * @param shouldValidateSchema boolean * @return a set of validation messages if shouldValidateSchema is true. */ - Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema); + Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema); } diff --git a/src/main/java/com/networknt/schema/walk/WalkEvent.java b/src/main/java/com/networknt/schema/walk/WalkEvent.java index 6543e1591..83c020b31 100644 --- a/src/main/java/com/networknt/schema/walk/WalkEvent.java +++ b/src/main/java/com/networknt/schema/walk/WalkEvent.java @@ -1,6 +1,7 @@ package com.networknt.schema.walk; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; import com.networknt.schema.JsonSchema; import com.networknt.schema.JsonSchemaFactory; import com.networknt.schema.SchemaValidatorsConfig; @@ -13,6 +14,7 @@ */ public class WalkEvent { + private ExecutionContext executionContext; private String schemaPath; private JsonNode schemaNode; private JsonSchema parentSchema; @@ -23,6 +25,10 @@ public class WalkEvent { private JsonSchemaFactory currentJsonSchemaFactory; private ValidationContext validationContext; + public ExecutionContext getExecutionContext() { + return executionContext; + } + public String getSchemaPath() { return schemaPath; } @@ -75,6 +81,11 @@ static class WalkEventBuilder { walkEvent = new WalkEvent(); } + public WalkEventBuilder executionContext(ExecutionContext executionContext) { + walkEvent.executionContext = executionContext; + return this; + } + public WalkEventBuilder schemaPath(String schemaPath) { walkEvent.schemaPath = schemaPath; return this; diff --git a/src/main/java/com/networknt/schema/walk/WalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/WalkListenerRunner.java index 5eb331a61..b0d45be86 100644 --- a/src/main/java/com/networknt/schema/walk/WalkListenerRunner.java +++ b/src/main/java/com/networknt/schema/walk/WalkListenerRunner.java @@ -1,6 +1,7 @@ package com.networknt.schema.walk; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; import com.networknt.schema.JsonSchema; import com.networknt.schema.JsonSchemaFactory; import com.networknt.schema.ValidationContext; @@ -10,11 +11,11 @@ public interface WalkListenerRunner { - public boolean runPreWalkListeners(String keyWordPath, JsonNode node, JsonNode rootNode, String at, - String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, JsonSchemaFactory jsonSchemaFactory); + public boolean runPreWalkListeners(ExecutionContext executionContext, String keyWordPath, JsonNode node, JsonNode rootNode, + String at, String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, JsonSchemaFactory jsonSchemaFactory); - public void runPostWalkListeners(String keyWordPath, JsonNode node, JsonNode rootNode, String at, String schemaPath, - JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, JsonSchemaFactory jsonSchemaFactory, - Set validationMessages); + public void runPostWalkListeners(ExecutionContext executionContext, String keyWordPath, JsonNode node, JsonNode rootNode, String at, + String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, + JsonSchemaFactory jsonSchemaFactory, Set validationMessages); } diff --git a/src/test/java/com/networknt/schema/CollectorContextTest.java b/src/test/java/com/networknt/schema/CollectorContextTest.java index da5b8dc0a..164f5b22b 100644 --- a/src/test/java/com/networknt/schema/CollectorContextTest.java +++ b/src/test/java/com/networknt/schema/CollectorContextTest.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -37,19 +36,12 @@ public class CollectorContextTest { private JsonSchema jsonSchema; private JsonSchema jsonSchemaForCombine; - + @BeforeEach public void setup() throws Exception { setupSchema(); } - @AfterEach - public void cleanup() { - if (CollectorContext.getInstance() != null) { - CollectorContext.getInstance().reset(); - } - } - @SuppressWarnings("unchecked") @Test public void testCollectorContextWithKeyword() throws Exception { @@ -113,15 +105,15 @@ public void testCollectorGetAll() throws JsonMappingException, JsonProcessingExc Assertions.assertEquals(((List) collectorContext.get(SAMPLE_COLLECTOR)).size(), 1); Assertions.assertEquals(((List) collectorContext.get(SAMPLE_COLLECTOR_OTHER)).size(), 3); } - + private JsonMetaSchema getJsonMetaSchema(String uri) throws Exception { JsonMetaSchema jsonMetaSchema = JsonMetaSchema.builder(uri, JsonMetaSchema.getV201909()) .addKeyword(new CustomKeyword()).addKeyword(new CustomKeyword1()).addFormat(new Format() { @SuppressWarnings("unchecked") @Override - public boolean matches(String value) { - CollectorContext collectorContext = CollectorContext.getInstance(); + public boolean matches(ExecutionContext executionContext, String value) { + CollectorContext collectorContext = executionContext.getCollectorContext(); if (collectorContext.get(SAMPLE_COLLECTOR) == null) { collectorContext.add(SAMPLE_COLLECTOR, new ArrayList()); } @@ -151,7 +143,6 @@ private void setupSchema() throws Exception { .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)).addMetaSchema(metaSchema) .build(); SchemaValidatorsConfig schemaValidatorsConfig = new SchemaValidatorsConfig(); - schemaValidatorsConfig.setResetCollectorContext(false); this.jsonSchema = schemaFactory.getSchema(getSchemaString(), schemaValidatorsConfig); this.jsonSchemaForCombine = schemaFactory.getSchema(getSchemaStringMultipleProperties(), schemaValidatorsConfig); } @@ -220,7 +211,7 @@ private class ValidationThread implements Runnable { private String name; private ValidationResult validationResult; - + ValidationThread(String data, String name) { this.name = name; this.data = data; @@ -279,9 +270,9 @@ public JsonValidator newValidator(String schemaPath, JsonNode schemaNode, JsonSc private class CustomValidator implements JsonValidator { @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { // Get an instance of collector context. - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = executionContext.getCollectorContext(); if (collectorContext.get(SAMPLE_COLLECTOR) == null) { collectorContext.add(SAMPLE_COLLECTOR, new CustomCollector()); } @@ -290,12 +281,12 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set validate(JsonNode rootNode) { - return validate(rootNode, rootNode, PathType.DEFAULT.getRoot()); + public Set validate(ExecutionContext executionContext, JsonNode rootNode) { + return validate(executionContext, rootNode, rootNode, PathType.DEFAULT.getRoot()); } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { // Ignore this method for testing. return null; } @@ -354,9 +345,9 @@ public JsonValidator newValidator(String schemaPath, JsonNode schemaNode, JsonSc private class CustomValidator1 implements JsonValidator { @SuppressWarnings("unchecked") @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { // Get an instance of collector context. - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = executionContext.getCollectorContext(); // If collector type is not added to context add one. if (collectorContext.get(SAMPLE_COLLECTOR_OTHER) == null) { collectorContext.add(SAMPLE_COLLECTOR_OTHER, new ArrayList()); @@ -367,12 +358,12 @@ public Set validate(JsonNode node, JsonNode rootNode, String } @Override - public Set validate(JsonNode rootNode) { - return validate(rootNode, rootNode, PathType.DEFAULT.getRoot()); + public Set validate(ExecutionContext executionContext, JsonNode rootNode) { + return validate(executionContext, rootNode, rootNode, PathType.DEFAULT.getRoot()); } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { // Ignore this method for testing. return null; } diff --git a/src/test/java/com/networknt/schema/CustomMetaSchemaTest.java b/src/test/java/com/networknt/schema/CustomMetaSchemaTest.java index 3047cec49..e900fe3c1 100644 --- a/src/test/java/com/networknt/schema/CustomMetaSchemaTest.java +++ b/src/test/java/com/networknt/schema/CustomMetaSchemaTest.java @@ -60,7 +60,7 @@ private Validator(String keyword, List enumValues, List enumName } @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { String value = node.asText(); int idx = enumValues.indexOf(value); if (idx < 0) { diff --git a/src/test/java/com/networknt/schema/HTTPServiceSupport.java b/src/test/java/com/networknt/schema/HTTPServiceSupport.java index 29ab33546..bf1e826b0 100644 --- a/src/test/java/com/networknt/schema/HTTPServiceSupport.java +++ b/src/test/java/com/networknt/schema/HTTPServiceSupport.java @@ -21,10 +21,8 @@ import io.undertow.server.handlers.resource.FileResourceManager; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import java.io.File; -import java.util.Optional; import static io.undertow.Handlers.*; @@ -84,10 +82,6 @@ public static void tearDown() throws Exception { } } - @AfterEach protected void cleanup() { - // Clear CollectorContext after every test. - Optional.ofNullable(CollectorContext.getInstance()).ifPresent(CollectorContext::reset); } - } diff --git a/src/test/java/com/networknt/schema/Issue451Test.java b/src/test/java/com/networknt/schema/Issue451Test.java index 2fba7c654..186bdb7ac 100644 --- a/src/test/java/com/networknt/schema/Issue451Test.java +++ b/src/test/java/com/networknt/schema/Issue451Test.java @@ -5,9 +5,7 @@ import com.networknt.schema.walk.JsonSchemaWalkListener; import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.InputStream; @@ -25,7 +23,6 @@ public class Issue451Test { protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); SchemaValidatorsConfig svc = new SchemaValidatorsConfig(); - svc.setResetCollectorContext(false); svc.addPropertyWalkListener(new CountingWalker()); return factory.getSchema(schemaContent, svc); } @@ -35,24 +32,6 @@ protected JsonNode getJsonNodeFromStreamContent(InputStream content) throws Exce return mapper.readTree(content); } - - @BeforeAll - public static void beforeAll() { - reset(); - } - - @AfterEach - public void cleanup() { - reset(); - } - - - private static void reset() { - if (CollectorContext.getInstance() != null) { - CollectorContext.getInstance().reset(); - } - } - @Test public void shouldWalkAnyOfProperties() { walk(null, false); @@ -78,9 +57,9 @@ private void walk(JsonNode data, boolean shouldValidate) { InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); - schema.walk(data, shouldValidate); + CollectorContext collectorContext = schema.walk(data, shouldValidate).getCollectorContext(); - Map collector = (Map) CollectorContext.getInstance().get(COLLECTOR_ID); + Map collector = (Map) collectorContext.get(COLLECTOR_ID); Assertions.assertEquals(2, collector.get("#/definitions/definition1/properties/a")); Assertions.assertEquals(2, collector.get("#/definitions/definition2/properties/x")); } @@ -90,7 +69,7 @@ private static class CountingWalker implements JsonSchemaWalkListener { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { String path = walkEvent.getSchemaPath(); - collector().compute(path, (k, v) -> v == null ? 1 : v + 1); + collector(walkEvent.getExecutionContext()).compute(path, (k, v) -> v == null ? 1 : v + 1); return WalkFlow.CONTINUE; } @@ -99,11 +78,11 @@ public void onWalkEnd(WalkEvent walkEvent, Set validationMess } - private Map collector() { - Map collector = (Map) CollectorContext.getInstance().get(COLLECTOR_ID); + private Map collector(ExecutionContext executionContext) { + Map collector = (Map) executionContext.getCollectorContext().get(COLLECTOR_ID); if(collector == null) { collector = new HashMap<>(); - CollectorContext.getInstance().add(COLLECTOR_ID, collector); + executionContext.getCollectorContext().add(COLLECTOR_ID, collector); } return collector; diff --git a/src/test/java/com/networknt/schema/Issue784Test.java b/src/test/java/com/networknt/schema/Issue784Test.java index e649a4c3c..eea913c99 100644 --- a/src/test/java/com/networknt/schema/Issue784Test.java +++ b/src/test/java/com/networknt/schema/Issue784Test.java @@ -23,7 +23,7 @@ public String getName() { } @Override - public boolean matches(String value) { + public boolean matches(ExecutionContext executionContext, String value) { return value.equals(FOO_BAR); } diff --git a/src/test/java/com/networknt/schema/JsonWalkTest.java b/src/test/java/com/networknt/schema/JsonWalkTest.java index 535236f52..8989b94f1 100644 --- a/src/test/java/com/networknt/schema/JsonWalkTest.java +++ b/src/test/java/com/networknt/schema/JsonWalkTest.java @@ -7,7 +7,6 @@ import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -34,11 +33,6 @@ public void setup() { setupSchema(); } - @AfterEach - public void cleanup() { - CollectorContext.getInstance().reset(); - } - private void setupSchema() { final JsonMetaSchema metaSchema = getJsonMetaSchema(); // Create Schema. @@ -47,7 +41,6 @@ private void setupSchema() { schemaValidatorsConfig.addKeywordWalkListener(ValidatorTypeCode.REF.getValue(), new RefKeywordListener()); schemaValidatorsConfig.addKeywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(), new PropertiesKeywordListener()); - schemaValidatorsConfig.setResetCollectorContext(false); final JsonSchemaFactory schemaFactory = JsonSchemaFactory .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)).addMetaSchema(metaSchema) .build(); @@ -57,7 +50,6 @@ private void setupSchema() { schemaValidatorsConfig1.addKeywordWalkListener(ValidatorTypeCode.REF.getValue(), new RefKeywordListener()); schemaValidatorsConfig1.addKeywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(), new PropertiesKeywordListener()); - schemaValidatorsConfig1.setResetCollectorContext(false); this.jsonSchema1 = schemaFactory.getSchema(getSchema(), schemaValidatorsConfig1); } @@ -105,11 +97,8 @@ public void testWalkWithDifferentListeners() throws IOException { + " }" + "}"))); // This instance of schema contains one listener removed. - CollectorContext collectorContext = result.getCollectorContext(); - collectorContext.reset(); - result = jsonSchema1.walk( - objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false); - collectedNode = (JsonNode) result.getCollectorContext().get(SAMPLE_WALK_COLLECTOR_TYPE); + result = jsonSchema1.walk(objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false); + collectedNode = (JsonNode) result.getExecutionContext().getCollectorContext().get(SAMPLE_WALK_COLLECTOR_TYPE); assertEquals(collectedNode, (objectMapper.readTree("{" + " \"property3\": {" + " \"street_address\":\"test-address\"," @@ -152,18 +141,18 @@ public JsonValidator newValidator(String schemaPath, JsonNode schemaNode, JsonSc private static class CustomValidator implements JsonValidator { @Override - public Set validate(JsonNode node, JsonNode rootNode, String at) { + public Set validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) { return new TreeSet(); } @Override - public Set validate(JsonNode rootNode) { - return validate(rootNode, rootNode, PathType.DEFAULT.getRoot()); + public Set validate(ExecutionContext executionContext, JsonNode rootNode) { + return validate(executionContext, rootNode, rootNode, PathType.DEFAULT.getRoot()); } @Override - public Set walk(JsonNode node, JsonNode rootNode, String at, - boolean shouldValidateSchema) { + public Set walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + String at, boolean shouldValidateSchema) { return new LinkedHashSet(); } } @@ -175,7 +164,7 @@ public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) { ObjectMapper mapper = new ObjectMapper(); String keyWordName = keywordWalkEvent.getKeyWordName(); JsonNode schemaNode = keywordWalkEvent.getSchemaNode(); - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = keywordWalkEvent.getExecutionContext().getCollectorContext(); if (collectorContext.get(SAMPLE_WALK_COLLECTOR_TYPE) == null) { collectorContext.add(SAMPLE_WALK_COLLECTOR_TYPE, mapper.createObjectNode()); } @@ -198,7 +187,7 @@ private static class RefKeywordListener implements JsonSchemaWalkListener { @Override public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) { ObjectMapper mapper = new ObjectMapper(); - CollectorContext collectorContext = CollectorContext.getInstance(); + CollectorContext collectorContext = keywordWalkEvent.getExecutionContext().getCollectorContext(); if (collectorContext.get(SAMPLE_WALK_COLLECTOR_TYPE) == null) { collectorContext.add(SAMPLE_WALK_COLLECTOR_TYPE, mapper.createObjectNode()); }