Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
<version>1.5.9</version>
<version>2.0.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>JsonSchemaValidator</name>
<description>A json schema validator that supports draft v4, v6, v7, v2019-09 and v2020-12</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,17 @@ public AdditionalPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath
}

@Override
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
JsonNodePath instanceLocation) {
return validate(executionContext, node, rootNode, instanceLocation, false);
validate(executionContext, node, rootNode, instanceLocation, false);
}

protected Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
JsonNodePath instanceLocation, boolean walk) {
debug(logger, executionContext, node, rootNode, instanceLocation);
if (!node.isObject()) {
// ignore no object
return Collections.emptySet();
return;
}

Set<String> matchedInstancePropertyNames = null;
Expand All @@ -108,8 +108,6 @@ protected Set<ValidationMessage> validate(ExecutionContext executionContext, Jso
}
}

Set<ValidationMessage> errors = null;

for (Iterator<Entry<String, JsonNode>> it = node.fields(); it.hasNext(); ) {
Entry<String, JsonNode> entry = it.next();
String pname = entry.getKey();
Expand All @@ -119,25 +117,18 @@ protected Set<ValidationMessage> validate(ExecutionContext executionContext, Jso
}
if (!allowedProperties.contains(pname) && !handledByPatternProperties(pname)) {
if (!allowAdditionalProperties) {
if (errors == null) {
errors = new LinkedHashSet<>();
}
errors.add(message().instanceNode(node).property(pname)
executionContext.addError(message().instanceNode(node).property(pname)
.instanceLocation(instanceLocation)
.locale(executionContext.getExecutionConfig().getLocale())
.failFast(executionContext.isFailFast()).arguments(pname).build());
} else {
if (additionalPropertiesSchema != null) {
Set<ValidationMessage> results = !walk
? additionalPropertiesSchema.validate(executionContext, entry.getValue(), rootNode,
instanceLocation.append(pname))
: additionalPropertiesSchema.walk(executionContext, entry.getValue(), rootNode,
instanceLocation.append(pname), true);
if (!results.isEmpty()) {
if (errors == null) {
errors = new LinkedHashSet<>();
}
errors.addAll(results);
if (!walk) {
additionalPropertiesSchema.validate(executionContext, entry.getValue(), rootNode,
instanceLocation.append(pname));
} else {
additionalPropertiesSchema.walk(executionContext, entry.getValue(), rootNode,
instanceLocation.append(pname), true);
}
}
}
Expand All @@ -149,18 +140,18 @@ protected Set<ValidationMessage> validate(ExecutionContext executionContext, Jso
.value(matchedInstancePropertyNames != null ? matchedInstancePropertyNames : Collections.emptySet())
.build());
}
return errors == null ? Collections.emptySet() : Collections.unmodifiableSet(errors);
}

@Override
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) {
public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) {
if (shouldValidateSchema && node != null) {
return validate(executionContext, node, rootNode, instanceLocation, true);
validate(executionContext, node, rootNode, instanceLocation, true);
return;
}

if (node == null || !node.isObject()) {
// ignore no object
return Collections.emptySet();
return;
}

// Else continue walking.
Expand All @@ -179,7 +170,6 @@ public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode n
}
}
}
return Collections.emptySet();
}

private boolean handledByPatternProperties(String pname) {
Expand Down
33 changes: 9 additions & 24 deletions src/main/java/com/networknt/schema/AllOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.networknt.schema.utils.SetView;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -52,31 +51,19 @@ public AllOfValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath
}

@Override
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) {
return validate(executionContext, node, rootNode, instanceLocation, false);
public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) {
validate(executionContext, node, rootNode, instanceLocation, false);
}

