Skip to content

Commit

Permalink
Fixing Walk Listeners Issues. (#368)
Browse files Browse the repository at this point in the history
* Fixing walk issues for properties

* Correcting walk changes for few validators

* adding item walk listener

* walk listener changes

* walk listener changes

Co-authored-by: Prashanth Josyula <prashanth.chaitanya@salesforce.com>
  • Loading branch information
prashanthjos and prashanth-chaitanya authored Jan 16, 2021
1 parent 1783eb5 commit a5eca44
Show file tree
Hide file tree
Showing 13 changed files with 272 additions and 170 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,49 +94,17 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
errors.add(buildValidationMessage(at, pname));
} else {
if (additionalPropertiesSchema != null) {
errors.addAll(additionalPropertiesSchema.validate(node.get(pname), rootNode, at + "." + pname));
ValidatorState state = validatorState.get();
if (state != null && state.isWalkEnabled()) {
errors.addAll(additionalPropertiesSchema.walk(node.get(pname), rootNode, at + "." + pname, state.isValidationEnabledWhileWalking()));
} else {
errors.addAll(additionalPropertiesSchema.validate(node.get(pname), rootNode, at + "." + pname));
}
}
}
}
}
return Collections.unmodifiableSet(errors);
}

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
Set<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();
if (!node.isObject()) {
return validationMessages;
}
// Validate schema if required.
if (shouldValidateSchema) {
validationMessages.addAll(validate(node, rootNode, at));
}
for (Iterator<String> it = node.fieldNames(); it.hasNext();) {
String pname = it.next();
// skip the context items
if (pname.startsWith("#")) {
continue;
}
boolean handledByPatternProperties = false;
for (Pattern pattern : patternProperties) {
Matcher m = pattern.matcher(pname);
if (m.find()) {
handledByPatternProperties = true;
break;
}
}
if (!allowedProperties.contains(pname) && !handledByPatternProperties) {
if (allowAdditionalProperties) {
if (additionalPropertiesSchema != null) {
validationMessages.addAll(additionalPropertiesSchema.walk(node.get(pname), rootNode, at + "." + pname,
shouldValidateSchema));
}
}
}
}

return validationMessages;
}

}
4 changes: 0 additions & 4 deletions src/main/java/com/networknt/schema/AllOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at,
Set<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();

for (JsonSchema schema : schemas) {
// Check if validation is needed.
if (shouldValidateSchema) {
validationMessages.addAll(schema.validate(node, rootNode, at));
}
// Walk through the schema
validationMessages.addAll(schema.walk(node, rootNode, at, shouldValidateSchema));
}
Expand Down
137 changes: 77 additions & 60 deletions src/main/java/com/networknt/schema/ItemsValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
package com.networknt.schema;

import com.fasterxml.jackson.databind.JsonNode;
import com.networknt.schema.walk.DefaultItemWalkListenerRunner;
import com.networknt.schema.walk.WalkListenerRunner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -30,17 +33,21 @@ public class ItemsValidator extends BaseJsonValidator implements JsonValidator {
private List<JsonSchema> tupleSchema;
private boolean additionalItems = true;
private JsonSchema additionalSchema;
private WalkListenerRunner arrayItemWalkListenerRunner;
private ValidationContext validationContext;

public ItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
public ItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema,
ValidationContext validationContext) {
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.ITEMS, validationContext);
if (schemaNode.isObject() || schemaNode.isBoolean()) {
schema = new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), schemaNode, parentSchema)
.initialize();
schema = new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), schemaNode,
parentSchema).initialize();
} else {
tupleSchema = new ArrayList<JsonSchema>();
for (JsonNode s : schemaNode) {
tupleSchema.add(new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), s, parentSchema)
.initialize());
tupleSchema.add(
new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), s, parentSchema)
.initialize());
}

JsonNode addItemNode = getParentSchema().getSchemaNode().get(PROPERTY_ADDITIONAL_ITEMS);
Expand All @@ -49,10 +56,13 @@ public ItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
additionalItems = addItemNode.asBoolean();
} else if (addItemNode.isObject()) {
additionalSchema = new JsonSchema(validationContext, parentSchema.getCurrentUri(), addItemNode)
.initialize();
.initialize();
}
}
}
arrayItemWalkListenerRunner = new DefaultItemWalkListenerRunner(config.getArrayItemWalkListeners());

this.validationContext = validationContext;

