Skip to content

Commit f9f73fc

Browse files
Changes for walk methods
1 parent a4ffec1 commit f9f73fc

15 files changed

+283
-138
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<modelVersion>4.0.0</modelVersion>
2121
<groupId>com.networknt</groupId>
2222
<artifactId>json-schema-validator</artifactId>
23-
<version>1.0.43 </version>
23+
<version>1.0.47 </version>
2424
<packaging>bundle</packaging>
2525
<description>A json schema validator that supports draft v4, v6, v7 and v2019-09</description>
2626
<url>https://github.com/networknt/json-schema-validator</url>

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,43 @@ private void doValidate(Set<ValidationMessage> errors, int i, JsonNode node, Jso
100100
}
101101
}
102102
}
103+
104+
@Override
105+
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
106+
if (shouldValidateSchema) {
107+
return validate(node, rootNode, at);
108+
} else {
109+
HashSet<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();
110+
if (node.isArray()) {
111+
int i = 0;
112+
for (JsonNode n : node) {
113+
doWalk(i, n, rootNode, at);
114+
i++;
115+
}
116+
} else {
117+
doWalk(0, node, rootNode, at);
118+
}
119+
return validationMessages;
120+
}
121+
}
122+
123+
private void doWalk(int i, JsonNode node, JsonNode rootNode, String at) {
124+
if (schema != null) {
125+
// Walk the schema.
126+
schema.walk(node, rootNode, at + "[" + i + "]", false);
127+
}
128+
129+
if (tupleSchema != null) {
130+
if (i < tupleSchema.size()) {
131+
// walk tuple schema
132+
tupleSchema.get(i).walk(node, rootNode, at + "[" + i + "]", false);
133+
} else {
134+
if (additionalSchema != null) {
135+
// walk additional item schema
136+
additionalSchema.walk(node, rootNode, at + "[" + i + "]", false);
137+
}
138+
}
139+
}
140+
}
103141

104142
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@
3030
import java.util.regex.Pattern;
3131

3232
import com.fasterxml.jackson.databind.JsonNode;
33+
import com.networknt.schema.walk.DefaultKeywordWalkListenerRunner;
3334
import com.networknt.schema.walk.JsonWalker;
34-
import com.networknt.schema.walk.KeywordWalkListenerRunner;
35+
import com.networknt.schema.walk.WalkListenerRunner;
3536

