Skip to content

Commit 0d1d8f2

Browse files
open-abbottJohn Abbott
andauthored
Add support for draft 2020-12 (#380) (#580)
Co-authored-by: John Abbott <[email protected]>
1 parent 640768b commit 0d1d8f2

File tree

11 files changed

+1792
-47
lines changed

11 files changed

+1792
-47
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ public static JsonSchemaFactory getInstance(SpecVersion.VersionFlag versionFlag)
251251
public static JsonSchemaVersion checkVersion(SpecVersion.VersionFlag versionFlag){
252252
JsonSchemaVersion jsonSchemaVersion = null;
253253
switch (versionFlag) {
254+
case V202012:
255+
jsonSchemaVersion = new Version202012();
256+
break;
254257
case V201909:
255258
jsonSchemaVersion = new Version201909();
256259
break;
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
* Copyright (c) 2022 Network New Technologies Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.networknt.schema;
18+
19+
import com.fasterxml.jackson.databind.JsonNode;
20+
import com.fasterxml.jackson.databind.node.ArrayNode;
21+
import com.networknt.schema.walk.DefaultItemWalkListenerRunner;
22+
import com.networknt.schema.walk.WalkListenerRunner;
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
26+
import java.util.ArrayList;
27+
import java.util.Collections;
28+
import java.util.HashSet;
29+
import java.util.LinkedHashSet;
30+
import java.util.List;
31+
import java.util.Set;
32+
33+
public class PrefixItemsValidator extends BaseJsonValidator implements JsonValidator {
34+
private static final Logger logger = LoggerFactory.getLogger(PrefixItemsValidator.class);
35+
private static final String PROPERTY_ITEMS = "items";
36+
37+
private final JsonSchema schema;
38+
private final List<JsonSchema> tupleSchema;
39+
private boolean additionalItems = true;
40+
private final JsonSchema additionalSchema;
41+
private WalkListenerRunner arrayItemWalkListenerRunner;
42+
43+
public PrefixItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema,
44+
ValidationContext validationContext) {
45+
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.ITEMS, validationContext);
46+
tupleSchema = new ArrayList<JsonSchema>();
47+
JsonSchema foundSchema = null;
48+
JsonSchema foundAdditionalSchema = null;
49+
50+
if (schemaNode.isObject() || schemaNode.isBoolean()) {
51+
foundSchema = new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), schemaNode,
52+
parentSchema);
53+
} else {
54+
for (JsonNode s : schemaNode) {
55+
tupleSchema.add(
56+
new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), s, parentSchema));
57+
}
58+
59+
JsonNode addItemNode = getParentSchema().getSchemaNode().get(PROPERTY_ITEMS);
60+
if (addItemNode != null) {
61+
if (addItemNode.isBoolean()) {
62+
additionalItems = addItemNode.asBoolean();
63+
} else if (addItemNode.isObject()) {
64+
foundAdditionalSchema = new JsonSchema(validationContext, "#", parentSchema.getCurrentUri(), addItemNode, parentSchema);
65+
}
66+
}
67+
}
68+
arrayItemWalkListenerRunner = new DefaultItemWalkListenerRunner(validationContext.getConfig().getArrayItemWalkListeners());
69+
70+
this.validationContext = validationContext;
71+
72+
parseErrorCode(getValidatorType().getErrorCodeKey());
73+
74+
this.schema = foundSchema;
75+
this.additionalSchema = foundAdditionalSchema;
76+
}
77+
78+
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
79+
debug(logger, node, rootNode, at);
80+
81+
Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
82+
83+
if (!node.isArray() && !this.validationContext.getConfig().isTypeLoose()) {
84+
// ignores non-arrays
85+
return errors;
86+
}
87+
if (node.isArray()) {
88+
int i = 0;
89+
for (JsonNode n : node) {
90+
doValidate(errors, i, n, rootNode, at);
91+
i++;
92+
}
93+
} else {
94+
doValidate(errors, 0, node, rootNode, at);
95+
}
96+
return Collections.unmodifiableSet(errors);
97+
}
98+
99+
private void doValidate(Set<ValidationMessage> errors, int i, JsonNode node, JsonNode rootNode, String at) {
100+
if (schema != null) {
101+
// validate with item schema (the whole array has the same item
102+
// schema)
103+
errors.addAll(schema.validate(node, rootNode, at + "[" + i + "]"));
104+
}
105+
106+
if (tupleSchema != null) {
107+
if (i < tupleSchema.size()) {
108+
// validate against tuple schema
109+
errors.addAll(tupleSchema.get(i).validate(node, rootNode, at + "[" + i + "]"));
110+
} else {
111+
if (additionalSchema != null) {
112+
// validate against additional item schema
113+
errors.addAll(additionalSchema.validate(node, rootNode, at + "[" + i + "]"));
114+
} else if (!additionalItems) {
115+
// no additional item allowed, return error
116+
errors.add(buildValidationMessage(at, "" + i));
117+
}
118+
}
119+
}
120+
}
121+
122+
@Override
123+
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
124+
HashSet<ValidationMessage> validationMessages = new LinkedHashSet<ValidationMessage>();
125+
if (node instanceof ArrayNode) {
126+
ArrayNode arrayNode = (ArrayNode) node;
127+
JsonNode defaultNode = null;
128+
if (applyDefaultsStrategy.shouldApplyArrayDefaults() && schema != null) {
129+
defaultNode = schema.getSchemaNode().get("default");
130+
}
131+
int i = 0;
132+
for (JsonNode n : arrayNode) {
133+
if (n.isNull() && defaultNode != null) {
134+
arrayNode.set(i, defaultNode);
135+
n = defaultNode;
136+
}
137+
doWalk(validationMessages, i, n, rootNode, at, shouldValidateSchema);
138+
i++;
139+
}
140+
} else {
141+
doWalk(validationMessages, 0, node, rootNode, at, shouldValidateSchema);
142+
}
143+
return validationMessages;
144+
}
145+
146+
private void doWalk(HashSet<ValidationMessage> validationMessages, int i, JsonNode node, JsonNode rootNode,
147+
String at, boolean shouldValidateSchema) {
148+
if (schema != null) {
149+
// Walk the schema.
150+
walkSchema(schema, node, rootNode, at + "[" + i + "]", shouldValidateSchema, validationMessages);
151+
}
152+
153+
if (tupleSchema != null) {
154+
if (i < tupleSchema.size()) {
155+
// walk tuple schema
156+
walkSchema(tupleSchema.get(i), node, rootNode, at + "[" + i + "]", shouldValidateSchema,
157+
validationMessages);
158+
} else {
159+
if (additionalSchema != null) {
160+
// walk additional item schema
161+
walkSchema(additionalSchema, node, rootNode, at + "[" + i + "]", shouldValidateSchema,
162+
validationMessages);
163+
}
164+
}
165+
}
166+
}
167+
168+
private void walkSchema(JsonSchema walkSchema, JsonNode node, JsonNode rootNode, String at,
169+
boolean shouldValidateSchema, Set<ValidationMessage> validationMessages) {
170+
boolean executeWalk = arrayItemWalkListenerRunner.runPreWalkListeners(ValidatorTypeCode.ITEMS.getValue(), node,
171+
rootNode, at, walkSchema.getSchemaPath(), walkSchema.getSchemaNode(), walkSchema.getParentSchema(),
172+
validationContext, validationContext.getJsonSchemaFactory());
173+
if (executeWalk) {
174+
validationMessages.addAll(walkSchema.walk(node, rootNode, at, shouldValidateSchema));
175+
}
176+
arrayItemWalkListenerRunner.runPostWalkListeners(ValidatorTypeCode.ITEMS.getValue(), node, rootNode, at,
177+
walkSchema.getSchemaPath(), walkSchema.getSchemaNode(), walkSchema.getParentSchema(),
178+
validationContext, validationContext.getJsonSchemaFactory(), validationMessages);
179+
180+
}
181+
182+
public List<JsonSchema> getTupleSchema() {
183+
return this.tupleSchema;
184+
}
185+
186+
public JsonSchema getSchema() {
187+
return schema;
188+
}
189+
190+
@Override
191+
public void preloadJsonSchema() {
192+
if (null != schema) {
193+
schema.initializeValidators();
194+
}
195+
preloadJsonSchemas(tupleSchema);
196+
if (null != additionalSchema) {
197+
additionalSchema.initializeValidators();
198+
}
199+
}
200+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ public enum VersionFlag {
2525
V4(1 << 0),
2626
V6(1 << 1),
2727
V7(1 << 2),
28-
V201909(1 << 3);
28+
V201909(1 << 3),
29+
V202012(1 << 4);
2930

3031

3132
private final long versionFlagValue;

0 commit comments

Comments
 (0)