Skip to content

Commit efbb37e

Browse files
fduttonFaron Dutton
andauthored
Adds support for walking dependentSchemas (#811)
Resolves #724 Co-authored-by: Faron Dutton <[email protected]>
1 parent ad3fa5c commit efbb37e

File tree

2 files changed

+106
-6
lines changed

2 files changed

+106
-6
lines changed

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222

2323
import java.util.*;
2424

25-
public class DependentSchemas extends BaseJsonValidator implements JsonValidator {
25+
public class DependentSchemas extends BaseJsonValidator {
2626
private static final Logger logger = LoggerFactory.getLogger(DependentSchemas.class);
27-
private final Map<String, JsonSchema> schemaDependencies = new HashMap<String, JsonSchema>();
27+
private final Map<String, JsonSchema> schemaDependencies = new HashMap<>();
2828

2929
public DependentSchemas(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
3030

@@ -34,21 +34,22 @@ public DependentSchemas(String schemaPath, JsonNode schemaNode, JsonSchema paren
3434
String pname = it.next();
3535
JsonNode pvalue = schemaNode.get(pname);
3636
if (pvalue.isObject() || pvalue.isBoolean()) {
37-
schemaDependencies.put(pname, validationContext.newSchema(pname, pvalue, parentSchema));
37+
this.schemaDependencies.put(pname, validationContext.newSchema(pname, pvalue, parentSchema));
3838
}
3939
}
4040

4141
parseErrorCode(getValidatorType().getErrorCodeKey());
4242
}
4343

44+
@Override
4445
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
4546
debug(logger, node, rootNode, at);
4647

47-
Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
48+
Set<ValidationMessage> errors = new LinkedHashSet<>();
4849

4950
for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) {
5051
String pname = it.next();
51-
JsonSchema schema = schemaDependencies.get(pname);
52+
JsonSchema schema = this.schemaDependencies.get(pname);
5253
if (schema != null) {
5354
errors.addAll(schema.validate(node, rootNode, at));
5455
}
@@ -59,6 +60,18 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
5960

6061
@Override
6162
public void preloadJsonSchema() {
62-
preloadJsonSchemas(schemaDependencies.values());
63+
preloadJsonSchemas(this.schemaDependencies.values());
6364
}
65+
66+
@Override
67+
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
68+
if (shouldValidateSchema) {
69+
return validate(node, rootNode, at);
70+
}
71+
for (JsonSchema schema : this.schemaDependencies.values()) {
72+
schema.walk(node, rootNode, at, false);
73+
}
74+
return Collections.emptySet();
75+
}
76+
6477
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.networknt.schema;
2+
3+
import static org.junit.jupiter.api.Assertions.assertLinesMatch;
4+
5+
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
import java.util.List;
8+
import java.util.Optional;
9+
import java.util.Set;
10+
11+
import org.junit.jupiter.api.Test;
12+
13+
import com.fasterxml.jackson.core.JsonProcessingException;
14+
import com.fasterxml.jackson.databind.JsonNode;
15+
import com.fasterxml.jackson.databind.ObjectMapper;
16+
import com.networknt.schema.SpecVersion.VersionFlag;
17+
import com.networknt.schema.walk.JsonSchemaWalkListener;
18+
import com.networknt.schema.walk.WalkEvent;
19+
import com.networknt.schema.walk.WalkFlow;
20+
21+
class Issue724Test {
22+
23+
@Test
24+
void test() throws JsonProcessingException {
25+
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
26+
StringCollector stringCollector = new StringCollector();
27+
config.addKeywordWalkListener(stringCollector);
28+
29+
String schema =
30+
"{\n"
31+
+ " \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n"
32+
+ " \"type\" : \"object\",\n"
33+
+ " \"properties\" : {\n"
34+
+ " \"credit_card\": {\n"
35+
+ " \"type\" : \"string\"\n"
36+
+ " }\n"
37+
+ " },\n"
38+
+ " \"dependentSchemas\": {\n"
39+
+ " \"credit_card\": {\n"
40+
+ " \"properties\": {\n"
41+
+ " \"billing_address\": {\n"
42+
+ " \"type\" : \"string\"\n"
43+
+ " }\n"
44+
+ " },\n"
45+
+ " \"required\": [\"billing_address\"]\n"
46+
+ " }\n"
47+
+ " }\n"
48+
+ "}\n";
49+
String data =
50+
"{\n"
51+
+ " \"credit_card\" : \"my_credit_card\",\n"
52+
+ " \"billing_address\" : \"my_billing_address\"\n"
53+
+ "}\n";
54+
55+
JsonSchema jsonSchema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schema, config);
56+
jsonSchema.walk(new ObjectMapper().readTree(data), /* shouldValidateSchema= */ false);
57+
58+
System.out.println(stringCollector.strings);
59+
assertLinesMatch(Arrays.asList("my_credit_card", "my_billing_address"), stringCollector.strings);
60+
}
61+
62+
static class StringCollector implements JsonSchemaWalkListener {
63+
final List<String> strings = new ArrayList<>();
64+
65+
@Override
66+
public WalkFlow onWalkStart(WalkEvent walkEvent) {
67+
boolean isString =
68+
Optional.of(walkEvent.getSchemaNode())
69+
.map(jsonNode -> jsonNode.get("type"))
70+
.map(JsonNode::asText)
71+
.map(type -> type.equals("string"))
72+
.orElse(false);
73+
74+
if (isString) {
75+
this.strings.add(walkEvent.getNode().asText());
76+
}
77+
78+
return WalkFlow.CONTINUE;
79+
}
80+
81+
@Override
82+
public void onWalkEnd(WalkEvent walkEvent, Set<ValidationMessage> validationMessages) {
83+
// nothing to do here
84+
}
85+
}
86+
87+
}

0 commit comments

Comments
 (0)