3637
/**
3738
* This is the core of json constraint implementation. It parses json constraint
@@ -43,7 +44,7 @@ public class JsonSchema extends BaseJsonValidator {
4344
protected Map<String, JsonValidator> validators;
4445
private final String idKeyword;
4546
private final ValidationContext validationContext;
46-
private KeywordWalkListenerRunner keywordWalkListenerRunner;
47+
private WalkListenerRunner keywordWalkListenerRunner;
4748

4849
/**
4950
* This is the current uri of this schema. This uri could refer to the uri of this schema's file
@@ -79,7 +80,7 @@ private JsonSchema(ValidationContext validationContext, String schemaPath, URI c
7980
this.config = validationContext.getConfig();
8081
this.idKeyword = validationContext.getMetaSchema().getIdKeyword();
8182
this.currentUri = this.combineCurrentUriWithIds(currentUri, schemaNode);
82-
this.keywordWalkListenerRunner = new KeywordWalkListenerRunner(validationContext.getKeywordWalkListenersMap());
83+
this.keywordWalkListenerRunner = new DefaultKeywordWalkListenerRunner(validationContext.getKeywordWalkListenersMap());
8384
}
8485

8586
JsonSchema initialize() {

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

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
import com.networknt.schema.uri.URLFactory;
4343
import com.networknt.schema.uri.URLFetcher;
4444
import com.networknt.schema.urn.URNFactory;
45-
import com.networknt.schema.walk.KeywordWalkListener;
45+
import com.networknt.schema.walk.WalkListener;
4646

4747
public class JsonSchemaFactory {
4848
private static final Logger logger = LoggerFactory
@@ -59,7 +59,8 @@ public static class Builder {
5959
private URNFactory urnFactory;
6060
private final Map<String, JsonMetaSchema> jsonMetaSchemas = new HashMap<String, JsonMetaSchema>();
6161
private final Map<String, String> uriMap = new HashMap<String, String>();
62-
private final Map<String, List<KeywordWalkListener>> keywordWalkListenersMap = new HashMap<String, List<KeywordWalkListener>>();
62+
private final Map<String, List<WalkListener>> keywordWalkListenersMap = new HashMap<String, List<WalkListener>>();
63+
private final List<WalkListener> propertyWalkListeners = new ArrayList<WalkListener>();
6364

6465
public Builder() {
6566
// Adds support for creating {@link URL}s.
@@ -143,42 +144,52 @@ public Builder addUrnFactory(URNFactory urnFactory) {
143144
return this;
144145
}
145146

146-
public Builder addKeywordWalkListener(KeywordWalkListener keywordWalkListener) {
147+
public Builder addKeywordWalkListener(WalkListener keywordWalkListener) {
147148
if (keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY) == null) {
148-
List<KeywordWalkListener> keywordWalkListeners = new ArrayList<KeywordWalkListener>();
149+
List<WalkListener> keywordWalkListeners = new ArrayList<WalkListener>();
149150
keywordWalkListenersMap.put(ALL_KEYWORD_WALK_LISTENER_KEY, keywordWalkListeners);
150151
}
151152
keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY).add(keywordWalkListener);
152153
return this;
153154
}
154155

155-
public Builder addKeywordWalkListener(String keyword, KeywordWalkListener keywordWalkListener) {
156+
public Builder addKeywordWalkListener(String keyword, WalkListener keywordWalkListener) {
156157
if (keywordWalkListenersMap.get(keyword) == null) {
157-
List<KeywordWalkListener> keywordWalkListeners = new ArrayList<KeywordWalkListener>();
158+
List<WalkListener> keywordWalkListeners = new ArrayList<WalkListener>();
158159
keywordWalkListenersMap.put(keyword, keywordWalkListeners);
159160
}
160161
keywordWalkListenersMap.get(keyword).add(keywordWalkListener);
161162
return this;
162163
}
163164

164165

165-
public Builder addKeywordWalkListeners(List<KeywordWalkListener> keywordWalkListeners) {
166+
public Builder addKeywordWalkListeners(List<WalkListener> keywordWalkListeners) {
166167
if (keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY) == null) {
167-
List<KeywordWalkListener> ikeywordWalkListeners = new ArrayList<KeywordWalkListener>();
168+
List<WalkListener> ikeywordWalkListeners = new ArrayList<WalkListener>();
168169
keywordWalkListenersMap.put(ALL_KEYWORD_WALK_LISTENER_KEY, ikeywordWalkListeners);
169170
}
170171
keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY).addAll(keywordWalkListeners);
171172
return this;
172173
}
173174

174-
public Builder addKeywordWalkListeners(String keyword, List<KeywordWalkListener> keywordWalkListeners) {
175+
public Builder addKeywordWalkListeners(String keyword, List<WalkListener> keywordWalkListeners) {
175176
if (keywordWalkListenersMap.get(keyword) == null) {
176-
List<KeywordWalkListener> ikeywordWalkListeners = new ArrayList<KeywordWalkListener>();
177+
List<WalkListener> ikeywordWalkListeners = new ArrayList<WalkListener>();
177178
keywordWalkListenersMap.put(keyword, ikeywordWalkListeners);
178179
}
179180
keywordWalkListenersMap.get(keyword).addAll(keywordWalkListeners);
180181
return this;
181182
}
183+
184+
public Builder addPropertyWalkListeners(List<WalkListener> propertyWalkListeners) {
185+
this.propertyWalkListeners.addAll(propertyWalkListeners);
186+
return this;
187+
}
188+
189+
public Builder addPropertyWalkListener(WalkListener propertyWalkListener) {
190+
this.propertyWalkListeners.add(propertyWalkListener);
191+
return this;
192+
}
182193

183194
public JsonSchemaFactory build() {
184195
// create builtin keywords with (custom) formats.
@@ -190,7 +201,8 @@ public JsonSchemaFactory build() {
190201
urnFactory,
191202
jsonMetaSchemas,
192203
uriMap,
193-
keywordWalkListenersMap
204+
keywordWalkListenersMap,
205+
propertyWalkListeners
194206
);
195207
}
196208
}
@@ -203,7 +215,8 @@ public JsonSchemaFactory build() {
203215
private final Map<String, JsonMetaSchema> jsonMetaSchemas;
204216
private final Map<String, String> uriMap;
205217
private final ConcurrentMap<URI, JsonSchema> uriSchemaCache = new ConcurrentHashMap<URI, JsonSchema>();
206-
private final Map<String, List<KeywordWalkListener>> keywordWalkListenersMap;
218+
private final Map<String, List<WalkListener>> keywordWalkListenersMap;
219+
private final List<WalkListener> propertyWalkListeners;
207220

208221

209222
private JsonSchemaFactory(
@@ -214,7 +227,8 @@ private JsonSchemaFactory(
214227
final URNFactory urnFactory,
215228
final Map<String, JsonMetaSchema> jsonMetaSchemas,
216229
final Map<String, String> uriMap,
217-
final Map<String, List<KeywordWalkListener>> keywordWalkListenersMap) {
230+
final Map<String, List<WalkListener>> keywordWalkListenersMap,
231+
final List<WalkListener> propertyWalkListeners) {
218232
if (mapper == null) {
219233
throw new IllegalArgumentException("ObjectMapper must not be null");
220234
} else if (defaultMetaSchemaURI == null || defaultMetaSchemaURI.trim().isEmpty()) {
@@ -238,6 +252,7 @@ private JsonSchemaFactory(
238252
this.jsonMetaSchemas = jsonMetaSchemas;
239253
this.uriMap = uriMap;
240254
this.keywordWalkListenersMap = keywordWalkListenersMap;
255+
this.propertyWalkListeners = propertyWalkListeners;
241256
}
242257

243258
/**
@@ -311,7 +326,8 @@ protected JsonSchema newJsonSchema(final URI schemaUri, final JsonNode schemaNod
311326

312327
protected ValidationContext createValidationContext(final JsonNode schemaNode) {
313328
final JsonMetaSchema jsonMetaSchema = findMetaSchemaForSchema(schemaNode);
314-
return new ValidationContext(this.uriFactory, this.urnFactory, jsonMetaSchema, this, null, this.keywordWalkListenersMap);
329+
return new ValidationContext(this.uriFactory, this.urnFactory, jsonMetaSchema, this, null,
330+
this.keywordWalkListenersMap, this.propertyWalkListeners);
315331
}
316332

317333
private JsonMetaSchema findMetaSchemaForSchema(final JsonNode schemaNode) {
@@ -383,7 +399,10 @@ public JsonSchema getSchema(final URI schemaUri, final SchemaValidatorsConfig co
383399

384400
JsonSchema jsonSchema;
385401
if (idMatchesSourceUri(jsonMetaSchema, schemaNode, schemaUri)) {
386-
jsonSchema = new JsonSchema(new ValidationContext(this.uriFactory, this.urnFactory, jsonMetaSchema, this, config, this.keywordWalkListenersMap), mappedUri, schemaNode, true /*retrieved via id, resolving will not change anything*/);
402+
jsonSchema = new JsonSchema(
403+
new ValidationContext(this.uriFactory, this.urnFactory, jsonMetaSchema, this, config,
404+
this.keywordWalkListenersMap, this.propertyWalkListeners),
405+
mappedUri, schemaNode, true /* retrieved via id, resolving will not change anything */);
387406
} else {
388407
final ValidationContext validationContext = createValidationContext(schemaNode);
389408
validationContext.setConfig(config);

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
package com.networknt.schema;
1818

1919
import com.fasterxml.jackson.databind.JsonNode;
20+
import com.networknt.schema.walk.DefaultPropertyWalkListenerRunner;
21+
import com.networknt.schema.walk.WalkListenerRunner;
22+
2023
import org.slf4j.Logger;
2124
import org.slf4j.LoggerFactory;
2225

@@ -26,6 +29,7 @@ public class PropertiesValidator extends BaseJsonValidator implements JsonValida
2629
public static final String PROPERTY = "properties";
2730
private static final Logger logger = LoggerFactory.getLogger(PropertiesValidator.class);
2831
private Map<String, JsonSchema> schemas;
32+
private WalkListenerRunner propertyWalkListenerRunner;
2933

3034
public PropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
3135
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.PROPERTIES, validationContext);
@@ -35,6 +39,8 @@ public PropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSchema pa
3539
schemas.put(pname, new JsonSchema(validationContext, schemaPath + "/" + pname, parentSchema.getCurrentUri(), schemaNode.get(pname), parentSchema)
3640
.initialize());
3741
}
42+
propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(
43+
validationContext.getPropertyWalkListeners());
3844
}
3945