parseErrorCode(getValidatorType().getErrorCodeKey());
}
Expand Down Expand Up @@ -100,57 +110,64 @@ private void doValidate(Set<ValidationMessage> errors, int i, JsonNode node, Jso
}
}
}

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
HashSet<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();
if (node != null && node.isArray()) {
int i = 0;
for (JsonNode n : node) {
doWalk(validationMessages, i, n, rootNode, at, shouldValidateSchema);
i++;
}
} else {
doWalk(validationMessages, 0, node, rootNode, at, shouldValidateSchema);
}
return validationMessages;
}

private void doWalk(HashSet<ValidationMessage> validationMessages, int i, JsonNode node, JsonNode rootNode,
String at, boolean shouldValidateSchema) {
if (schema != null) {
if (shouldValidateSchema) {
validationMessages.addAll(schema.validate(node, rootNode, at));
}
// Walk the schema.
validationMessages.addAll(schema.walk(node, rootNode, at + "[" + i + "]", shouldValidateSchema));
}

if (tupleSchema != null) {
if (i < tupleSchema.size()) {
if (shouldValidateSchema) {
validationMessages.addAll(tupleSchema.get(i).validate(node, rootNode, at));
}
// walk tuple schema
validationMessages.addAll(tupleSchema.get(i).walk(node, rootNode, at + "[" + i + "]", shouldValidateSchema));
} else {
if (additionalSchema != null) {
if (shouldValidateSchema) {
validationMessages.addAll(additionalSchema.validate(node, rootNode, at));
}
// walk additional item schema
validationMessages.addAll(additionalSchema.walk(node, rootNode, at + "[" + i + "]", shouldValidateSchema));
}
}
}
}

public List<JsonSchema> getTupleSchema() {
return this.tupleSchema;
}

public JsonSchema getSchema() {
return schema;
}

}

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
HashSet<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();
if (node != null && node.isArray()) {
int i = 0;
for (JsonNode n : node) {
doWalk(validationMessages, i, n, rootNode, at, shouldValidateSchema);
i++;
}
} else {
doWalk(validationMessages, 0, node, rootNode, at, shouldValidateSchema);
}
return validationMessages;
}

private void doWalk(HashSet<ValidationMessage> validationMessages, int i, JsonNode node, JsonNode rootNode,
String at, boolean shouldValidateSchema) {
if (schema != null) {
// Walk the schema.
walkSchema(schema, node, rootNode, at + "[" + i + "]", shouldValidateSchema, validationMessages);
}

if (tupleSchema != null) {
if (i < tupleSchema.size()) {
// walk tuple schema
walkSchema(tupleSchema.get(i), node, rootNode, at + "[" + i + "]", shouldValidateSchema,
validationMessages);
} else {
if (additionalSchema != null) {
// walk additional item schema
walkSchema(additionalSchema, node, rootNode, at + "[" + i + "]", shouldValidateSchema,
validationMessages);
}
}
}
}

private void walkSchema(JsonSchema walkSchema, JsonNode node, JsonNode rootNode, String at,
boolean shouldValidateSchema, Set<ValidationMessage> validationMessages) {
boolean executeWalk = arrayItemWalkListenerRunner.runPreWalkListeners(ValidatorTypeCode.ITEMS.getValue(), node,
rootNode, at, walkSchema.getSchemaPath(), walkSchema.getSchemaNode(), walkSchema.getParentSchema(),
validationContext.getJsonSchemaFactory());
if (executeWalk) {
validationMessages.addAll(walkSchema.walk(node, rootNode, at, shouldValidateSchema));
}
arrayItemWalkListenerRunner.runPostWalkListeners(ValidatorTypeCode.ITEMS.getValue(), node, rootNode, at,
walkSchema.getSchemaPath(), walkSchema.getSchemaNode(), walkSchema.getParentSchema(),
validationContext.getJsonSchemaFactory(), validationMessages);

}

public List<JsonSchema> getTupleSchema() {
return this.tupleSchema;
}