protected Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean walk) {
protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean walk) {
debug(logger, executionContext, node, rootNode, instanceLocation);

SetView<ValidationMessage> childSchemaErrors = null;

for (JsonSchema schema : this.schemas) {
Set<ValidationMessage> localErrors = null;

if (!walk) {
localErrors = schema.validate(executionContext, node, rootNode, instanceLocation);
schema.validate(executionContext, node, rootNode, instanceLocation);
} else {
localErrors = schema.walk(executionContext, node, rootNode, instanceLocation, true);
}

if (localErrors != null && !localErrors.isEmpty()) {
if (childSchemaErrors == null) {
childSchemaErrors = new SetView<>();
}
childSchemaErrors.union(localErrors);
schema.walk(executionContext, node, rootNode, instanceLocation, true);
}

if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) {
final Iterator<JsonNode> arrayElements = this.schemaNode.elements();
while (arrayElements.hasNext()) {
Expand Down Expand Up @@ -106,21 +93,19 @@ protected Set<ValidationMessage> validate(ExecutionContext executionContext, Jso
}
}
}

return childSchemaErrors != null ? childSchemaErrors : Collections.emptySet();
}

@Override
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) {
public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) {
if (shouldValidateSchema && node != null) {
return validate(executionContext, node, rootNode, instanceLocation, true);
validate(executionContext, node, rootNode, instanceLocation, true);
return;
}
for (JsonSchema schema : this.schemas) {
// Walk through the schema
schema.walk(executionContext, node, rootNode, instanceLocation, false);
}
return Collections.emptySet();
}
}

@Override
public void preloadJsonSchema() {
Expand Down
6 changes: 1 addition & 5 deletions src/main/java/com/networknt/schema/AnnotationKeyword.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@

import com.fasterxml.jackson.databind.JsonNode;

import java.util.Collections;
import java.util.Set;

/**
* Used for Keywords that have no validation aspect, but are part of the metaschema, where annotations may need to be collected.
*/
Expand All @@ -33,15 +30,14 @@ public Validator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, Jso
}

@Override
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) {
public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) {
if (collectAnnotations(executionContext)) {
Object value = getAnnotationValue(getSchemaNode());
if (value != null) {
putAnnotation(executionContext,
annotation -> annotation.instanceLocation(instanceLocation).value(value));
}
}
return Collections.emptySet();
}

private Object getAnnotationValue(JsonNode schemaNode) {
Expand Down
65 changes: 37 additions & 28 deletions src/main/java/com/networknt/schema/AnyOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package com.networknt.schema;

import com.fasterxml.jackson.databind.JsonNode;
import com.networknt.schema.utils.SetView;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -54,45 +53,48 @@ public AnyOfValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath
}

@Override
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
JsonNodePath instanceLocation) {
return validate(executionContext, node, rootNode, instanceLocation, false);
validate(executionContext, node, rootNode, instanceLocation, false);
}

protected Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
JsonNodePath instanceLocation, boolean walk) {
debug(logger, executionContext, node, rootNode, instanceLocation);

if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) {
executionContext.enterDiscriminatorContext(new DiscriminatorContext(), instanceLocation);
}
SetView<ValidationMessage> allErrors = null;