4046
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
@@ -100,14 +106,22 @@ public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at,
100106
if (shouldValidateSchema) {
101107
return validate(node, rootNode, at);
102108
} else {
109+
HashSet<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();
110+
boolean executeWalk = true;
103111
for (Map.Entry<String, JsonSchema> entry : schemas.entrySet()) {
104112
JsonSchema propertySchema = entry.getValue();
105113
JsonNode propertyNode = node.get(entry.getKey());
106-
if (propertyNode != null) {
114+
executeWalk = propertyWalkListenerRunner.runPreWalkListeners(ValidatorTypeCode.PROPERTIES.getValue(),
115+
propertyNode, rootNode, at + "." + entry.getKey(), propertySchema.getSchemaPath(),
116+
propertySchema.getSchemaNode(), propertySchema.getParentSchema());
117+
if (propertyNode != null && executeWalk) {
107118
propertySchema.walk(propertyNode, rootNode, at + "." + entry.getKey(), false);
108119
}
120+
propertyWalkListenerRunner.runPostWalkListeners(ValidatorTypeCode.PROPERTIES.getValue(), propertyNode,
121+
rootNode, at + "." + entry.getKey(), propertySchema.getSchemaPath(),
122+
propertySchema.getSchemaNode(), propertySchema.getParentSchema(), validationMessages);
109123
}
110-
return new LinkedHashSet<ValidationMessage>();
124+
return validationMessages;
111125
}
112126
}
113127

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import com.fasterxml.jackson.databind.JsonNode;
2424
import com.networknt.schema.uri.URIFactory;
2525
import com.networknt.schema.urn.URNFactory;
26-
import com.networknt.schema.walk.KeywordWalkListener;
26+
import com.networknt.schema.walk.WalkListener;
2727

