Skip to content

Commit d4500ca

Browse files
authored
Merge pull request #45 from v1ctor/has-field
44: Add possibility to check if field exists in schema
2 parents 3bb3f05 + 751e367 commit d4500ca

File tree

10 files changed

+220
-4
lines changed

10 files changed

+220
-4
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.everit.json.schema;
1717

18+
import org.json.JSONArray;
19+
1820
import java.util.ArrayList;
1921
import java.util.Collection;
2022
import java.util.List;
@@ -24,8 +26,6 @@
2426
import java.util.function.IntFunction;
2527
import java.util.stream.IntStream;
2628

27-
import org.json.JSONArray;
28-
2929
/**
3030
* Array schema validator.
3131
*/

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,4 +178,17 @@ public void validate(final Object subject) {
178178
e.getKeyword());
179179
}
180180
}
181+
182+
@Override
183+
public boolean definesProperty(String field) {
184+
List<Schema> matching = subschemas.stream()
185+
.filter(schema -> schema.definesProperty(field))
186+
.collect(Collectors.toList());
187+
try {
188+
criterion.validate(subschemas.size(), matching.size());
189+
} catch (ValidationException e) {
190+
return false;
191+
}
192+
return true;
193+
}
181194
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,5 @@ public void validate(final Object subject) {
6161
}
6262
throw new ValidationException(this, "subject must not be valid agains schema " + mustNotMatch);
6363
}
64+
6465
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,5 @@ public void validate(final Object subject) {
5050
+ subject.getClass().getSimpleName());
5151
}
5252
}
53+
5354
}

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

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
*/
1616
package org.everit.json.schema;
1717

18+
import com.google.common.base.Splitter;
19+
import com.google.common.collect.Lists;
20+
import org.json.JSONObject;
21+
1822
import java.util.ArrayList;
1923
import java.util.Arrays;
2024
import java.util.Collections;
@@ -30,8 +34,6 @@
3034
import java.util.stream.Collectors;
3135
import java.util.stream.Stream;
3236

33-
import org.json.JSONObject;
34-
3537
/**
3638
* Object schema validator.
3739
*/
@@ -392,4 +394,42 @@ public void validate(final Object subject) {
392394
}
393395
}
394396

397+
@Override
398+
public boolean definesProperty(String field) {
399+
field = field.replaceFirst("^#", "").replaceFirst("^/", "");
400+
return !field.isEmpty() && (definesPatternProperty(field)
401+
|| definesSchemaDependencyProperty(field)
402+
|| definesSchemaProperty(field));
403+
}
404+
405+
private boolean definesSchemaProperty(String field) {
406+
List<String> fields = Lists.newArrayList(Splitter.on("/").limit(2).split(field));
407+
String current = unescape(fields.get(0));
408+
boolean hasSuffix = fields.size() > 1;
409+
if (propertySchemas.containsKey(current)) {
410+
if (hasSuffix) {
411+
String suffix = fields.get(1);
412+
return propertySchemas.get(current).definesProperty(suffix);
413+
} else {
414+
return true;
415+
}
416+
}
417+
return false;
418+
}
419+
420+
private boolean definesPatternProperty(String field) {
421+
return patternProperties.keySet().stream().filter(pattern -> pattern.matcher(field).matches())
422+
.findAny().isPresent();
423+
}
424+
425+
private boolean definesSchemaDependencyProperty(String field) {
426+
return schemaDependencies.containsKey(field)
427+
|| schemaDependencies.values().stream().filter(schema -> schema.definesProperty(field))
428+
.findAny().isPresent();
429+
}
430+
431+
private String unescape(String value) {
432+
return value.replace("~1", "/").replace("~0", "~");
433+
}
434+
395435
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ public void validate(final Object subject) {
6161
referredSchema.validate(subject);
6262
}
6363