int numberOfValidSubSchemas = 0;
List<ValidationMessage> existingErrors = executionContext.getErrors();
List<ValidationMessage> allErrors = null;
List<ValidationMessage> errors = new ArrayList<>();
executionContext.setErrors(errors);
try {
// Save flag as nested schema evaluation shouldn't trigger fail fast
boolean failFast = executionContext.isFailFast();
try {
executionContext.setFailFast(false);
for (JsonSchema schema : this.schemas) {
Set<ValidationMessage> errors = Collections.emptySet();
errors.clear();
TypeValidator typeValidator = schema.getTypeValidator();
if (typeValidator != null) {
// If schema has type validator and node type doesn't match with schemaType then
// ignore it
// For union type, it is a must to call TypeValidator
if (typeValidator.getSchemaType() != JsonType.UNION && !typeValidator.equalsToSchemaType(node)) {
typeValidator.validate(executionContext, node, rootNode, instanceLocation);
if (allErrors == null) {
allErrors = new SetView<>();
allErrors = new ArrayList<>();
}
allErrors.union(typeValidator.validate(executionContext, node, rootNode, instanceLocation));
allErrors.addAll(errors);
continue;
}
}
if (!walk) {
errors = schema.validate(executionContext, node, rootNode, instanceLocation);
schema.validate(executionContext, node, rootNode, instanceLocation);
} else {
errors = schema.walk(executionContext, node, rootNode, instanceLocation, true);
schema.walk(executionContext, node, rootNode, instanceLocation, true);
}

// check if any validation errors have occurred
Expand All @@ -105,8 +107,8 @@ protected Set<ValidationMessage> validate(ExecutionContext executionContext, Jso
&& canShortCircuit() && canShortCircuit(executionContext)) {
// Clear all errors. Note that this is checked in finally.
allErrors = null;
// return empty errors.
return errors;
executionContext.setErrors(existingErrors);
return;
} else if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) {
DiscriminatorContext currentDiscriminatorContext = executionContext.getCurrentDiscriminatorContext();
if (currentDiscriminatorContext.isDiscriminatorMatchFound()
Expand All @@ -116,24 +118,25 @@ && canShortCircuit() && canShortCircuit(executionContext)) {
// which is generally discarded as it returns errors but the allErrors
// is getting processed in finally
if (allErrors == null) {
allErrors = new SetView<>();
allErrors = new ArrayList<>();
}
allErrors.union(Collections
.singleton(message().instanceNode(node).instanceLocation(instanceLocation)
.locale(executionContext.getExecutionConfig().getLocale())
.failFast(executionContext.isFailFast()).arguments(DISCRIMINATOR_REMARK)
.build()));
allErrors.add(message().instanceNode(node).instanceLocation(instanceLocation)
.locale(executionContext.getExecutionConfig().getLocale())
.failFast(executionContext.isFailFast()).arguments(DISCRIMINATOR_REMARK)
.build());
} else {
// Clear all errors. Note that this is checked in finally.
allErrors = null;
}
return errors;
existingErrors.addAll(errors);
executionContext.setErrors(existingErrors);
return;
}
}
if (allErrors == null) {
allErrors = new SetView<>();
allErrors = new ArrayList<>();
}
allErrors.union(errors);
allErrors.addAll(errors);
}
} finally {
// Restore flag
Expand All @@ -143,32 +146,38 @@ && canShortCircuit() && canShortCircuit(executionContext)) {
if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()
&& executionContext.getCurrentDiscriminatorContext().isActive()
&& !executionContext.getCurrentDiscriminatorContext().isDiscriminatorIgnore()) {
return Collections.singleton(message().instanceNode(node).instanceLocation(instanceLocation)
existingErrors.add(message().instanceNode(node).instanceLocation(instanceLocation)
.locale(executionContext.getExecutionConfig().getLocale())
.arguments(
"based on the provided discriminator. No alternative could be chosen based on the discriminator property")
.build());
executionContext.setErrors(existingErrors);
return;
}
} finally {
if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) {
executionContext.leaveDiscriminatorContextImmediately(instanceLocation);
}
}
if (numberOfValidSubSchemas >= 1) {
return Collections.emptySet();
executionContext.setErrors(existingErrors);
} else {
if (allErrors != null) {
existingErrors.addAll(allErrors);
}
executionContext.setErrors(existingErrors);
}
return allErrors != null ? allErrors : Collections.emptySet();
}

@Override
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) {
public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) {
if (shouldValidateSchema && node != null) {
return validate(executionContext, node, rootNode, instanceLocation, true);
validate(executionContext, node, rootNode, instanceLocation, true);
return;
}
for (JsonSchema schema : this.schemas) {
schema.walk(executionContext, node, rootNode, instanceLocation, false);
}
return Collections.emptySet();
}

/**
Expand Down
Loading