Skip to content

Commit 106f9f3

Browse files
committed
Refactor evaluation context out from validator state
1 parent cb26405 commit 106f9f3

16 files changed

+338
-65
lines changed

src/main/java/com/networknt/schema/ExecutionContext.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
package com.networknt.schema;
1818

19+
import java.util.ArrayDeque;
1920
import java.util.ArrayList;
21+
import java.util.Deque;
2022
import java.util.HashMap;
2123
import java.util.List;
2224
import java.util.Map;
@@ -40,8 +42,19 @@ public class ExecutionContext {
4042
private SchemaResults results = null;
4143
private List<Error> errors = new ArrayList<>();
4244

43-
private Map<NodePath, DiscriminatorState> discriminatorMapping = new HashMap<>();
45+
private final Map<NodePath, DiscriminatorState> discriminatorMapping = new HashMap<>();
4446

47+
final Deque<Object> evaluationPath = new ArrayDeque<>();
48+
final Deque<Schema> evaluationSchema = new ArrayDeque<>();
49+
50+
public Deque<Object> getEvaluationPath() {
51+
return evaluationPath;
52+
}
53+
54+
public Deque<Schema> getEvaluationSchema() {
55+
return evaluationSchema;
56+
}
57+
4558
public Map<NodePath, DiscriminatorState> getDiscriminatorMapping() {
4659
return discriminatorMapping;
4760
}

src/main/java/com/networknt/schema/Schema.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -696,14 +696,24 @@ private List<KeywordValidator> read(JsonNode schemaNode) {
696696

697697
@Override
698698
public void validate(ExecutionContext executionContext, JsonNode jsonNode, JsonNode rootNode, NodePath instanceLocation) {
699-
int currentErrors = executionContext.getErrors().size();
700-
for (KeywordValidator v : getValidators()) {
701-
v.validate(executionContext, jsonNode, rootNode, instanceLocation);
702-
}
703-
if (executionContext.getErrors().size() > currentErrors) {
704-
// Failed with assertion set result and drop all annotations from this schema
705-
// and all subschemas
706-
executionContext.getResults().setResult(instanceLocation, getSchemaLocation(), getEvaluationPath(), false);
699+
executionContext.evaluationSchema.push(this);
700+
try {
701+
int currentErrors = executionContext.getErrors().size();
702+
for (KeywordValidator v : getValidators()) {
703+
executionContext.evaluationPath.push(v.getKeyword());
704+
try {
705+
v.validate(executionContext, jsonNode, rootNode, instanceLocation);
706+
} finally {
707+
executionContext.evaluationPath.pop();
708+
}
709+
}
710+
if (executionContext.getErrors().size() > currentErrors) {
711+
// Failed with assertion set result and drop all annotations from this schema
712+
// and all subschemas
713+
executionContext.getResults().setResult(instanceLocation, getSchemaLocation(), getEvaluationPath(), false);
714+
}
715+
} finally {
716+
executionContext.evaluationSchema.pop();
707717
}
708718
}
709719

src/main/java/com/networknt/schema/keyword/AllOfValidator.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,19 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode
5959

6060
protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
6161
NodePath instanceLocation, boolean walk) {
62+
int schemaIndex = 0;
6263
for (Schema schema : this.schemas) {
63-
if (!walk) {
64-
schema.validate(executionContext, node, rootNode, instanceLocation);
65-
} else {
66-
schema.walk(executionContext, node, rootNode, instanceLocation, true);
64+
executionContext.getEvaluationPath().push(schemaIndex);
65+
try {
66+
if (!walk) {
67+
schema.validate(executionContext, node, rootNode, instanceLocation);
68+
} else {
69+
schema.walk(executionContext, node, rootNode, instanceLocation, true);
70+
}
71+
} finally {
72+
executionContext.getEvaluationPath().pop();
6773
}
74+
schemaIndex++;
6875
}
6976
}
7077

@@ -75,9 +82,16 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root
7582
validate(executionContext, node, rootNode, instanceLocation, true);
7683
return;
7784
}
85+
int schemaIndex = 0;
7886
for (Schema schema : this.schemas) {
7987
// Walk through the schema
80-
schema.walk(executionContext, node, rootNode, instanceLocation, false);
88+
executionContext.getEvaluationPath().push(schemaIndex);
89+
try {
90+
schema.walk(executionContext, node, rootNode, instanceLocation, false);
91+
} finally {
92+
executionContext.getEvaluationPath().pop();
93+
}
94+
schemaIndex++;
8195
}
8296
}
8397

src/main/java/com/networknt/schema/keyword/AnyOfValidator.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo
7373
// Save flag as nested schema evaluation shouldn't trigger fail fast
7474
boolean failFast = executionContext.isFailFast();
7575
try {
76+
int schemaIndex = 0;
7677
executionContext.setFailFast(false);
7778
for (Schema schema : this.schemas) {
7879
subSchemaErrors.clear(); // Reuse and clear for each run
@@ -90,11 +91,17 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo
9091
continue;
9192
}
9293
}
93-
if (!walk) {
94-
schema.validate(executionContext, node, rootNode, instanceLocation);
95-
} else {
96-
schema.walk(executionContext, node, rootNode, instanceLocation, true);
94+
executionContext.getEvaluationPath().push(schemaIndex);
95+
try {
96+
if (!walk) {
97+
schema.validate(executionContext, node, rootNode, instanceLocation);
98+
} else {
99+
schema.walk(executionContext, node, rootNode, instanceLocation, true);
100+
}
101+
} finally {
102+
executionContext.getEvaluationPath().pop();
97103
}
104+
schemaIndex++;
98105

99106
// check if any validation errors have occurred
100107
if (subSchemaErrors.isEmpty()) {
@@ -202,7 +209,14 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root
202209
return;
203210
}
204211
for (Schema schema : this.schemas) {
205-
schema.walk(executionContext, node, rootNode, instanceLocation, false);
212+
int schemaIndex = 0;
213+
executionContext.getEvaluationPath().push(schemaIndex);
214+
try {
215+
schema.walk(executionContext, node, rootNode, instanceLocation, false);
216+
} finally {
217+
executionContext.getEvaluationPath().pop();
218+
}
219+
schemaIndex++;
206220
}
207221
}
208222

src/main/java/com/networknt/schema/keyword/DependenciesValidator.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,12 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode
7979
}
8080
Schema schema = schemaDeps.get(pname);
8181
if (schema != null) {
82-
schema.validate(executionContext, node, rootNode, instanceLocation);
82+
executionContext.getEvaluationPath().push(pname);
83+
try {
84+
schema.validate(executionContext, node, rootNode, instanceLocation);
85+
} finally {
86+
executionContext.getEvaluationPath().pop();
87+
}
8388
}
8489
}
8590
}

