Skip to content

Commit c26d997

Browse files
committed
Fixes #185 Validation issue in oneOf when elements have optional fields
1 parent 0816c2d commit c26d997

File tree

5 files changed

+62
-38
lines changed

5 files changed

+62
-38
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ public abstract class BaseJsonValidator implements JsonValidator {
3636
*/
3737
protected SchemaValidatorsConfig config;
3838

39+
/**
40+
* ThreadLocal to allow to pass state in recursive validator calls
41+
*/
42+
protected final static ThreadLocal<ValidatorState> validatorState = new ThreadLocal<ValidatorState>();
3943

4044
public BaseJsonValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema,
4145
ValidatorTypeCode validatorType, ValidationContext validationContext) {

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
132132
debug(logger, node, rootNode, at);
133133

134134
// this is a complex validator, we set the flag to true
135-
config.setComplexValidator(true);
135+
ValidatorState state = new ValidatorState();
136+
state.setComplexValidator(true);
137+
validatorState.set(state);
136138

137139
int numberOfValidSchema = 0;
138140
Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
@@ -158,7 +160,7 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
158160
// check if any validation errors have occurred
159161
if (schemaErrors.isEmpty()) {
160162
// check whether there are no errors HOWEVER we have validated the exact validator
161-
if(!config.hasMatchedNode())
163+
if(!state.hasMatchedNode())
162164
continue;
163165

164166
numberOfValidSchema++;
@@ -190,6 +192,9 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
190192
errors = Collections.singleton(buildValidationMessage(at, ""));
191193
}
192194

195+
// reset the ValidatorState object in the ThreadLocal
196+
validatorState.remove();
197+
193198
return Collections.unmodifiableSet(errors);
194199
}
195200

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

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,32 +41,42 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
4141

4242
Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
4343

44+
// get the Validator state object storing validation data
45+
ValidatorState state = validatorState.get();
46+
if(state == null) {
47+
// if one has not been created, instantiate one
48+
state = new ValidatorState();
49+
validatorState.set(state);
50+
}
51+
4452
for (Map.Entry<String, JsonSchema> entry : schemas.entrySet()) {
4553
JsonSchema propertySchema = entry.getValue();
4654
JsonNode propertyNode = node.get(entry.getKey());
4755

4856
if (propertyNode != null) {
4957
// check whether this is a complex validator. save the state
50-
boolean isComplex = config.isComplexValidator();
58+
boolean isComplex = state.isComplexValidator();
5159
// if this is a complex validator, the node has matched, and all it's child elements, if available, are to be validated
52-
if(config.isComplexValidator()) {
53-
config.setMatchedNode(true);
60+
if(state.isComplexValidator()) {
61+
state.setMatchedNode(true);
5462
}
5563
// reset the complex validator for child element validation, and reset it after the return from the recursive call
56-
config.setComplexValidator(false);
64+
state.setComplexValidator(false);
65+
5766
//validate the child element(s)
5867
errors.addAll(propertySchema.validate(propertyNode, rootNode, at + "." + entry.getKey()));
68+
5969
// reset the complex flag to the original value before the recursive call
60-
config.setComplexValidator(isComplex);
70+
state.setComplexValidator(isComplex);
6171
// if this was a complex validator, the node has matched and has been validated
62-
if(config.isComplexValidator()) {
63-
config.setMatchedNode(true);
72+
if(state.isComplexValidator()) {
73+
state.setMatchedNode(true);
6474
}
6575
} else {
6676
// decide which behavior to eomploy when validator has not matched
67-
if(config.isComplexValidator()) {
77+
if(state.isComplexValidator()) {
6878
// this was a complex validator (ex oneOf) and the node has not been matched
69-
config.setMatchedNode(false);
79+
state.setMatchedNode(false);
7080
return Collections.unmodifiableSet(new LinkedHashSet<ValidationMessage>());
7181
}
7282

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

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,6 @@ public class SchemaValidatorsConfig {
2525
*/
2626
private boolean typeLoose;
2727

28-
/**
29-
* Flag set when a node has matched
30-
* Works in conjunction with the next flag: isComplexValidator, to be used for complex validators such as oneOf, for ex
31-
*/
32-
private boolean matchedNode = true;
33-
34-
/**
35-
* Flag set if complex validators such as oneOf, for ex, neeed to have their properties validated.
36-
* The PropertiesValidator is not aware generally of a complex validator is being validated or a simple poperty tree
37-
*/
38-
private boolean isComplexValidator = false;
39-
4028
/**
4129
* Map of public, normally internet accessible schema URLs to alternate locations; this allows for offline
4230
* validation of schemas that refer to public URLs. This is merged with any mappings the {@link JsonSchemaFactory}
@@ -87,19 +75,4 @@ private void loadDefaultConfig() {
8775
this.typeLoose = true;
8876
this.uriMappings = new HashMap<String, String>();
8977
}
90-
91-
public void setMatchedNode(boolean matchedNode) {
92-
this.matchedNode = matchedNode;
93-
}
94-
public boolean hasMatchedNode() {
95-
return matchedNode;
96-
}
97-
98-
public boolean isComplexValidator() {
99-
return isComplexValidator;
100-
}
101-
102-
public void setComplexValidator(boolean isComplexValidator) {
103-
this.isComplexValidator = isComplexValidator;
104-
}
10578
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.networknt.schema;
2+
3+
public class ValidatorState {
4+
/**
5+
* Flag set when a node has matched Works in conjunction with the next flag:
6+
* isComplexValidator, to be used for complex validators such as oneOf, for ex
7+
*/
8+
private boolean matchedNode = true;
9+
10+
/**
11+
* Flag set if complex validators such as oneOf, for ex, neeed to have their
12+
* properties validated. The PropertiesValidator is not aware generally of a
13+
* complex validator is being validated or a simple poperty tree
14+
*/
15+
private boolean isComplexValidator = false;
16+
17+
public void setMatchedNode(boolean matchedNode) {
18+
this.matchedNode = matchedNode;
19+
}
20+
public boolean hasMatchedNode() {
21+
return matchedNode;
22+
}
23+
24+
public boolean isComplexValidator() {
25+
return isComplexValidator;
26+
}
27+
28+
public void setComplexValidator(boolean isComplexValidator) {
29+
this.isComplexValidator = isComplexValidator;
30+
}
31+
32+
}

0 commit comments

Comments
 (0)