64+
@Override
65+
public boolean definesProperty(String field) {
66+
if (referredSchema == null) {
67+
throw new IllegalStateException("referredSchema must be injected before validation");
68+
}
69+
return referredSchema.definesProperty(field);
70+
}
71+
6472
public Schema getReferredSchema() {
6573
return referredSchema;
6674
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ protected Schema(final Builder<?> builder) {
8585
*/
8686
public abstract void validate(final Object subject);
8787

88+
public boolean definesProperty(final String field) {
89+
return false;
90+
}
91+
8892
@Override
8993
public int hashCode() {
9094
final int prime = 31;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,5 @@ public void validate(final Object subject) {
173173
ValidationException.throwFor(this, rval);
174174
}
175175
}
176+
176177
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (C) 2011 Everit Kft. (http://www.everit.org)
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+
package org.everit.json.schema.loader;
17+
18+
import org.everit.json.schema.ObjectSchema;
19+
import org.everit.json.schema.Schema;
20+
import org.json.JSONObject;
21+
import org.json.JSONTokener;
22+
import org.junit.Assert;
23+
import org.junit.BeforeClass;
24+
import org.junit.Test;
25+
26+
import java.io.InputStream;
27+
28+
public class DefinesPropertyTest {
29+
30+
private static JSONObject ALL_SCHEMAS;
31+
32+
@BeforeClass
33+
public static void before() {
34+
InputStream stream = DefinesPropertyTest.class.getResourceAsStream(
35+
"/org/everit/jsonvalidator/testschemas.json");
36+
ALL_SCHEMAS = new JSONObject(new JSONTokener(stream));
37+
}
38+
39+
private JSONObject get(final String schemaName) {
40+
return ALL_SCHEMAS.getJSONObject(schemaName);
41+
}
42+
43+
@Test
44+
public void objectSchemaHasField() {
45+
ObjectSchema actual = (ObjectSchema) SchemaLoader.load(get("pointerResolution"));
46+
Assert.assertTrue(actual.definesProperty("#/rectangle"));
47+
Assert.assertTrue(actual.definesProperty("#/rectangle/a"));
48+
Assert.assertTrue(actual.definesProperty("#/rectangle/b"));
49+
50+
Assert.assertFalse(actual.definesProperty("#/rectangle/c"));
51+
Assert.assertFalse(actual.definesProperty("#/rectangle/"));
52+
Assert.assertFalse(actual.definesProperty("#/"));
53+
Assert.assertFalse(actual.definesProperty("#/a"));
54+
Assert.assertFalse(actual.definesProperty("#"));
55+
Assert.assertFalse(actual.definesProperty("#/rectangle/a/d"));
56+
}
57+
58+
@Test
59+
public void recursiveSchemaHasField() {
60+
Schema recursiveSchema = SchemaLoader.load(get("recursiveSchema"));
61+
62+
Assert.assertTrue(recursiveSchema.definesProperty("#/prop"));
63+
Assert.assertTrue(recursiveSchema.definesProperty("#/prop/subprop"));
64+
Assert.assertTrue(recursiveSchema.definesProperty("#/prop/subprop/subprop"));
65+
Assert.assertTrue(recursiveSchema.definesProperty("#/prop/subprop/subprop/subprop"));
66+
}
67+
68+
@Test
69+
public void patternPropertiesHasField() {
70+
ObjectSchema actual = (ObjectSchema) SchemaLoader.load(get("patternProperties"));
71+
Assert.assertTrue(actual.definesProperty("#/a"));
72+
Assert.assertTrue(actual.definesProperty("#/aa"));
73+
Assert.assertTrue(actual.definesProperty("#/aaa"));
74+
Assert.assertTrue(actual.definesProperty("#/aaaa"));
75+
Assert.assertTrue(actual.definesProperty("#/aaaaa"));
76+
77+
Assert.assertFalse(actual.definesProperty("b"));
78+
}
79+
80+
@Test
81+
public void objectWithSchemaDep() {
82+
ObjectSchema actual = (ObjectSchema) SchemaLoader.load(get("objectWithSchemaDep"));
83+
Assert.assertTrue(actual.definesProperty("#/a"));
84+
Assert.assertTrue(actual.definesProperty("#/b"));
85+
86+
Assert.assertFalse(actual.definesProperty("#/c"));
87+
}
88+
89+
@Test
90+
public void objectWithSchemaRectangleDep() {
91+
ObjectSchema actual = (ObjectSchema) SchemaLoader.load(get("objectWithSchemaRectangleDep"));
92+
Assert.assertTrue(actual.definesProperty("#/d"));
93+
Assert.assertTrue(actual.definesProperty("#/rectangle/a"));
94+
Assert.assertTrue(actual.definesProperty("#/rectangle/b"));
95+
96+
Assert.assertFalse(actual.definesProperty("#/c"));
97+
Assert.assertFalse(actual.definesProperty("#/d/c"));
98+
Assert.assertFalse(actual.definesProperty("#/rectangle/c"));
99+
}
100+
101+
@Test
102+
public void objectEscape() {
103+
ObjectSchema actual = (ObjectSchema) SchemaLoader.load(get("objectEscape"));
104+
Assert.assertTrue(actual.definesProperty("#/a~0b"));
105+
Assert.assertTrue(actual.definesProperty("#/a~0b/c~1d"));
106+
107+
Assert.assertFalse(actual.definesProperty("#/a~0b/c/d"));
108+
}
109+
110+
}

core/src/test/resources/org/everit/jsonvalidator/testschemas.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,30 @@
113113
}
114114
}
115115
},
116+
"objectWithSchemaRectangleDep" : {
117+
"type" : "object",
118+
"dependencies" : {
119+
"d" : {
120+
"type" : "object",
121+
"properties" : {
122+
"rectangle" : {"$ref" : "#/definitions/Rectangle" }
123+
}
124+
}
125+
},
126+
"definitions" : {
127+
"size" : {
128+
"type" : "number",
129+
"minimum" : 0
130+
},
131+
"Rectangle" : {
132+
"type" : "object",
133+
"properties" : {
134+
"a" : {"$ref" : "#/definitions/size"},
135+
"b" : {"$ref" : "#/definitions/size"}
136+
}
137+
}
138+
}
139+
},
116140
"invalidDependency" : {
117141
"type" : "object",
118142
"dependencies" : {
@@ -147,6 +171,20 @@
147171
}
148172
}
149173
},
174+
"objectEscape" : {
175+
"type" : "object",
176+
"properties" : {
177+
"a~b" : {"$ref" : "#/definitions/Prop" }
178+
},
179+
"definitions" : {
180+
"Prop" : {
181+
"type" : "object",
182+
"properties" : {
183+
"c/d" : {"type" : "string"}
184+
}
185+
}
186+
}
187+
},
150188
"pointerResolutionFailure" : {
151189
"type" : "object",
152190
"properties" : {

0 commit comments

Comments
 (0)