src/main/java/com/networknt/schema/keyword/DependentSchemas.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,10 @@
3131
public class DependentSchemas extends BaseKeywordValidator {
3232
private final Map<String, Schema> schemaDependencies = new HashMap<>();
3333

34-
public DependentSchemas(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) {
35-
34+
public DependentSchemas(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode,
35+
Schema parentSchema, SchemaContext schemaContext) {
3636
super(KeywordType.DEPENDENT_SCHEMAS, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath);
37-
38-
for (Iterator<String> it = schemaNode.fieldNames(); it.hasNext(); ) {
37+
for (Iterator<String> it = schemaNode.fieldNames(); it.hasNext();) {
3938
String pname = it.next();
4039
JsonNode pvalue = schemaNode.get(pname);
4140
if (pvalue.isObject() || pvalue.isBoolean()) {
@@ -57,10 +56,15 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo
5756
String pname = it.next();
5857
Schema schema = this.schemaDependencies.get(pname);
5958
if (schema != null) {
60-
if(!walk) {
61-
schema.validate(executionContext, node, rootNode, instanceLocation);
62-
} else {
63-
schema.walk(executionContext, node, rootNode, instanceLocation, true);
59+
executionContext.getEvaluationPath().push(pname);
60+
try {
61+
if(!walk) {
62+
schema.validate(executionContext, node, rootNode, instanceLocation);
63+
} else {
64+
schema.walk(executionContext, node, rootNode, instanceLocation, true);
65+
}
66+
} finally {
67+
executionContext.getEvaluationPath().pop();
6468
}
6569
}
6670
}

src/main/java/com/networknt/schema/keyword/IfValidator.java

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,6 @@ public IfValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonN
6666

6767
@Override
6868
public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) {
69-
70-
7169
boolean ifConditionPassed = false;
7270

7371
// Save flag as nested schema evaluation shouldn't trigger fail fast
@@ -77,7 +75,12 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode
7775
executionContext.setErrors(test);
7876
try {
7977
executionContext.setFailFast(false);
80-
this.ifSchema.validate(executionContext, node, rootNode, instanceLocation);
78+
executionContext.getEvaluationPath().push("if");
79+
try {
80+
this.ifSchema.validate(executionContext, node, rootNode, instanceLocation);
81+
} finally {
82+
executionContext.getEvaluationPath().pop();
83+
}
8184
ifConditionPassed = test.isEmpty();
8285
} finally {
8386
// Restore flag
@@ -86,9 +89,19 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode
8689
}
8790

8891
if (ifConditionPassed && this.thenSchema != null) {
89-
this.thenSchema.validate(executionContext, node, rootNode, instanceLocation);
92+
executionContext.getEvaluationPath().push("then");
93+
try {
94+
this.thenSchema.validate(executionContext, node, rootNode, instanceLocation);
95+
} finally {
96+
executionContext.getEvaluationPath().pop();
97+
}
9098
} else if (!ifConditionPassed && this.elseSchema != null) {
91-
this.elseSchema.validate(executionContext, node, rootNode, instanceLocation);
99+
executionContext.getEvaluationPath().push("else");
100+
try {
101+
this.elseSchema.validate(executionContext, node, rootNode, instanceLocation);
102+
} finally {
103+
executionContext.getEvaluationPath().pop();
104+
}
92105
}
93106
}
94107

@@ -117,7 +130,12 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root
117130
executionContext.setErrors(test);
118131
try {
119132
executionContext.setFailFast(false);
120-
this.ifSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);
133+
executionContext.getEvaluationPath().push("if");
134+
try {
135+
this.ifSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);
136+
} finally {
137+
executionContext.getEvaluationPath().pop();
138+
}
121139
ifConditionPassed = test.isEmpty();
122140
} finally {
123141
// Restore flag
@@ -126,17 +144,36 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root
126144
}
127145
if (!checkCondition) {
128146
if (this.thenSchema != null) {
129-
this.thenSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);
147+
executionContext.getEvaluationPath().push("then");
148+
try {
149+
this.thenSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);
150+
} finally {
151+
executionContext.getEvaluationPath().pop();
152+
}
130153
}
131154
if (this.elseSchema != null) {
132-
this.elseSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);
155+
executionContext.getEvaluationPath().push("else");
156+
try {
157+
this.elseSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);
158+
} finally {
159+
executionContext.getEvaluationPath().pop();
160+
}
133161
}
134162
} else {
135163
if (this.thenSchema != null && ifConditionPassed) {
136-
this.thenSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);
137-
}
138-
else if (this.elseSchema != null && !ifConditionPassed) {
139-
this.elseSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);
164+
executionContext.getEvaluationPath().push("then");
165+
try {
166+
this.thenSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);
167+
} finally {
168+
executionContext.getEvaluationPath().pop();
169+
}
170+
} else if (this.elseSchema != null && !ifConditionPassed) {
171+
executionContext.getEvaluationPath().push("else");
172+
try {
173+
this.elseSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema);
174+
} finally {
175+
executionContext.getEvaluationPath().pop();
176+
}
140177
}
141178
}
142179
}