2828
public class ValidationContext {
2929
private final URIFactory uriFactory;
@@ -32,11 +32,12 @@ public class ValidationContext {
3232
private final JsonSchemaFactory jsonSchemaFactory;
3333
private SchemaValidatorsConfig config;
3434
private final Map<String, JsonSchemaRef> refParsingInProgress = new HashMap<String, JsonSchemaRef>();
35-
private final Map<String, List<KeywordWalkListener>> keywordWalkListenersMap;
35+
private final Map<String, List<WalkListener>> keywordWalkListenersMap;
36+
private List<WalkListener> propertyWalkListeners;
3637

3738
public ValidationContext(URIFactory uriFactory, URNFactory urnFactory, JsonMetaSchema metaSchema,
3839
JsonSchemaFactory jsonSchemaFactory, SchemaValidatorsConfig config,
39-
Map<String, List<KeywordWalkListener>> keywordWalkListenersMap) {
40+
Map<String, List<WalkListener>> keywordWalkListenersMap, List<WalkListener> propertyWalkListeners) {
4041
if (uriFactory == null) {
4142
throw new IllegalArgumentException("URIFactory must not be null");
4243
}
@@ -52,6 +53,7 @@ public ValidationContext(URIFactory uriFactory, URNFactory urnFactory, JsonMetaS
5253
this.jsonSchemaFactory = jsonSchemaFactory;
5354
this.config = config;
5455
this.keywordWalkListenersMap = keywordWalkListenersMap;
56+
this.propertyWalkListeners = propertyWalkListeners;
5557
}
5658

5759
public JsonValidator newValidator(String schemaPath, String keyword /* keyword */, JsonNode schemaNode,
@@ -95,8 +97,12 @@ protected JsonMetaSchema getMetaSchema() {
9597
return metaSchema;
9698
}
9799

98-
public Map<String, List<KeywordWalkListener>> getKeywordWalkListenersMap() {
100+
public Map<String, List<WalkListener>> getKeywordWalkListenersMap() {
99101
return keywordWalkListenersMap;
100102
}
101103

104+
public List<WalkListener> getPropertyWalkListeners() {
105+
return propertyWalkListeners;
106+
}
107+
102108
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.networknt.schema.walk;
2+
3+
import java.util.List;
4+
import java.util.Set;
5+
6+
import com.fasterxml.jackson.databind.JsonNode;
7+
import com.networknt.schema.JsonSchema;
8+
import com.networknt.schema.ValidationMessage;
9+
10+
public abstract class AbstractWalkListenerRunner implements WalkListenerRunner {
11+
12+
protected String getKeywordName(String keyWordPath) {
13+
return keyWordPath.substring(keyWordPath.lastIndexOf('/') + 1);
14+
}
15+
16+
protected WalkEvent constructWalkEvent(String keyWordName, JsonNode node, JsonNode rootNode, String at,
17+
String schemaPath, JsonNode schemaNode, JsonSchema parentSchema) {
18+
return WalkEvent.builder().at(at).keyWordName(keyWordName).node(node).parentSchema(parentSchema)
19+
.rootNode(rootNode).schemaNode(schemaNode).schemaPath(schemaPath).build();
20+
}
21+
22+
protected boolean runPreWalkListeners(List<WalkListener> walkListeners, WalkEvent walkEvent) {
23+
boolean continueRunningListenersAndWalk = true;
24+
if (walkListeners != null) {
25+
for (WalkListener walkListener : walkListeners) {
26+
if (!walkListener.onWalkStart(walkEvent)) {
27+
continueRunningListenersAndWalk = false;
28+
break;
29+
}
30+
}
31+
}
32+
return continueRunningListenersAndWalk;
33+
}
34+
35+
protected void runPostWalkListeners(List<WalkListener> walkListeners, WalkEvent walkEvent,
36+
Set<ValidationMessage> validationMessages) {
37+
if (walkListeners != null) {
38+
for (WalkListener walkListener : walkListeners) {
39+
walkListener.onWalkEnd(walkEvent, validationMessages);
40+
}
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)