Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove incorrect logic for oneOf, anyOf and properties #1053

Merged
merged 4 commits into from
Jun 11, 2024
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
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