Skip to content

Commit cafa3ae

Browse files
committed
migrating ObjectSchema to the visitor model
1 parent 834c9fa commit cafa3ae

File tree

3 files changed

+233
-27
lines changed

3 files changed

+233
-27
lines changed

core/src/main/java/org/everit/json/schema/ObjectSchema.java

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ private Optional<ValidationException> ifFails(Schema schema, Object input) {
263263
}
264264

265265
@Override void accept(Visitor visitor) {
266-
throw new UnsupportedOperationException("not yet implemented");
266+
visitor.visitObjectSchema(this);
267267
}
268268

269269
private boolean matchesAnyPattern(String key) {
@@ -351,15 +351,6 @@ private void testPropertyDependencies(JSONObject subject, List<ValidationExcepti
351351
}
352352
}
353353

354-
private void testRequiredProperties(JSONObject subject, List<ValidationException> validationExceptions) {
355-
for (String required : requiredProperties) {
356-
if (!subject.has(required)) {
357-
validationExceptions.add(
358-
failure(format("required key [%s] not found", required), "required"));
359-
}
360-
}
361-
}
362-
363354
private void testSchemaDependencies(JSONObject subject, List<ValidationException> validationExceptions) {
364355
for (Map.Entry<String, Schema> schemaDep : schemaDependencies.entrySet()) {
365356
String propName = schemaDep.getKey();
@@ -386,23 +377,24 @@ private void testSize(JSONObject subject, List<ValidationException> validationEx
386377

387378
@Override
388379
public void validate(Object subject) {
389-
if (!(subject instanceof JSONObject)) {
390-
if (requiresObject) {
391-
throw failure(JSONObject.class, subject);
392-
}
393-
} else {
394-
List<ValidationException> validationExceptions = new ArrayList<>();
395-
JSONObject objSubject = (JSONObject) subject;
396-
testRequiredProperties(objSubject, validationExceptions);
397-
testProperties(objSubject, validationExceptions); // Test after requiredProperties because default values add properties
398-
testAdditionalProperties(objSubject, validationExceptions);
399-
testSize(objSubject, validationExceptions);
400-
testPropertyDependencies(objSubject, validationExceptions);
401-
testSchemaDependencies(objSubject, validationExceptions);
402-
testPatternProperties(objSubject, validationExceptions);
403-
testPropertyNames(objSubject, validationExceptions);
404-
ValidationException.throwFor(this, validationExceptions);
405-
}
380+
super.validate(subject);
381+
// if (!(subject instanceof JSONObject)) {
382+
// if (requiresObject) {
383+
// throw failure(JSONObject.class, subject);
384+
// }
385+
// } else {
386+
// List<ValidationException> validationExceptions = new ArrayList<>();
387+
// JSONObject objSubject = (JSONObject) subject;
388+
// testRequiredProperties(objSubject, validationExceptions);
389+
// testProperties(objSubject, validationExceptions); // Test after requiredProperties because default values add properties
390+
// testAdditionalProperties(objSubject, validationExceptions);
391+
// testSize(objSubject, validationExceptions);
392+
// testPropertyDependencies(objSubject, validationExceptions);
393+
// testSchemaDependencies(objSubject, validationExceptions);
394+
// testPatternProperties(objSubject, validationExceptions);
395+
// testPropertyNames(objSubject, validationExceptions);
396+
// ValidationException.throwFor(this, validationExceptions);
397+
// }
406398
}
407399

408400
private void testPropertyNames(JSONObject subject, List<ValidationException> validationExceptions) {
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package org.everit.json.schema;
2+
3+
import static java.lang.String.format;
4+
import static java.util.Objects.requireNonNull;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
import java.util.Set;
9+
import java.util.regex.Pattern;
10+
11+
import org.json.JSONObject;
12+
13+
public class ObjectSchemaValidatingVisitor extends Visitor {
14+
15+
private final Object subject;
16+
17+
private JSONObject objSubject;
18+
19+
private ObjectSchema schema;
20+
21+
private int objectSize;
22+
23+
private final ValidatingVisitor owner;
24+
25+
public ObjectSchemaValidatingVisitor(Object subject, ValidatingVisitor owner) {
26+
this.subject = requireNonNull(subject, "subject cannot be null");
27+
this.owner = requireNonNull(owner, "owner cannot be null");
28+
}
29+
30+
@Override void visitObjectSchema(ObjectSchema objectSchema) {
31+
if (!(subject instanceof JSONObject)) {
32+
if (objectSchema.requiresObject()) {
33+
owner.failure(JSONObject.class, subject);
34+
}
35+
} else {
36+
objSubject = (JSONObject) subject;
37+
objectSize = objSubject.length();
38+
this.schema = objectSchema;
39+
super.visitObjectSchema(objectSchema);
40+
}
41+
}
42+
43+
@Override void visitRequiredPropertyName(String requiredPropName) {
44+
if (!objSubject.has(requiredPropName)) {
45+
owner.failure(format("required key [%s] not found", requiredPropName), "required");
46+
}
47+
}
48+
49+
@Override void visitPropertyNameSchema(Schema propertyNameSchema) {
50+
if (propertyNameSchema != null) {
51+
String[] names = JSONObject.getNames(objSubject);
52+
if (names == null || names.length == 0) {
53+
return;
54+
}
55+
for (String name : names) {
56+
ValidationException failure = owner.getFailureOfSchema(propertyNameSchema, name);
57+
if (failure != null) {
58+
owner.failure(failure.prepend(name));
59+
}
60+
}
61+
}
62+
}
63+
64+
@Override void visitMinProperties(Integer minProperties) {
65+
if (minProperties != null && objectSize < minProperties.intValue()) {
66+
owner.failure(format("minimum size: [%d], found: [%d]", minProperties, objectSize), "minProperties");
67+
}
68+
}
69+
70+
@Override void visitMaxProperties(Integer maxProperties) {
71+
if (maxProperties != null && objectSize > maxProperties.intValue()) {
72+
owner.failure(format("maximum size: [%d], found: [%d]", maxProperties, objectSize), "maxProperties");
73+
}
74+
}
75+
76+
@Override void visitPropertyDependencies(String ifPresent, Set<String> allMustBePresent) {
77+
if (objSubject.has(ifPresent)) {
78+
for (String mustBePresent : allMustBePresent) {
79+
if (!objSubject.has(mustBePresent)) {
80+
owner.failure(format("property [%s] is required", mustBePresent), "dependencies");
81+
}
82+
}
83+
}
84+
}
85+
86+
@Override void visitAdditionalProperties(boolean permitsAdditionalProperties) {
87+
if (!permitsAdditionalProperties) {
88+
List<String> additionalProperties = getAdditionalProperties();
89+
if (null == additionalProperties || additionalProperties.isEmpty()) {
90+
return;
91+
}
92+
for (String additionalProperty : additionalProperties) {
93+
owner.failure(format("extraneous key [%s] is not permitted", additionalProperty), "additionalProperties");
94+
}
95+
}
96+
}
97+
98+
@Override void visitSchemaOfAdditionalProperties(Schema schemaOfAdditionalProperties) {
99+
if (schemaOfAdditionalProperties != null) {
100+
List<String> additionalPropNames = getAdditionalProperties();
101+
for (String propName : additionalPropNames) {
102+
Object propVal = objSubject.get(propName);
103+
ValidationException failure = owner.getFailureOfSchema(schemaOfAdditionalProperties, propVal);
104+
if (failure != null) {
105+
owner.failure(failure.prepend(propName, schema));
106+
}
107+
}
108+
}
109+
}
110+
111+
private List<String> getAdditionalProperties() {
112+
String[] names = JSONObject.getNames(objSubject);
113+
if (names == null) {
114+
return new ArrayList<>();
115+
} else {
116+
List<String> namesList = new ArrayList<>();
117+
for (String name : names) {
118+
if (!schema.getPropertySchemas().containsKey(name) && !matchesAnyPattern(name)) {
119+
namesList.add(name);
120+
}
121+
}
122+
return namesList;
123+
}
124+
}
125+
126+
private boolean matchesAnyPattern(String key) {
127+
for (Pattern pattern : schema.getPatternProperties().keySet()) {
128+
if (pattern.matcher(key).find()) {
129+
return true;
130+
}
131+
}
132+
return false;
133+
}
134+
135+
@Override void visitPatternPropertySchema(Pattern propertyNamePattern, Schema schema) {
136+
String[] propNames = JSONObject.getNames(objSubject);
137+
if (propNames == null || propNames.length == 0) {
138+
return;
139+
}
140+
for (String propName : propNames) {
141+
if (propertyNamePattern.matcher(propName).find()) {
142+
ValidationException failure = owner.getFailureOfSchema(schema, objSubject.get(propName));
143+
if (failure != null) {
144+
owner.failure(failure.prepend(propName));
145+
}
146+
}
147+
}
148+
}
149+
150+
@Override void visitSchemaDependency(String propName, Schema schema) {
151+
if (objSubject.has(propName)) {
152+
ValidationException failure = owner.getFailureOfSchema(schema, objSubject);
153+
if (failure != null) {
154+
owner.failure(failure);
155+
}
156+
}
157+
}
158+
159+
@Override void visitPropertySchema(String properyName, Schema schema) {
160+
if (objSubject.has(properyName)) {
161+
ValidationException failure = owner.getFailureOfSchema(schema, objSubject.get(properyName));
162+
if (failure != null) {
163+
owner.failure(failure.prepend(properyName));
164+
}
165+
} else if (schema.hasDefaultValue()) {
166+
objSubject.put(properyName, schema.getDefaultValue());
167+
}
168+
}
169+
}

core/src/main/java/org/everit/json/schema/Visitor.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.everit.json.schema;
22

33
import java.util.List;
4+
import java.util.Map;
5+
import java.util.Set;
46
import java.util.regex.Pattern;
57

68
abstract class Visitor {
@@ -109,6 +111,49 @@ void visitObjectSchema(ObjectSchema objectSchema) {
109111
visitRequiredPropertyName(requiredPropName);
110112
}
111113
visitPropertyNameSchema(objectSchema.getPropertyNameSchema());
114+
visitMinProperties(objectSchema.getMinProperties());
115+
visitMaxProperties(objectSchema.getMaxProperties());
116+
for (Map.Entry<String, Set<String>> entry : objectSchema.getPropertyDependencies().entrySet()) {
117+
visitPropertyDependencies(entry.getKey(), entry.getValue());
118+
}
119+
visitAdditionalProperties(objectSchema.permitsAdditionalProperties());
120+
visitSchemaOfAdditionalProperties(objectSchema.getSchemaOfAdditionalProperties());
121+
for (Map.Entry<Pattern, Schema> entry : objectSchema.getPatternProperties().entrySet()) {
122+
visitPatternPropertySchema(entry.getKey(), entry.getValue());
123+
}
124+
for (Map.Entry<String, Schema> schemaDep : objectSchema.getSchemaDependencies().entrySet()) {
125+
visitSchemaDependency(schemaDep.getKey(), schemaDep.getValue());
126+
}
127+
Map<String, Schema> propertySchemas = objectSchema.getPropertySchemas();
128+
if (propertySchemas != null) {
129+
for (Map.Entry<String, Schema> entry : propertySchemas.entrySet()) {
130+
visitPropertySchema(entry.getKey(), entry.getValue());
131+
}
132+
}
133+
}
134+
135+
void visitPropertySchema(String properyName, Schema schema) {
136+
}
137+
138+
void visitSchemaDependency(String propKey, Schema schema) {
139+
}
140+
141+
void visitPatternPropertySchema(Pattern propertyNamePattern, Schema schema) {
142+
}
143+
144+
void visitSchemaOfAdditionalProperties(Schema schemaOfAdditionalProperties) {
145+
}
146+
147+
void visitAdditionalProperties(boolean additionalProperties) {
148+
}
149+
150+
void visitPropertyDependencies(String ifPresent, Set<String> allMustBePresent) {
151+
}
152+
153+
void visitMaxProperties(Integer maxProperties) {
154+
}
155+
156+
void visitMinProperties(Integer minProperties) {
112157
}
113158

114159
void visitPropertyNameSchema(Schema propertyNameSchema) {

0 commit comments

Comments
 (0)