diff --git a/src/main/java/com/networknt/schema/AllOfValidator.java b/src/main/java/com/networknt/schema/AllOfValidator.java index f1312bf62..79ee22c2d 100644 --- a/src/main/java/com/networknt/schema/AllOfValidator.java +++ b/src/main/java/com/networknt/schema/AllOfValidator.java @@ -55,7 +55,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String for (JsonSchema schema : schemas) { errors.addAll(schema.validate(node, rootNode, at)); - if (config.isOpenAPI3StyleDiscriminators()) { + if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators()) { final Iterator arrayElements = schemaNode.elements(); while (arrayElements.hasNext()) { final ObjectNode allOfEntry = (ObjectNode) arrayElements.next(); diff --git a/src/main/java/com/networknt/schema/AnyOfValidator.java b/src/main/java/com/networknt/schema/AnyOfValidator.java index 5b1a471bc..15edf5c55 100644 --- a/src/main/java/com/networknt/schema/AnyOfValidator.java +++ b/src/main/java/com/networknt/schema/AnyOfValidator.java @@ -37,13 +37,13 @@ public AnyOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS int size = schemaNode.size(); for (int i = 0; i < size; i++) { schemas.add(new JsonSchema(validationContext, - getValidatorType().getValue(), - parentSchema.getCurrentUri(), - schemaNode.get(i), - parentSchema)); + getValidatorType().getValue(), + parentSchema.getCurrentUri(), + schemaNode.get(i), + parentSchema)); } - if (config.isOpenAPI3StyleDiscriminators()) { + if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators()) { this.discriminatorContext = new ValidationContext.DiscriminatorContext(); } else { this.discriminatorContext = null; @@ -53,7 +53,7 @@ public AnyOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - if (config.isOpenAPI3StyleDiscriminators()) { + if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators()) { validationContext.enterDiscriminatorContext(this.discriminatorContext, at); } @@ -72,9 +72,9 @@ public Set validate(JsonNode node, JsonNode rootNode, String } } Set errors = schema.validate(node, rootNode, at); - if (errors.isEmpty() && !config.isOpenAPI3StyleDiscriminators()) { + if (errors.isEmpty() && (!this.validationContext.getConfig().isOpenAPI3StyleDiscriminators())) { return errors; - } else if (config.isOpenAPI3StyleDiscriminators()) { + } else if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators()) { if (discriminatorContext.isDiscriminatorMatchFound()) { if (!errors.isEmpty()) { errors.add(buildValidationMessage(at, DISCRIMINATOR_REMARK)); @@ -85,13 +85,13 @@ public Set validate(JsonNode node, JsonNode rootNode, String allErrors.addAll(errors); } - if (config.isOpenAPI3StyleDiscriminators() && discriminatorContext.isActive()) { - final Set errors = new HashSet(); - errors.add(buildValidationMessage(at, "based on the provided discriminator. No alternative could be chosen based on the discriminator property")); - return Collections.unmodifiableSet(errors); + if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators() && discriminatorContext.isActive()) { + final Set errors = new HashSet(); + errors.add(buildValidationMessage(at, "based on the provided discriminator. No alternative could be chosen based on the discriminator property")); + return Collections.unmodifiableSet(errors); } } finally { - if (config.isOpenAPI3StyleDiscriminators()) { + if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators()) { validationContext.leaveDiscriminatorContextImmediately(at); } } diff --git a/src/main/java/com/networknt/schema/BaseJsonValidator.java b/src/main/java/com/networknt/schema/BaseJsonValidator.java index 9ad401b7a..b410c1b81 100644 --- a/src/main/java/com/networknt/schema/BaseJsonValidator.java +++ b/src/main/java/com/networknt/schema/BaseJsonValidator.java @@ -36,17 +36,13 @@ public abstract class BaseJsonValidator implements JsonValidator { private boolean suppressSubSchemaRetrieval; private ValidatorTypeCode validatorType; private ErrorMessageType errorMessageType; - /** - * SchemaValidatorsConfig can only get and set in validationContext - */ - protected SchemaValidatorsConfig config; + protected final boolean failFast; public BaseJsonValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidatorTypeCode validatorType, ValidationContext validationContext) { this(schemaPath, schemaNode, parentSchema, validatorType, false, validationContext.getConfig() != null && validationContext.getConfig().isFailFast()); - this.config = validationContext.getConfig() == null ? new SchemaValidatorsConfig() : validationContext.getConfig(); } public BaseJsonValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, diff --git a/src/main/java/com/networknt/schema/DateTimeValidator.java b/src/main/java/com/networknt/schema/DateTimeValidator.java index ed4d01fe5..420aaacda 100644 --- a/src/main/java/com/networknt/schema/DateTimeValidator.java +++ b/src/main/java/com/networknt/schema/DateTimeValidator.java @@ -32,6 +32,8 @@ public class DateTimeValidator extends BaseJsonValidator implements JsonValidator { private static final Logger logger = LoggerFactory.getLogger(DateTimeValidator.class); + private final ValidationContext validationContext; + private final String formatName; private final String DATE = "date"; private final String DATETIME = "date-time"; @@ -44,6 +46,7 @@ public class DateTimeValidator extends BaseJsonValidator implements JsonValidato public DateTimeValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, String formatName) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.DATETIME, validationContext); this.formatName = formatName; + this.validationContext = validationContext; parseErrorCode(getValidatorType().getErrorCodeKey()); } @@ -52,7 +55,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String Set errors = new LinkedHashSet(); - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); if (nodeType != JsonType.STRING) { return errors; } diff --git a/src/main/java/com/networknt/schema/EnumValidator.java b/src/main/java/com/networknt/schema/EnumValidator.java index abd95f980..dc24de97c 100644 --- a/src/main/java/com/networknt/schema/EnumValidator.java +++ b/src/main/java/com/networknt/schema/EnumValidator.java @@ -32,10 +32,11 @@ public class EnumValidator extends BaseJsonValidator implements JsonValidator { private final Set nodes; private final String error; + private final ValidationContext validationContext; public EnumValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.ENUM, validationContext); - + this.validationContext = validationContext; if (schemaNode != null && schemaNode.isArray()) { nodes = new HashSet(); StringBuilder sb = new StringBuilder(); @@ -57,7 +58,7 @@ public EnumValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSc } // check if the parent schema declares the fields as nullable - if (config.isHandleNullableField()) { + if (validationContext.getConfig().isHandleNullableField()) { JsonNode nullable = parentSchema.getSchemaNode().get("nullable"); if (nullable != null && nullable.asBoolean()) { nodes.add(NullNode.getInstance()); @@ -83,7 +84,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String Set errors = new LinkedHashSet(); if (node.isNumber()) node = DecimalNode.valueOf(node.decimalValue()); - if (!nodes.contains(node) && !(config.isTypeLoose() && isTypeLooseContainsInEnum(node))) { + if (!nodes.contains(node) && !( this.validationContext.getConfig().isTypeLoose() && isTypeLooseContainsInEnum(node))) { errors.add(buildValidationMessage(at, error)); } @@ -96,7 +97,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String * @param node JsonNode to check */ private boolean isTypeLooseContainsInEnum(JsonNode node) { - if (TypeFactory.getValueNodeType(node, super.config) == JsonType.STRING) { + if (TypeFactory.getValueNodeType(node, this.validationContext.getConfig()) == JsonType.STRING) { String nodeText = node.textValue(); for (JsonNode n : nodes) { String value = n.asText(); diff --git a/src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java b/src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java index cf2942da1..b9f7d4491 100644 --- a/src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java +++ b/src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java @@ -30,9 +30,11 @@ public class ExclusiveMaximumValidator extends BaseJsonValidator implements Json private final ThresholdMixin typedMaximum; + private final ValidationContext validationContext; + public ExclusiveMaximumValidator(String schemaPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.EXCLUSIVE_MAXIMUM, validationContext); - + this.validationContext = validationContext; if (!schemaNode.isNumber()) { throw new JsonSchemaException("exclusiveMaximum value is not a number"); } @@ -99,7 +101,7 @@ public String thresholdValue() { public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - if (!TypeValidator.isNumber(node, super.config)) { + if (!TypeValidator.isNumber(node, validationContext.getConfig())) { // maximum only applies to numbers return Collections.emptySet(); } diff --git a/src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java b/src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java index afccbfe14..1444a2d4c 100644 --- a/src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java +++ b/src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java @@ -34,9 +34,11 @@ public class ExclusiveMinimumValidator extends BaseJsonValidator implements Json */ private final ThresholdMixin typedMinimum; + private final ValidationContext validationContext; + public ExclusiveMinimumValidator(String schemaPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.EXCLUSIVE_MINIMUM, validationContext); - + this.validationContext = validationContext; if (!schemaNode.isNumber()) { throw new JsonSchemaException("exclusiveMinimum value is not a number"); } @@ -106,7 +108,7 @@ public String thresholdValue() { public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - if (!TypeValidator.isNumber(node, super.config)) { + if (!TypeValidator.isNumber(node, this.validationContext.getConfig())) { // minimum only applies to numbers return Collections.emptySet(); } diff --git a/src/main/java/com/networknt/schema/FormatValidator.java b/src/main/java/com/networknt/schema/FormatValidator.java index 6db5f0192..7e7962d71 100644 --- a/src/main/java/com/networknt/schema/FormatValidator.java +++ b/src/main/java/com/networknt/schema/FormatValidator.java @@ -29,10 +29,12 @@ public class FormatValidator extends BaseJsonValidator implements JsonValidator private static final Logger logger = LoggerFactory.getLogger(FormatValidator.class); private final Format format; + private final ValidationContext validationContext; public FormatValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, Format format) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.FORMAT, validationContext); this.format = format; + this.validationContext = validationContext; parseErrorCode(getValidatorType().getErrorCodeKey()); } @@ -41,7 +43,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String Set errors = new LinkedHashSet(); - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); if (nodeType != JsonType.STRING) { return errors; } diff --git a/src/main/java/com/networknt/schema/ItemsValidator.java b/src/main/java/com/networknt/schema/ItemsValidator.java index 6f8ed5af0..3a81f5607 100644 --- a/src/main/java/com/networknt/schema/ItemsValidator.java +++ b/src/main/java/com/networknt/schema/ItemsValidator.java @@ -33,7 +33,7 @@ public class ItemsValidator extends BaseJsonValidator implements JsonValidator { private final List tupleSchema; private boolean additionalItems = true; private final JsonSchema additionalSchema; - private final WalkListenerRunner arrayItemWalkListenerRunner; + private WalkListenerRunner arrayItemWalkListenerRunner; private final ValidationContext validationContext; public ItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, @@ -61,7 +61,7 @@ public ItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS } } } - arrayItemWalkListenerRunner = new DefaultItemWalkListenerRunner(config.getArrayItemWalkListeners()); + arrayItemWalkListenerRunner = new DefaultItemWalkListenerRunner(validationContext.getConfig().getArrayItemWalkListeners()); this.validationContext = validationContext; @@ -76,7 +76,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String Set errors = new LinkedHashSet(); - if (!node.isArray() && !config.isTypeLoose()) { + if (!node.isArray() && !this.validationContext.getConfig().isTypeLoose()) { // ignores non-arrays return errors; } diff --git a/src/main/java/com/networknt/schema/JsonSchema.java b/src/main/java/com/networknt/schema/JsonSchema.java index 18936b954..6799e4d40 100644 --- a/src/main/java/com/networknt/schema/JsonSchema.java +++ b/src/main/java/com/networknt/schema/JsonSchema.java @@ -19,6 +19,7 @@ import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; +import java.sql.Ref; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -36,6 +37,8 @@ import com.networknt.schema.walk.JsonSchemaWalker; import com.networknt.schema.walk.WalkListenerRunner; +import javax.xml.validation.Schema; + /** * This is the core of json constraint implementation. It parses json constraint * file and generates JsonValidators. The class is thread safe, once it is @@ -46,7 +49,6 @@ public class JsonSchema extends BaseJsonValidator { private Map validators; private final String idKeyword; private final ValidationContext validationContext; - private WalkListenerRunner keywordWalkListenerRunner; private boolean validatorsLoaded = false; /** @@ -80,13 +82,10 @@ private JsonSchema(ValidationContext validationContext, String schemaPath, URI c super(schemaPath, schemaNode, parent, null, suppressSubSchemaRetrieval, validationContext.getConfig() != null && validationContext.getConfig().isFailFast()); this.validationContext = validationContext; - this.config = validationContext.getConfig(); this.idKeyword = validationContext.getMetaSchema().getIdKeyword(); this.currentUri = this.combineCurrentUriWithIds(currentUri, schemaNode); - if (config != null) { - this.keywordWalkListenerRunner = new DefaultKeywordWalkListenerRunner(config.getKeywordWalkListenersMap()); - - if (config.isOpenAPI3StyleDiscriminators()) { + if (validationContext.getConfig() != null) { + if (validationContext.getConfig().isOpenAPI3StyleDiscriminators()) { ObjectNode discriminator = (ObjectNode) schemaNode.get("discriminator"); if (null != discriminator && null != validationContext.getCurrentDiscriminatorContext()) { validationContext.getCurrentDiscriminatorContext().registerDiscriminator(schemaPath, discriminator); @@ -95,6 +94,10 @@ private JsonSchema(ValidationContext validationContext, String schemaPath, URI c } } + ValidationContext getValidationContext() { + return this.validationContext; + } + private URI combineCurrentUriWithIds(URI currentUri, JsonNode schemaNode) { final String id = validationContext.resolveSchemaId(schemaNode); if (id == null) { @@ -257,6 +260,7 @@ private JsonNode getMessageNode(JsonNode schemaNode, JsonSchema parentSchema) { /************************ START OF VALIDATE METHODS **********************************/ public Set validate(JsonNode jsonNode, JsonNode rootNode, String at) { + SchemaValidatorsConfig config = validationContext.getConfig(); Set errors = new LinkedHashSet(); // Get the collector context. getCollectorContext(); @@ -353,6 +357,7 @@ public ValidationResult walk(JsonNode node, boolean shouldValidateSchema) { @Override public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { Set validationMessages = new LinkedHashSet(); + WalkListenerRunner keywordWalkListenerRunner = new DefaultKeywordWalkListenerRunner(this.validationContext.getConfig().getKeywordWalkListenersMap()); // Walk through all the JSONWalker's. for (Entry entry : getValidators().entrySet()) { JsonSchemaWalker jsonWalker = entry.getValue(); @@ -401,11 +406,12 @@ private void setValidatorState(boolean isWalkEnabled, boolean shouldValidateSche } public CollectorContext getCollectorContext() { + SchemaValidatorsConfig config = validationContext.getConfig(); CollectorContext collectorContext = (CollectorContext) ThreadInfo .get(CollectorContext.COLLECTOR_CONTEXT_THREAD_LOCAL_KEY); if (collectorContext == null) { - if (this.config != null && this.config.getCollectorContext() != null) { - collectorContext = this.config.getCollectorContext(); + if (config != null && config.getCollectorContext() != null) { + collectorContext = config.getCollectorContext(); } else { collectorContext = new CollectorContext(); } diff --git a/src/main/java/com/networknt/schema/JsonSchemaFactory.java b/src/main/java/com/networknt/schema/JsonSchemaFactory.java index 8fe4c5118..b8f4baf7e 100644 --- a/src/main/java/com/networknt/schema/JsonSchemaFactory.java +++ b/src/main/java/com/networknt/schema/JsonSchemaFactory.java @@ -338,8 +338,14 @@ public JsonSchema getSchema(final URI schemaUri, final SchemaValidatorsConfig co throw new JsonSchemaException(e); } - if (uriSchemaCache.containsKey(mappedUri)) - return uriSchemaCache.get(mappedUri); + if (uriSchemaCache.containsKey(mappedUri)) { + JsonSchema cachedUriSchema = uriSchemaCache.get(mappedUri); + // This is important because if we use same JsonSchemaFactory for creating multiple JSONSchema instances, + // these schemas will be cached along with config. We have to replace the config for cached $ref references + // with the latest config. + cachedUriSchema.getValidationContext().setConfig(config); + return cachedUriSchema; + } try { inputStream = this.uriFetcher.fetch(mappedUri); diff --git a/src/main/java/com/networknt/schema/MaxItemsValidator.java b/src/main/java/com/networknt/schema/MaxItemsValidator.java index dd1779009..97a68123e 100644 --- a/src/main/java/com/networknt/schema/MaxItemsValidator.java +++ b/src/main/java/com/networknt/schema/MaxItemsValidator.java @@ -24,8 +24,11 @@ import java.util.Set; public class MaxItemsValidator extends BaseJsonValidator implements JsonValidator { + private static final Logger logger = LoggerFactory.getLogger(MaxItemsValidator.class); + private final ValidationContext validationContext; + private int max = 0; public MaxItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { @@ -33,7 +36,7 @@ public MaxItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema pare if (schemaNode.isIntegralNumber()) { max = schemaNode.intValue(); } - + this.validationContext = validationContext; parseErrorCode(getValidatorType().getErrorCodeKey()); } @@ -44,7 +47,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String if (node.size() > max) { return Collections.singleton(buildValidationMessage(at, "" + max)); } - } else if (config.isTypeLoose()) { + } else if (this.validationContext.getConfig().isTypeLoose()) { if (1 > max) { return Collections.singleton(buildValidationMessage(at, "" + max)); } diff --git a/src/main/java/com/networknt/schema/MaxLengthValidator.java b/src/main/java/com/networknt/schema/MaxLengthValidator.java index e5c097f71..0fbe76176 100644 --- a/src/main/java/com/networknt/schema/MaxLengthValidator.java +++ b/src/main/java/com/networknt/schema/MaxLengthValidator.java @@ -26,6 +26,8 @@ public class MaxLengthValidator extends BaseJsonValidator implements JsonValidator { private static final Logger logger = LoggerFactory.getLogger(MaxLengthValidator.class); + private final ValidationContext validationContext; + private int maxLength; public MaxLengthValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { @@ -34,14 +36,14 @@ public MaxLengthValidator(String schemaPath, JsonNode schemaNode, JsonSchema par if (schemaNode != null && schemaNode.isIntegralNumber()) { maxLength = schemaNode.intValue(); } - + this.validationContext = validationContext; parseErrorCode(getValidatorType().getErrorCodeKey()); } public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); if (nodeType != JsonType.STRING) { // ignore no-string typs return Collections.emptySet(); diff --git a/src/main/java/com/networknt/schema/MaximumValidator.java b/src/main/java/com/networknt/schema/MaximumValidator.java index b189bc7b0..9bd3a3438 100644 --- a/src/main/java/com/networknt/schema/MaximumValidator.java +++ b/src/main/java/com/networknt/schema/MaximumValidator.java @@ -32,11 +32,12 @@ public class MaximumValidator extends BaseJsonValidator implements JsonValidator private boolean excludeEqual = false; private final ThresholdMixin typedMaximum; + private final ValidationContext validationContext; public MaximumValidator(String schemaPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.MAXIMUM, validationContext); - + this.validationContext = validationContext; if (!schemaNode.isNumber()) { throw new JsonSchemaException("maximum value is not a number"); } @@ -108,7 +109,7 @@ public String thresholdValue() { public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - if (!TypeValidator.isNumber(node, super.config)) { + if (!TypeValidator.isNumber(node, this.validationContext.getConfig())) { // maximum only applies to numbers return Collections.emptySet(); } diff --git a/src/main/java/com/networknt/schema/MinItemsValidator.java b/src/main/java/com/networknt/schema/MinItemsValidator.java index b58c5c072..dd840469d 100644 --- a/src/main/java/com/networknt/schema/MinItemsValidator.java +++ b/src/main/java/com/networknt/schema/MinItemsValidator.java @@ -26,6 +26,8 @@ public class MinItemsValidator extends BaseJsonValidator implements JsonValidator { private static final Logger logger = LoggerFactory.getLogger(MinItemsValidator.class); + private final ValidationContext validationContext; + private int min = 0; public MinItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { @@ -33,7 +35,7 @@ public MinItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema pare if (schemaNode.isIntegralNumber()) { min = schemaNode.intValue(); } - + this.validationContext = validationContext; parseErrorCode(getValidatorType().getErrorCodeKey()); } @@ -44,7 +46,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String if (node.size() < min) { return Collections.singleton(buildValidationMessage(at, "" + min)); } - } else if (config.isTypeLoose()) { + } else if (this.validationContext.getConfig().isTypeLoose()) { if (1 < min) { return Collections.singleton(buildValidationMessage(at, "" + min)); } diff --git a/src/main/java/com/networknt/schema/MinLengthValidator.java b/src/main/java/com/networknt/schema/MinLengthValidator.java index cec85eb43..af88dd463 100644 --- a/src/main/java/com/networknt/schema/MinLengthValidator.java +++ b/src/main/java/com/networknt/schema/MinLengthValidator.java @@ -26,6 +26,8 @@ public class MinLengthValidator extends BaseJsonValidator implements JsonValidator { private static final Logger logger = LoggerFactory.getLogger(MinLengthValidator.class); + private final ValidationContext validationContext; + private int minLength; public MinLengthValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { @@ -34,14 +36,14 @@ public MinLengthValidator(String schemaPath, JsonNode schemaNode, JsonSchema par if (schemaNode != null && schemaNode.isIntegralNumber()) { minLength = schemaNode.intValue(); } - + this.validationContext = validationContext; parseErrorCode(getValidatorType().getErrorCodeKey()); } public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); if (nodeType != JsonType.STRING) { // ignore non-string types return Collections.emptySet(); diff --git a/src/main/java/com/networknt/schema/MinimumValidator.java b/src/main/java/com/networknt/schema/MinimumValidator.java index f9af8f8be..2208120ea 100644 --- a/src/main/java/com/networknt/schema/MinimumValidator.java +++ b/src/main/java/com/networknt/schema/MinimumValidator.java @@ -37,6 +37,8 @@ public class MinimumValidator extends BaseJsonValidator implements JsonValidator */ private final ThresholdMixin typedMinimum; + private final ValidationContext validationContext; + public MinimumValidator(String schemaPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.MINIMUM, validationContext); @@ -109,12 +111,13 @@ public String thresholdValue() { } }; } + this.validationContext = validationContext; } public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - if (!TypeValidator.isNumber(node, super.config)) { + if (!TypeValidator.isNumber(node, this.validationContext.getConfig())) { // minimum only applies to numbers return Collections.emptySet(); } diff --git a/src/main/java/com/networknt/schema/OneOfValidator.java b/src/main/java/com/networknt/schema/OneOfValidator.java index b44f5dd80..283875e56 100644 --- a/src/main/java/com/networknt/schema/OneOfValidator.java +++ b/src/main/java/com/networknt/schema/OneOfValidator.java @@ -27,13 +27,17 @@ import java.util.*; public class OneOfValidator extends BaseJsonValidator implements JsonValidator { + private static final Logger logger = LoggerFactory.getLogger(OneOfValidator.class); private final List schemas = new ArrayList(); + private final ValidationContext validationContext; + private static class ShortcutValidator { private final JsonSchema schema; private final Map constants; + private final ValidationContext validationContext; ShortcutValidator(JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, JsonSchema schema) { @@ -41,6 +45,7 @@ private static class ShortcutValidator { JsonSchema resolvedRefSchema = refNode != null && refNode.isTextual() ? RefValidator.getRefSchema(parentSchema, validationContext, refNode.textValue()).getSchema() : null; this.constants = extractConstants(schemaNode, resolvedRefSchema); this.schema = schema; + this.validationContext = validationContext; } private Map extractConstants(JsonNode schemaNode, JsonSchema resolvedRefSchema) { @@ -125,7 +130,7 @@ public OneOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS JsonSchema childSchema = new JsonSchema(validationContext, getValidatorType().getValue(), parentSchema.getCurrentUri(), childNode, parentSchema); schemas.add(new ShortcutValidator(childNode, parentSchema, validationContext, childSchema)); } - + this.validationContext = validationContext; parseErrorCode(getValidatorType().getErrorCodeKey()); } @@ -159,7 +164,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String }*/ //Check to see if it is already validated. - if(!childErrors.isEmpty() && JsonNodeUtil.matchOneOfTypeNode(schemaNode,TypeFactory.getValueNodeType(node, super.config))){ + if(!childErrors.isEmpty() && JsonNodeUtil.matchOneOfTypeNode(schemaNode,TypeFactory.getValueNodeType(node, this.validationContext.getConfig()))){ continue; } @@ -167,7 +172,8 @@ public Set validate(JsonNode node, JsonNode rootNode, String JsonSchema schema = validator.schema; //Skip the validation when the current node is oneOf type and it is not equal to schemaType. - if(JsonNodeUtil.matchOneOfTypeNode(schemaNode,TypeFactory.getValueNodeType(node, super.config)) && !JsonNodeUtil.equalsToSchemaType(node,schema,config) && !(JsonType.UNKNOWN.equals(JsonNodeUtil.getSchemaJsonType(schema)))){ + if (JsonNodeUtil.matchOneOfTypeNode(schemaNode, TypeFactory.getValueNodeType(node, this.validationContext.getConfig())) && + !JsonNodeUtil.equalsToSchemaType(node, schema, this.validationContext.getConfig()) && !(JsonType.UNKNOWN.equals(JsonNodeUtil.getSchemaJsonType(schema)))) { continue; } @@ -189,9 +195,11 @@ public Set validate(JsonNode node, JsonNode rootNode, String childErrors.addAll(schemaErrors); } // ensure there is always an "OneOf" error reported if number of valid schemas is not equal to 1. - if(numberOfValidSchema > 1){ + if (numberOfValidSchema > 1) { // check if the parent schema declares the fields as nullable - if (!JsonType.NULL.equals(TypeFactory.getValueNodeType(node,config)) || !JsonNodeUtil.isNodeNullable(parentSchema.getSchemaNode(),config) && !JsonNodeUtil.isChildNodeNullable((ArrayNode) schemaNode,config)) { + if (!JsonType.NULL.equals(TypeFactory.getValueNodeType(node, this.validationContext.getConfig())) || + !JsonNodeUtil.isNodeNullable(parentSchema.getSchemaNode(), this.validationContext.getConfig()) && + !JsonNodeUtil.isChildNodeNullable((ArrayNode) schemaNode, this.validationContext.getConfig())) { final ValidationMessage message = getMultiSchemasValidErrorMsg(at); if (failFast) { throw new JsonSchemaException(message); diff --git a/src/main/java/com/networknt/schema/PatternValidator.java b/src/main/java/com/networknt/schema/PatternValidator.java index 36a74077a..548b2a82f 100644 --- a/src/main/java/com/networknt/schema/PatternValidator.java +++ b/src/main/java/com/networknt/schema/PatternValidator.java @@ -35,7 +35,10 @@ public class PatternValidator implements JsonValidator { private final JsonValidator delegate; + private final ValidationContext validationContext; + public PatternValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { + this.validationContext = validationContext; if (validationContext.getConfig() != null && validationContext.getConfig().isEcma262Validator()) { delegate = new PatternValidatorEcma262(schemaPath, schemaNode, parentSchema, validationContext); } else { @@ -60,7 +63,7 @@ public Set walk(JsonNode node, JsonNode rootNode, String at, private static class PatternValidatorJava extends BaseJsonValidator implements JsonValidator { private static final Logger logger = LoggerFactory.getLogger(PatternValidator.class); - + private final ValidationContext validationContext; private String pattern; private Pattern compiledPattern; @@ -77,7 +80,7 @@ public PatternValidatorJava(String schemaPath, JsonNode schemaNode, JsonSchema p throw pse; } } - + this.validationContext = validationContext; parseErrorCode(getValidatorType().getErrorCodeKey()); } @@ -88,7 +91,7 @@ private boolean matches(String value) { public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); if (nodeType != JsonType.STRING) { return Collections.emptySet(); } @@ -107,7 +110,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String private static class PatternValidatorEcma262 extends BaseJsonValidator implements JsonValidator { private static final Logger logger = LoggerFactory.getLogger(PatternValidator.class); - + private final ValidationContext validationContext; private String pattern; private Regex compiledRegex; @@ -124,7 +127,7 @@ public PatternValidatorEcma262(String schemaPath, JsonNode schemaNode, JsonSchem throw se; } } - + this.validationContext = validationContext; parseErrorCode(getValidatorType().getErrorCodeKey()); } @@ -145,7 +148,7 @@ private boolean matches(String value) { public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + JsonType nodeType = TypeFactory.getValueNodeType(node, validationContext.getConfig()); if (nodeType != JsonType.STRING) { return Collections.emptySet(); } diff --git a/src/main/java/com/networknt/schema/PropertiesValidator.java b/src/main/java/com/networknt/schema/PropertiesValidator.java index 16b6adc77..17c201664 100644 --- a/src/main/java/com/networknt/schema/PropertiesValidator.java +++ b/src/main/java/com/networknt/schema/PropertiesValidator.java @@ -28,7 +28,6 @@ public class PropertiesValidator extends BaseJsonValidator implements JsonValida public static final String PROPERTY = "properties"; private static final Logger logger = LoggerFactory.getLogger(PropertiesValidator.class); private final Map schemas = new HashMap(); - private final WalkListenerRunner propertyWalkListenerRunner; private final ValidationContext validationContext; public PropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { @@ -38,12 +37,13 @@ public PropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSchema pa String pname = it.next(); schemas.put(pname, new JsonSchema(validationContext, schemaPath + "/" + pname, parentSchema.getCurrentUri(), schemaNode.get(pname), parentSchema)); } - propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(config.getPropertyWalkListeners()); } public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); + WalkListenerRunner propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(this.validationContext.getConfig().getPropertyWalkListeners()); + Set errors = new LinkedHashSet(); // get the Validator state object storing validation data @@ -68,7 +68,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String errors.addAll(propertySchema.validate(propertyNode, rootNode, 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); + walkSchema(entry, node, rootNode, at, state.isValidationEnabled(), errors, propertyWalkListenerRunner); } // reset the complex flag to the original value before the recursive call @@ -105,15 +105,16 @@ public Set walk(JsonNode node, JsonNode rootNode, String at, if (shouldValidateSchema) { validationMessages.addAll(validate(node, rootNode, at)); } else { + WalkListenerRunner propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(this.validationContext.getConfig().getPropertyWalkListeners()); for (Map.Entry entry : schemas.entrySet()) { - walkSchema(entry, node, rootNode, at, shouldValidateSchema, validationMessages); + walkSchema(entry, node, rootNode, at, shouldValidateSchema, validationMessages, propertyWalkListenerRunner); } } return validationMessages; } private void walkSchema(Map.Entry entry, JsonNode node, JsonNode rootNode, String at, - boolean shouldValidateSchema, Set validationMessages) { + 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(), diff --git a/src/main/java/com/networknt/schema/RefValidator.java b/src/main/java/com/networknt/schema/RefValidator.java index b08b9864e..74d2f73fa 100644 --- a/src/main/java/com/networknt/schema/RefValidator.java +++ b/src/main/java/com/networknt/schema/RefValidator.java @@ -34,11 +34,14 @@ public class RefValidator extends BaseJsonValidator implements JsonValidator { protected JsonSchemaRef schema; + private JsonSchema parentSchema; + private static final String REF_CURRENT = "#"; public RefValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.REF, validationContext); String refValue = schemaNode.asText(); + this.parentSchema = parentSchema; schema = getRefSchema(parentSchema, validationContext, refValue); if (schema == null) { throw new JsonSchemaException( @@ -128,7 +131,10 @@ private static URI determineSchemaUrn(final URNFactory urnFactory, final String public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - + // This is important because if we use same JsonSchemaFactory for creating multiple JSONSchema instances, + // 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.getSchema().getValidationContext().setConfig(parentSchema.getValidationContext().getConfig()); if (schema != null) { return schema.validate(node, rootNode, at); } else { @@ -138,6 +144,10 @@ public Set validate(JsonNode node, JsonNode rootNode, String @Override public Set walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) { + // This is important because if we use same JsonSchemaFactory for creating multiple JSONSchema instances, + // 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.getSchema().getValidationContext().setConfig(parentSchema.getValidationContext().getConfig()); if (schema != null) { return schema.walk(node, rootNode, at, shouldValidateSchema); } diff --git a/src/main/java/com/networknt/schema/TypeFactory.java b/src/main/java/com/networknt/schema/TypeFactory.java index 3e0693d23..71bb8ea5f 100644 --- a/src/main/java/com/networknt/schema/TypeFactory.java +++ b/src/main/java/com/networknt/schema/TypeFactory.java @@ -72,9 +72,9 @@ public static JsonType getValueNodeType(JsonNode node, SchemaValidatorsConfig co if (node.isIntegralNumber()) return JsonType.INTEGER; if (node.isNumber()) - if (config.isJavaSemantics() && node.canConvertToLong() && (node.asText().indexOf('.') == -1)) + if (config != null && config.isJavaSemantics() && node.canConvertToLong() && (node.asText().indexOf('.') == -1)) return JsonType.INTEGER; - else if (config.isLosslessNarrowing() && node.asText().endsWith(".0")) + else if (config!= null && config.isLosslessNarrowing() && node.asText().endsWith(".0")) return JsonType.INTEGER; else return JsonType.NUMBER; diff --git a/src/main/java/com/networknt/schema/TypeValidator.java b/src/main/java/com/networknt/schema/TypeValidator.java index 8ca71732a..50950830e 100644 --- a/src/main/java/com/networknt/schema/TypeValidator.java +++ b/src/main/java/com/networknt/schema/TypeValidator.java @@ -37,12 +37,13 @@ public class TypeValidator extends BaseJsonValidator implements JsonValidator { private JsonType schemaType; private JsonSchema parentSchema; private UnionTypeValidator unionTypeValidator; + private final ValidationContext validationContext; public TypeValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.TYPE, validationContext); schemaType = TypeFactory.getSchemaNodeType(schemaNode); this.parentSchema = parentSchema; - + this.validationContext = validationContext; if (schemaType == JsonType.UNION) { unionTypeValidator = new UnionTypeValidator(schemaPath, schemaNode, parentSchema, validationContext); } @@ -55,7 +56,7 @@ public JsonType getSchemaType() { } public boolean equalsToSchemaType(JsonNode node) { - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + JsonType nodeType = TypeFactory.getValueNodeType(node, validationContext.getConfig()); // in the case that node type is not the same as schema type, try to convert node to the // same type of schema. In REST API, query parameters, path parameters and headers are all // string type and we must convert, otherwise, all schema validations will fail. @@ -70,7 +71,8 @@ public boolean equalsToSchemaType(JsonNode node) { ValidatorState state = (ValidatorState) CollectorContext.getInstance().get(ValidatorState.VALIDATOR_STATE_KEY); if(JsonType.NULL.equals(nodeType) ){ - if((state.isComplexValidator() && JsonNodeUtil.isNodeNullable(parentSchema.getParentSchema().getSchemaNode(), config)) || JsonNodeUtil.isNodeNullable(this.getParentSchema().getSchemaNode()) ){ + if ((state.isComplexValidator() && JsonNodeUtil.isNodeNullable(parentSchema.getParentSchema().getSchemaNode(), validationContext.getConfig())) || + JsonNodeUtil.isNodeNullable(this.getParentSchema().getSchemaNode())) { return true; } } @@ -80,7 +82,7 @@ public boolean equalsToSchemaType(JsonNode node) { if (isEnumObjectSchema(parentSchema)) { return true; } - if (config.isTypeLoose()) { + if (validationContext.getConfig().isTypeLoose()) { // if typeLoose is true, everything can be a size 1 array if (schemaType == JsonType.ARRAY) { return true; @@ -115,8 +117,8 @@ public Set validate(JsonNode node, JsonNode rootNode, String } //if (!equalsToSchemaType(node)) { - if(!JsonNodeUtil.equalsToSchemaType(node,schemaType, parentSchema, super.config)){ - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + if(!JsonNodeUtil.equalsToSchemaType(node,schemaType, parentSchema, validationContext.getConfig())){ + JsonType nodeType = TypeFactory.getValueNodeType(node, validationContext.getConfig()); return Collections.singleton(buildValidationMessage(at, nodeType.toString(), schemaType.toString())); } return Collections.emptySet(); diff --git a/src/main/java/com/networknt/schema/UUIDValidator.java b/src/main/java/com/networknt/schema/UUIDValidator.java index 2677befa7..1bb980c47 100644 --- a/src/main/java/com/networknt/schema/UUIDValidator.java +++ b/src/main/java/com/networknt/schema/UUIDValidator.java @@ -31,11 +31,13 @@ public class UUIDValidator extends BaseJsonValidator implements JsonValidator { private static final String regex = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"; + private final ValidationContext validationContext; public UUIDValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, String formatName) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.UUID, validationContext); this.formatName = formatName; parseErrorCode(getValidatorType().getErrorCodeKey()); + this.validationContext = validationContext; } public Set validate(JsonNode node, JsonNode rootNode, String at) { @@ -43,7 +45,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String Set errors = new LinkedHashSet(); - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); if (nodeType != JsonType.STRING) { return errors; } diff --git a/src/main/java/com/networknt/schema/UnionTypeValidator.java b/src/main/java/com/networknt/schema/UnionTypeValidator.java index 547eafe26..cb7326de5 100644 --- a/src/main/java/com/networknt/schema/UnionTypeValidator.java +++ b/src/main/java/com/networknt/schema/UnionTypeValidator.java @@ -31,9 +31,11 @@ public class UnionTypeValidator extends BaseJsonValidator implements JsonValidat private final List schemas = new ArrayList(); private final String error; + private final ValidationContext validationContext; + public UnionTypeValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.UNION_TYPE, validationContext); - + this.validationContext = validationContext; StringBuilder errorBuilder = new StringBuilder(); String sep = ""; @@ -64,7 +66,7 @@ public UnionTypeValidator(String schemaPath, JsonNode schemaNode, JsonSchema par public Set validate(JsonNode node, JsonNode rootNode, String at) { debug(logger, node, rootNode, at); - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + JsonType nodeType = TypeFactory.getValueNodeType(node, validationContext.getConfig()); boolean valid = false; diff --git a/src/main/java/com/networknt/schema/ValidationContext.java b/src/main/java/com/networknt/schema/ValidationContext.java index a7d247497..150cd51e3 100644 --- a/src/main/java/com/networknt/schema/ValidationContext.java +++ b/src/main/java/com/networknt/schema/ValidationContext.java @@ -74,6 +74,9 @@ public JsonSchemaFactory getJsonSchemaFactory() { } public SchemaValidatorsConfig getConfig() { + if (config == null) { + config = new SchemaValidatorsConfig(); + } return config; } diff --git a/src/main/java/com/networknt/schema/format/EmailValidator.java b/src/main/java/com/networknt/schema/format/EmailValidator.java index 57e920765..e69f18301 100644 --- a/src/main/java/com/networknt/schema/format/EmailValidator.java +++ b/src/main/java/com/networknt/schema/format/EmailValidator.java @@ -62,6 +62,8 @@ public class EmailValidator extends BaseJsonValidator implements JsonValidator { private final boolean allowTld = false; private final String formatName; + private final ValidationContext validationContext; + /** *