public JsonSchema getSchema() {
return schema;
}

}
28 changes: 24 additions & 4 deletions src/main/java/com/networknt/schema/JsonSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,12 @@ public ValidationResult validateAndCollect(JsonNode node) {
*/
protected ValidationResult validateAndCollect(JsonNode jsonNode, JsonNode rootNode, String at) {
try {
// Create the collector context object.
CollectorContext collectorContext = new CollectorContext();
CollectorContext collectorContext;
if(this.config !=null && this.config.getCollectorContext() != null){
collectorContext = this.config.getCollectorContext();
} else {
collectorContext = new CollectorContext();
}
// Set the collector context in thread info, this is unique for every thread.
ThreadInfo.set(CollectorContext.COLLECTOR_CONTEXT_THREAD_LOCAL_KEY, collectorContext);
Set<ValidationMessage> errors = validate(jsonNode, rootNode, at);
Expand Down Expand Up @@ -275,7 +279,10 @@ public ValidationResult walk(JsonNode node, boolean shouldValidateSchema) {
// Create the collector context object.
CollectorContext collectorContext = new CollectorContext();
// Set the collector context in thread info, this is unique for every thread.
ThreadInfo.set(CollectorContext.COLLECTOR_CONTEXT_THREAD_LOCAL_KEY, collectorContext);
ThreadInfo.set(CollectorContext.COLLECTOR_CONTEXT_THREAD_LOCAL_KEY, collectorContext);
// Set the walkEnabled flag in internal validator state.
setValidatorState(true, shouldValidateSchema);
// Walk through the schema.
Set<ValidationMessage> errors = walk(node, node, AT_ROOT, shouldValidateSchema);
// Load all the data from collectors into the context.
collectorContext.loadCollectors();
Expand All @@ -284,7 +291,8 @@ public ValidationResult walk(JsonNode node, boolean shouldValidateSchema) {
return validationResult;
}

@Override

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
Set<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();
// Walk through all the JSONWalker's.
Expand All @@ -309,6 +317,18 @@ public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at,

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

private void setValidatorState(boolean isWalkEnabled, boolean shouldValidateSchema) {
// Get the Validator state object storing validation data
ValidatorState state = validatorState.get();
if (state == null) {
// if one has not been created, instantiate one
state = new ValidatorState();
state.setWalkEnabled(isWalkEnabled);
state.setValidationEnabledWhileWalking(shouldValidateSchema);
validatorState.set(state);
}
}

@Override
public String toString() {
return "\"" + getSchemaPath() + "\" : " + getSchemaNode().toString();
Expand Down
7 changes: 1 addition & 6 deletions src/main/java/com/networknt/schema/NotValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,7 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
Set<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();
if (shouldValidateSchema) {
validationMessages.addAll(validate(node, rootNode, at));
}
validationMessages.addAll(schema.walk(node, rootNode, at, shouldValidateSchema));
return validationMessages;
return schema.walk(node, rootNode, at, shouldValidateSchema);
}

}
28 changes: 25 additions & 3 deletions src/main/java/com/networknt/schema/OneOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,14 @@ public OneOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);

ValidatorState state = validatorState.get();
if (state == null) {
state = new ValidatorState();
validatorState.set(state);
}
// this is a complex validator, we set the flag to true
ValidatorState state = new ValidatorState();
state.setComplexValidator(true);
validatorState.set(state);


int numberOfValidSchema = 0;
Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
Expand All @@ -145,6 +149,7 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
// }

for (ShortcutValidator validator : schemas) {
Set<ValidationMessage> schemaErrors = null;
// Reset state in case the previous validator did not match
state.setMatchedNode(true);
if (!validator.allConstantsMatch(node)) {
Expand All @@ -155,7 +160,11 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String

// get the current validator
JsonSchema schema = validator.schema;
Set<ValidationMessage> schemaErrors = schema.validate(node, rootNode, at);
if (!state.isWalkEnabled()) {
schemaErrors = schema.validate(node, rootNode, at);
} else {
schemaErrors = schema.walk(node, rootNode, at, state.isValidationEnabledWhileWalking());
}

// check if any validation errors have occurred
if (schemaErrors.isEmpty()) {
Expand Down Expand Up @@ -187,4 +196,17 @@ public List<JsonSchema> getChildSchemas() {
return childJsonSchemas;
}

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
HashSet<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();
if (shouldValidateSchema) {
validationMessages.addAll(validate(node, rootNode, at));
} else {
for (ShortcutValidator validator : schemas) {
validator.schema.walk(node, rootNode, at , shouldValidateSchema);
}
}
return validationMessages;
}

}
7 changes: 1 addition & 6 deletions src/main/java/com/networknt/schema/PatternValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,7 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
Set<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();
if (shouldValidateSchema) {
validationMessages.addAll(validate(node, rootNode, at));
}
validationMessages.addAll(delegate.walk(node, rootNode, at, shouldValidateSchema));
return validationMessages;
return delegate.walk(node, rootNode, at, shouldValidateSchema);
}

private static class PatternValidatorJava extends BaseJsonValidator implements JsonValidator {
Expand Down
Loading

0 comments on commit a5eca44

Please sign in to comment.