Skip to content

Commit

Permalink
Remove incorrect logic for oneOf, anyOf and properties (#1053)
Browse files Browse the repository at this point in the history
* Remove incorrect logic for oneOf, anyOf and properties

* Refactor

* Refactor

* Refactor
  • Loading branch information
justin-tay committed Jun 11, 2024
1 parent 11c0df2 commit 3957163
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 297 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,14 @@ public AdditionalPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath
}
}

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

protected Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
JsonNodePath instanceLocation, boolean walk) {
debug(logger, node, rootNode, instanceLocation);
if (!node.isObject()) {
// ignore no object
Expand Down Expand Up @@ -110,15 +117,7 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
if (pname.startsWith("#")) {
continue;
}
boolean handledByPatternProperties = false;
for (RegularExpression pattern : patternProperties) {
if (pattern.matches(pname)) {
handledByPatternProperties = true;
break;
}
}

if (!allowedProperties.contains(pname) && !handledByPatternProperties) {
if (!allowedProperties.contains(pname) && !handledByPatternProperties(pname)) {
if (!allowAdditionalProperties) {
if (errors == null) {
errors = new LinkedHashSet<>();
Expand All @@ -129,26 +128,16 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
.failFast(executionContext.isFailFast()).arguments(pname).build());
} else {
if (additionalPropertiesSchema != null) {
ValidatorState state = executionContext.getValidatorState();
if (state != null && state.isWalkEnabled()) {
Set<ValidationMessage> results = additionalPropertiesSchema.walk(executionContext,
entry.getValue(), rootNode, instanceLocation.append(pname),
state.isValidationEnabled());
if (!results.isEmpty()) {
if (errors == null) {
errors = new LinkedHashSet<>();
}
errors.addAll(results);
}
} else {
Set<ValidationMessage> results = additionalPropertiesSchema.validate(executionContext,
entry.getValue(), rootNode, instanceLocation.append(pname));
if (!results.isEmpty()) {
if (errors == null) {
errors = new LinkedHashSet<>();
}
errors.addAll(results);
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);
}
}
}
Expand All @@ -166,7 +155,7 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
@Override
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) {
if (shouldValidateSchema && node != null) {
return validate(executionContext, node, rootNode, instanceLocation);
return validate(executionContext, node, rootNode, instanceLocation, true);
}

if (node == null || !node.isObject()) {
Expand All @@ -181,28 +170,27 @@ public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode n
if (pname.startsWith("#")) {
continue;
}
boolean handledByPatternProperties = false;
for (RegularExpression pattern : patternProperties) {
if (pattern.matches(pname)) {
handledByPatternProperties = true;
break;
}
}

if (!allowedProperties.contains(pname) && !handledByPatternProperties) {
if (!allowedProperties.contains(pname) && !handledByPatternProperties(pname)) {
if (allowAdditionalProperties) {
if (additionalPropertiesSchema != null) {
ValidatorState state = executionContext.getValidatorState();
if (state != null && state.isWalkEnabled()) {
additionalPropertiesSchema.walk(executionContext, node.get(pname), rootNode, instanceLocation.append(pname), state.isValidationEnabled());
}
additionalPropertiesSchema.walk(executionContext, node.get(pname), rootNode,
instanceLocation.append(pname), shouldValidateSchema);
}
}
}
}
return Collections.emptySet();
}

private boolean handledByPatternProperties(String pname) {
for (RegularExpression pattern : this.patternProperties) {
if (pattern.matches(pname)) {
return true;
}
}
return false;
}

private boolean collectAnnotations() {
return hasUnevaluatedPropertiesValidator();
}
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/com/networknt/schema/AllOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,18 @@ public AllOfValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath

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

// get the Validator state object storing validation data
ValidatorState state = executionContext.getValidatorState();
protected Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean walk) {
debug(logger, node, rootNode, instanceLocation);

SetView<ValidationMessage> childSchemaErrors = null;

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

if (!state.isWalkEnabled()) {
if (!walk) {
localErrors = schema.validate(executionContext, node, rootNode, instanceLocation);
} else {
localErrors = schema.walk(executionContext, node, rootNode, instanceLocation, true);
Expand Down Expand Up @@ -111,7 +112,7 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
@Override
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) {
if (shouldValidateSchema) {
return validate(executionContext, node, rootNode, instanceLocation);
return validate(executionContext, node, rootNode, instanceLocation, true);
}
for (JsonSchema schema : this.schemas) {
// Walk through the schema
Expand Down
28 changes: 9 additions & 19 deletions src/main/java/com/networknt/schema/AnyOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,18 @@ public AnyOfValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath
}

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

// get the Validator state object storing validation data
ValidatorState state = executionContext.getValidatorState();
protected Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
JsonNodePath instanceLocation, boolean walk) {
debug(logger, node, rootNode, instanceLocation);

if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators()) {
executionContext.enterDiscriminatorContext(new DiscriminatorContext(), instanceLocation);
}

boolean initialHasMatchedNode = state.hasMatchedNode();

SetView<ValidationMessage> allErrors = null;

int numberOfValidSubSchemas = 0;
Expand All @@ -75,8 +75,6 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
executionContext.setFailFast(false);
for (JsonSchema schema : this.schemas) {
Set<ValidationMessage> errors = Collections.emptySet();
state.setMatchedNode(initialHasMatchedNode);

TypeValidator typeValidator = schema.getTypeValidator();
if (typeValidator != null) {
// If schema has type validator and node type doesn't match with schemaType then
Expand All @@ -90,19 +88,14 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
continue;
}
}
if (!state.isWalkEnabled()) {
if (!walk) {
errors = schema.validate(executionContext, node, rootNode, instanceLocation);
} else {
errors = schema.walk(executionContext, node, rootNode, instanceLocation, true);
}

// check if any validation errors have occurred
if (errors.isEmpty()) {
// check whether there are no errors HOWEVER we have validated the exact
// validator
if (!state.hasMatchedNode()) {
continue;
}
// we found a valid subschema, so increase counter
numberOfValidSubSchemas++;
}
Expand Down Expand Up @@ -159,9 +152,6 @@ && canShortCircuit() && canShortCircuit(executionContext)) {
if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators()) {
executionContext.leaveDiscriminatorContextImmediately(instanceLocation);
}
if (allErrors == null || allErrors.isEmpty()) {
state.setMatchedNode(true);
}
}
if (numberOfValidSubSchemas >= 1) {
return Collections.emptySet();
Expand All @@ -172,7 +162,7 @@ && canShortCircuit() && canShortCircuit(executionContext)) {
@Override
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) {
if (shouldValidateSchema) {
return validate(executionContext, node, rootNode, instanceLocation);
return validate(executionContext, node, rootNode, instanceLocation, true);
}
for (JsonSchema schema : this.schemas) {
schema.walk(executionContext, node, rootNode, instanceLocation, false);
Expand Down
14 changes: 11 additions & 3 deletions src/main/java/com/networknt/schema/DependentSchemas.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,23 @@ public DependentSchemas(SchemaLocation schemaLocation, JsonNodePath evaluationPa
}

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

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

Set<ValidationMessage> errors = null;
for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) {
String pname = it.next();
JsonSchema schema = this.schemaDependencies.get(pname);
if (schema != null) {
Set<ValidationMessage> schemaDependenciesErrors = schema.validate(executionContext, node, rootNode, instanceLocation);
Set<ValidationMessage> schemaDependenciesErrors = !walk
? schema.validate(executionContext, node, rootNode, instanceLocation)
: schema.walk(executionContext, node, rootNode, instanceLocation, true);
if (!schemaDependenciesErrors.isEmpty()) {
if (errors == null) {
errors = new LinkedHashSet<>();
Expand All @@ -72,7 +80,7 @@ public void preloadJsonSchema() {
@Override
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) {
if (shouldValidateSchema) {
return validate(executionContext, node, rootNode, instanceLocation);
return validate(executionContext, node, rootNode, instanceLocation, true);
}
for (JsonSchema schema : this.schemaDependencies.values()) {
schema.walk(executionContext, node, rootNode, instanceLocation, false);
Expand Down
19 changes: 0 additions & 19 deletions src/main/java/com/networknt/schema/ExecutionContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
public class ExecutionContext {
private ExecutionConfig executionConfig;
private CollectorContext collectorContext = null;
private ValidatorState validatorState = null;
private Stack<DiscriminatorContext> discriminatorContexts = null;
private JsonNodeAnnotations annotations = null;
private JsonNodeResults results = null;
Expand Down Expand Up @@ -153,24 +152,6 @@ public void setFailFast(boolean failFast) {
this.failFast = failFast;
}

/**
* Gets the validator state.
*
* @return the validator state
*/
public ValidatorState getValidatorState() {
return validatorState;
}

/**
* Sets the validator state.
*
* @param validatorState the validator state
*/
public void setValidatorState(ValidatorState validatorState) {
this.validatorState = validatorState;
}

public DiscriminatorContext getCurrentDiscriminatorContext() {
if (this.discriminatorContexts == null) {
return null;
Expand Down
32 changes: 0 additions & 32 deletions src/main/java/com/networknt/schema/JsonSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ public class JsonSchema extends BaseJsonValidator {
private boolean validatorsLoaded = false;
private boolean recursiveAnchor = false;

private JsonValidator requiredValidator = null;
private TypeValidator typeValidator;

private final String id;
Expand Down Expand Up @@ -161,7 +160,6 @@ protected JsonSchema(JsonSchema copy) {
this.validators = copy.validators;
this.validatorsLoaded = copy.validatorsLoaded;
this.recursiveAnchor = copy.recursiveAnchor;
this.requiredValidator = copy.requiredValidator;
this.typeValidator = copy.typeValidator;
this.id = copy.id;
}
Expand Down Expand Up @@ -189,7 +187,6 @@ public JsonSchema fromRef(JsonSchema refEvaluationParentSchema, JsonNodePath ref
copy.evaluationParentSchema = refEvaluationParentSchema;
// Validator state is reset due to the changes in evaluation path
copy.validatorsLoaded = false;
copy.requiredValidator = null;
copy.typeValidator = null;
copy.validators = null;
return copy;
Expand All @@ -204,7 +201,6 @@ public JsonSchema withConfig(SchemaValidatorsConfig config) {
copy.getValidationContext().getSchemaResources(),
copy.getValidationContext().getDynamicAnchors());
copy.validatorsLoaded = false;
copy.requiredValidator = null;
copy.typeValidator = null;
copy.validators = null;
return copy;
Expand Down Expand Up @@ -472,8 +468,6 @@ private List<JsonValidator> read(JsonNode schemaNode) {

if ("$ref".equals(pname)) {
refValidator = validator;
} else if ("required".equals(pname)) {
this.requiredValidator = validator;
} else if ("type".equals(pname)) {
if (validator instanceof TypeValidator) {
this.typeValidator = (TypeValidator) validator;
Expand Down Expand Up @@ -537,9 +531,6 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
}

SetView<ValidationMessage> errors = null;
// Set the walkEnabled and isValidationEnabled flag in internal validator state.
setValidatorState(executionContext, false, true);

for (JsonValidator v : getValidators()) {
Set<ValidationMessage> results = null;

Expand Down Expand Up @@ -894,8 +885,6 @@ public ValidationResult validateAndCollect(ExecutionContext executionContext, Js
* @return ValidationResult
*/
private ValidationResult validateAndCollect(ExecutionContext executionContext, JsonNode jsonNode, JsonNode rootNode, JsonNodePath instanceLocation) {
// Set the walkEnabled and isValidationEnabled flag in internal validator state.
setValidatorState(executionContext, false, true);
// Validate.
Set<ValidationMessage> errors = validate(executionContext, jsonNode, rootNode, instanceLocation);

Expand Down Expand Up @@ -990,8 +979,6 @@ public ValidationResult walkAtNode(ExecutionContext executionContext, JsonNode n

private ValidationResult walkAtNodeInternal(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
JsonNodePath instanceLocation, boolean shouldValidateSchema) {
// Set the walkEnabled flag in internal validator state.
setValidatorState(executionContext, true, shouldValidateSchema);
// Walk through the schema.
Set<ValidationMessage> errors = walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);

Expand Down Expand Up @@ -1041,30 +1028,11 @@ public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode n
}

/************************ END OF WALK METHODS **********************************/

private static void setValidatorState(ExecutionContext executionContext, boolean isWalkEnabled,
boolean shouldValidateSchema) {
// Get the Validator state object storing validation data
ValidatorState validatorState = executionContext.getValidatorState();
if (validatorState == null) {
// If one has not been created, instantiate one
executionContext.setValidatorState(new ValidatorState(isWalkEnabled, shouldValidateSchema));
}
}

@Override
public String toString() {
return "\"" + getEvaluationPath() + "\" : " + getSchemaNode().toString();
}

public boolean hasRequiredValidator() {
return this.requiredValidator != null;
}

public JsonValidator getRequiredValidator() {
return this.requiredValidator;
}

public boolean hasTypeValidator() {
return getTypeValidator() != null;
}
Expand Down
Loading

0 comments on commit 3957163

Please sign in to comment.