Checks if a field has a valid e-mail address.

* @@ -138,6 +140,7 @@ protected boolean isValidUser(String user) { public EmailValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, String formatName) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.FORMAT, validationContext); this.formatName = formatName; + this.validationContext = validationContext; parseErrorCode(getValidatorType().getErrorCodeKey()); } @@ -147,7 +150,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String Set errors = new LinkedHashSet(); - JsonType nodeType = TypeFactory.getValueNodeType(node, super.config); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); if (nodeType != JsonType.STRING) { return errors; } diff --git a/src/main/java/com/networknt/schema/utils/JsonNodeUtil.java b/src/main/java/com/networknt/schema/utils/JsonNodeUtil.java index 141c6f23d..d9ddd804f 100644 --- a/src/main/java/com/networknt/schema/utils/JsonNodeUtil.java +++ b/src/main/java/com/networknt/schema/utils/JsonNodeUtil.java @@ -95,7 +95,7 @@ public static boolean equalsToSchemaType(JsonNode node, JsonType schemaType, Jso if (isEnumObjectSchema(parentSchema)) { return true; } - if (config.isTypeLoose()) { + if (config != null && config.isTypeLoose()) { // if typeLoose is true, everything can be a size 1 array if (schemaType == JsonType.ARRAY) { return true; diff --git a/src/test/java/com/networknt/schema/JsonWalkTest.java b/src/test/java/com/networknt/schema/JsonWalkTest.java index 8137beeb8..a8dc89c5b 100644 --- a/src/test/java/com/networknt/schema/JsonWalkTest.java +++ b/src/test/java/com/networknt/schema/JsonWalkTest.java @@ -23,6 +23,8 @@ public class JsonWalkTest { private JsonSchema jsonSchema; + private JsonSchema jsonSchema1; + private static final String SAMPLE_WALK_COLLECTOR_TYPE = "sampleWalkCollectorType"; private static final String CUSTOM_KEYWORD = "custom-keyword"; @@ -39,6 +41,7 @@ public void cleanup() { private void setupSchema() { final JsonMetaSchema metaSchema = getJsonMetaSchema(); + // Create Schema. SchemaValidatorsConfig schemaValidatorsConfig = new SchemaValidatorsConfig(); schemaValidatorsConfig.addKeywordWalkListener(new AllKeywordListener()); schemaValidatorsConfig.addKeywordWalkListener(ValidatorTypeCode.REF.getValue(), new RefKeywordListener()); @@ -48,6 +51,12 @@ private void setupSchema() { .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)).addMetaSchema(metaSchema) .build(); this.jsonSchema = schemaFactory.getSchema(getSchema(), schemaValidatorsConfig); + // Create another Schema. + SchemaValidatorsConfig schemaValidatorsConfig1 = new SchemaValidatorsConfig(); + schemaValidatorsConfig1.addKeywordWalkListener(ValidatorTypeCode.REF.getValue(), new RefKeywordListener()); + schemaValidatorsConfig1.addKeywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(), + new PropertiesKeywordListener()); + this.jsonSchema1 = schemaFactory.getSchema(getSchema(), schemaValidatorsConfig1); } private JsonMetaSchema getJsonMetaSchema() { @@ -75,6 +84,41 @@ public void testWalk() throws IOException { + "}"))); } + @Test + public void testWalkWithDifferentListeners() throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + // This instance of schema contains all listeners. + ValidationResult result = jsonSchema.walk( + objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false); + JsonNode collectedNode = (JsonNode) result.getCollectorContext().get(SAMPLE_WALK_COLLECTOR_TYPE); + assertEquals(collectedNode, (objectMapper.readTree("{" + + " \"PROPERTY1\": \"sample1\"," + + " \"PROPERTY2\": \"sample2\"," + + " \"property3\": {" + + " \"street_address\":\"test-address\"," + + " \"phone_number\": {" + + " \"country-code\": \"091\"," + + " \"number\": \"123456789\"" + + " }" + + " }" + + "}"))); + // 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); + assertEquals(collectedNode, (objectMapper.readTree("{" + + " \"property3\": {" + + " \"street_address\":\"test-address\"," + + " \"phone_number\": {" + + " \"country-code\": \"091\"," + + " \"number\": \"123456789\"" + + " }" + + " }" + + "}"))); + } + private InputStream getSchema() { return getClass().getClassLoader().getResourceAsStream("schema/walk-schema.json"); }