src/main/java/com/networknt/schema/keyword/ItemsValidator.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,13 @@ private boolean doValidate(ExecutionContext executionContext, int i, JsonNode no
163163
} else if (this.tupleSchema != null) {
164164
if (i < this.tupleSchema.size()) {
165165
// validate against tuple schema
166-
this.tupleSchema.get(i).validate(executionContext, node, rootNode, path);
166+
executionContext.getEvaluationPath().push(i);
167+
try {
168+
this.tupleSchema.get(i).validate(executionContext, node, rootNode, path);
169+
} finally {
170+
executionContext.getEvaluationPath().pop();
171+
}
172+
167173
} else {
168174
if ((this.additionalItems != null && this.additionalItems) || this.additionalSchema != null) {
169175
isAdditionalItem = true;
@@ -265,11 +271,21 @@ else if (this.tupleSchema != null) {
265271
n = defaultNode;
266272
}
267273
}
268-
walkSchema(executionContext, this.tupleSchema.get(i), n, rootNode, instanceLocation.append(i),
269-
shouldValidateSchema, KeywordType.ITEMS.getValue());
274+
executionContext.getEvaluationPath().push(i);
275+
try {
276+
walkSchema(executionContext, this.tupleSchema.get(i), n, rootNode, instanceLocation.append(i),
277+
shouldValidateSchema, KeywordType.ITEMS.getValue());
278+
} finally {
279+
executionContext.getEvaluationPath().pop();
280+
}
270281
} else {
271-
walkSchema(executionContext, this.tupleSchema.get(i), null, rootNode, instanceLocation.append(i),
272-
shouldValidateSchema, KeywordType.ITEMS.getValue());
282+
executionContext.getEvaluationPath().push(i);
283+
try {
284+
walkSchema(executionContext, this.tupleSchema.get(i), null, rootNode,
285+
instanceLocation.append(i), shouldValidateSchema, KeywordType.ITEMS.getValue());
286+
} finally {
287+
executionContext.getEvaluationPath().pop();
288+
}
273289
}
274290
}
275291
if (this.additionalSchema != null) {

src/main/java/com/networknt/schema/keyword/OneOfValidator.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,22 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo
7575
executionContext.setErrors(subSchemaErrors);
7676
// Save flag as nested schema evaluation shouldn't trigger fail fast
7777
boolean failFast = executionContext.isFailFast();
78+
int schemaIndex = 0;
7879
try {
7980
executionContext.setFailFast(false);
8081
for (Schema schema : this.schemas) {
8182
subSchemaErrors.clear();
82-
if (!walk) {
83-
schema.validate(executionContext, node, rootNode, instanceLocation);
84-
} else {
85-
schema.walk(executionContext, node, rootNode, instanceLocation, true);
83+
executionContext.getEvaluationPath().push(schemaIndex);
84+
try {
85+
if (!walk) {
86+
schema.validate(executionContext, node, rootNode, instanceLocation);
87+
} else {
88+
schema.walk(executionContext, node, rootNode, instanceLocation, true);
89+
}
90+
} finally {
91+
executionContext.getEvaluationPath().pop();
8692
}
93+
schemaIndex++;
8794

8895
// check if any validation errors have occurred
8996
if (subSchemaErrors.isEmpty()) { // No new errors
@@ -233,8 +240,15 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root
233240
if (shouldValidateSchema && node != null) {
234241
validate(executionContext, node, rootNode, instanceLocation, true);
235242
} else {
243+
int schemaIndex = 0;
236244
for (Schema schema : this.schemas) {
237-
schema.walk(executionContext, node, rootNode, instanceLocation, false);
245+
executionContext.getEvaluationPath().push(schemaIndex);
246+
try {
247+
schema.walk(executionContext, node, rootNode, instanceLocation, false);
248+
} finally {
249+
executionContext.getEvaluationPath().pop();
250+
}
251+
schemaIndex++;
238252
}
239253
}
240254
}

0 commit comments

Comments
 (0)