Skip to content

Commit a47d276

Browse files
committed
initial bugfix - weird stackoverflow
1 parent e63cdaf commit a47d276

File tree

8 files changed

+194
-48
lines changed

8 files changed

+194
-48
lines changed

core/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
</parent>
2727
<groupId>org.everit.json</groupId>
2828
<artifactId>org.everit.json.schema</artifactId>
29-
<version>1.1.1</version>
29+
<version>1.1.2-SNAPSHOT</version>
3030
<packaging>bundle</packaging>
3131
<properties>
3232
<projectpath>json-schema-validator</projectpath>

core/src/main/java/org/everit/json/schema/loader/SchemaLoader.java

Lines changed: 63 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public class SchemaLoader {
6161
*/
6262
@FunctionalInterface
6363
private interface CombinedSchemaProvider
64-
extends Function<Collection<Schema>, CombinedSchema.Builder> {
64+
extends Function<Collection<Schema>, CombinedSchema.Builder> {
6565

6666
}
6767

@@ -115,7 +115,7 @@ public static Schema load(final JSONObject schemaJson) {
115115
public static Schema load(final JSONObject schemaJson, final SchemaClient httpClient) {
116116
String schemaId = schemaJson.optString("id");
117117
return new SchemaLoader(schemaId, schemaJson, schemaJson, new HashMap<>(), httpClient)
118-
.load().build();
118+
.load().build();
119119
}
120120

121121
private final SchemaClient httpClient;
@@ -143,29 +143,29 @@ public static Schema load(final JSONObject schemaJson, final SchemaClient httpCl
143143

144144
private void addDependencies(final Builder builder, final JSONObject deps) {
145145
Arrays.stream(JSONObject.getNames(deps))
146-
.forEach(ifPresent -> addDependency(builder, ifPresent, deps.get(ifPresent)));
146+
.forEach(ifPresent -> addDependency(builder, ifPresent, deps.get(ifPresent)));
147147
}
148148

149149
private void addDependency(final Builder builder, final String ifPresent, final Object deps) {
150150
typeMultiplexer(deps)
151-
.ifObject().then(obj -> {
152-
builder.schemaDependency(ifPresent, loadChild(obj).build());
153-
})
154-
.ifIs(JSONArray.class).then(propNames -> {
155-
IntStream.range(0, propNames.length())
156-
.mapToObj(i -> propNames.getString(i))
157-
.forEach(dependency -> builder.propertyDependency(ifPresent, dependency));
158-
}).requireAny();
151+
.ifObject().then(obj -> {
152+
builder.schemaDependency(ifPresent, loadChild(obj).build());
153+
})
154+
.ifIs(JSONArray.class).then(propNames -> {
155+
IntStream.range(0, propNames.length())
156+
.mapToObj(i -> propNames.getString(i))
157+
.forEach(dependency -> builder.propertyDependency(ifPresent, dependency));
158+
}).requireAny();
159159
}
160160

161161
private void addPropertySchemaDefinition(final String keyOfObj, final Object definition,
162162
final ObjectSchema.Builder builder) {
163163
typeMultiplexer(definition)
164-
.ifObject()
165-
.then(obj -> {
166-
builder.addPropertySchema(keyOfObj, loadChild(obj).build());
167-
})
168-
.requireAny();
164+
.ifObject()
165+
.then(obj -> {
166+
builder.addPropertySchema(keyOfObj, loadChild(obj).build());
167+
})
168+
.requireAny();
169169
}
170170

171171
private CombinedSchema.Builder buildAnyOfSchemaForMultipleTypes() {
@@ -188,15 +188,15 @@ private ArraySchema.Builder buildArraySchema() {
188188
ifPresent("uniqueItems", Boolean.class, builder::uniqueItems);
189189
if (schemaJson.has("additionalItems")) {
190190
typeMultiplexer("additionalItems", schemaJson.get("additionalItems"))
191-
.ifIs(Boolean.class).then(builder::additionalItems)
192-
.ifObject().then(jsonObj -> builder.schemaOfAdditionalItems(loadChild(jsonObj).build()))
193-
.requireAny();
191+
.ifIs(Boolean.class).then(builder::additionalItems)
192+
.ifObject().then(jsonObj -> builder.schemaOfAdditionalItems(loadChild(jsonObj).build()))
193+
.requireAny();
194194
}
195195
if (schemaJson.has("items")) {
196196
typeMultiplexer("items", schemaJson.get("items"))
197-
.ifObject().then(itemSchema -> builder.allItemSchema(loadChild(itemSchema).build()))
198-
.ifIs(JSONArray.class).then(arr -> buildTupleSchema(builder, arr))
199-
.requireAny();
197+
.ifObject().then(itemSchema -> builder.allItemSchema(loadChild(itemSchema).build()))
198+
.ifIs(JSONArray.class).then(arr -> buildTupleSchema(builder, arr))
199+
.requireAny();
200200
}
201201
return builder;
202202
}
@@ -205,8 +205,8 @@ private EnumSchema.Builder buildEnumSchema() {
205205
Set<Object> possibleValues = new HashSet<>();
206206
JSONArray arr = schemaJson.getJSONArray("enum");
207207
IntStream.range(0, arr.length())
208-
.mapToObj(arr::get)
209-
.forEach(possibleValues::add);
208+
.mapToObj(arr::get)
209+
.forEach(possibleValues::add);
210210
return EnumSchema.builder().possibleValues(possibleValues);
211211
}
212212

@@ -231,21 +231,21 @@ private ObjectSchema.Builder buildObjectSchema() {
231231
ifPresent("maxProperties", Integer.class, builder::maxProperties);
232232
if (schemaJson.has("properties")) {
233233
typeMultiplexer(schemaJson.get("properties"))
234-
.ifObject().then(propertyDefs -> {
235-
populatePropertySchemas(propertyDefs, builder);
236-
}).requireAny();
234+
.ifObject().then(propertyDefs -> {
235+
populatePropertySchemas(propertyDefs, builder);
236+
}).requireAny();
237237
}
238238
if (schemaJson.has("additionalProperties")) {
239239
typeMultiplexer("additionalProperties", schemaJson.get("additionalProperties"))
240-
.ifIs(Boolean.class).then(builder::additionalProperties)
241-
.ifObject().then(def -> builder.schemaOfAdditionalProperties(loadChild(def).build()))
242-
.requireAny();
240+
.ifIs(Boolean.class).then(builder::additionalProperties)
241+
.ifObject().then(def -> builder.schemaOfAdditionalProperties(loadChild(def).build()))
242+
.requireAny();
243243
}
244244
if (schemaJson.has("required")) {
245245
JSONArray requiredJson = schemaJson.getJSONArray("required");
246246
IntStream.range(0, requiredJson.length())
247-
.mapToObj(requiredJson::getString)
248-
.forEach(builder::addRequiredProperty);
247+
.mapToObj(requiredJson::getString)
248+
.forEach(builder::addRequiredProperty);
249249
}
250250
if (schemaJson.has("patternProperties")) {
251251
JSONObject patternPropsJson = schemaJson.getJSONObject("patternProperties");
@@ -266,7 +266,7 @@ private Schema.Builder<?> buildSchemaWithoutExplicitType() {
266266
return EmptySchema.builder();
267267
}
268268
if (schemaJson.has("$ref")) {
269-
return lookupReference(schemaJson.getString("$ref"));
269+
return lookupReference(schemaJson.getString("$ref"), schemaJson);
270270
}
271271
Schema.Builder<?> rval = sniffSchemaByProps();
272272
if (rval != null) {
@@ -289,11 +289,28 @@ private StringSchema.Builder buildStringSchema() {
289289
private void buildTupleSchema(final ArraySchema.Builder builder, final JSONArray itemSchema) {
290290
for (int i = 0; i < itemSchema.length(); ++i) {
291291
typeMultiplexer(itemSchema.get(i))
292-
.ifObject().then(schema -> builder.addItemSchema(loadChild(schema).build()))
293-
.requireAny();
292+
.ifObject().then(schema -> builder.addItemSchema(loadChild(schema).build()))
293+
.requireAny();
294294
}
295295
}
296296

297+
JSONObject extend(final JSONObject additional, final JSONObject original) {
298+
String[] additionalNames = JSONObject.getNames(additional);
299+
if (additionalNames == null) {
300+
return original;
301+
}
302+
String[] originalNames = JSONObject.getNames(original);
303+
if (originalNames == null) {
304+
return additional;
305+
}
306+
JSONObject rval = new JSONObject();
307+
Arrays.stream(originalNames)
308+
.forEach(name -> rval.put(name, original.get(name)));
309+
Arrays.stream(additionalNames)
310+
.forEach(name -> rval.put(name, additional.get(name)));
311+
return rval;
312+
}
313+
297314
private <E> void ifPresent(final String key, final Class<E> expectedType,
298315
final Consumer<E> consumer) {
299316
if (schemaJson.has(key)) {
@@ -373,22 +390,23 @@ private Schema.Builder<?> loadForType(final Object type) {
373390
/**
374391
* Returns a schema builder instance after looking up the JSON pointer.
375392
*/
376-
private Schema.Builder<?> lookupReference(final String relPointerString) {
393+
private Schema.Builder<?> lookupReference(final String relPointerString, final JSONObject context) {
377394
String absPointerString = ReferenceResolver.resolve(id, relPointerString);
378395
if (pointerSchemas.containsKey(absPointerString)) {
379396
return pointerSchemas.get(absPointerString);
380397
}
381398
JSONPointer pointer = absPointerString.startsWith("#")
382399
? JSONPointer.forDocument(rootSchemaJson, absPointerString)
383-
: JSONPointer.forURL(httpClient, absPointerString);
384-
ReferenceSchema.Builder refBuilder = ReferenceSchema.builder();
385-
pointerSchemas.put(absPointerString, refBuilder);
386-
QueryResult result = pointer.query();
387-
SchemaLoader childLoader = new SchemaLoader(id, result.getQueryResult(),
388-
result.getContainingDocument(), pointerSchemas, httpClient);
389-
Schema referredSchema = childLoader.load().build();
390-
refBuilder.build().setReferredSchema(referredSchema);
391-
return refBuilder;
400+
: JSONPointer.forURL(httpClient, absPointerString);
401+
ReferenceSchema.Builder refBuilder = ReferenceSchema.builder();
402+
pointerSchemas.put(absPointerString, refBuilder);
403+
QueryResult result = pointer.query();
404+
JSONObject resultObject = extend(context, result.getQueryResult());
405+
SchemaLoader childLoader = new SchemaLoader(id, resultObject,
406+
result.getContainingDocument(), pointerSchemas, httpClient);
407+
Schema referredSchema = childLoader.load().build();
408+
refBuilder.build().setReferredSchema(referredSchema);
409+
return refBuilder;
392410
}
393411

394412
private void populatePropertySchemas(final JSONObject propertyDefs,
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package org.everit.json.schema.loader;
2+
3+
import java.util.HashMap;
4+
5+
import org.everit.json.schema.ObjectComparator;
6+
import org.everit.json.schema.ReferenceSchema;
7+
import org.everit.json.schema.loader.internal.DefaultSchemaClient;
8+
import org.json.JSONObject;
9+
import org.json.JSONTokener;
10+
import org.junit.Assert;
11+
import org.junit.Test;
12+
13+
public class ExtendTest {
14+
15+
private static JSONObject OBJECTS;
16+
17+
static {
18+
OBJECTS = new JSONObject(new JSONTokener(
19+
ExtendTest.class.getResourceAsStream("/org/everit/jsonvalidator/merge-testcases.json")));
20+
}
21+
22+
@Test
23+
public void additionalHasMoreProps() {
24+
JSONObject actual = subject().extend(get("propIsTrue"), get("empty"));
25+
assertEquals(get("propIsTrue"), actual);
26+
}
27+
28+
@Test
29+
public void additionalOverridesOriginal() {
30+
JSONObject actual = subject().extend(get("propIsTrue"), get("propIsFalse"));
31+
assertEquals(get("propIsTrue"), actual);
32+
}
33+
34+
@Test
35+
public void additionalPropsAreMerged() {
36+
JSONObject actual = subject().extend(get("propIsTrue"), get("prop2IsFalse"));
37+
assertEquals(actual, get("propTrueProp2False"));
38+
}
39+
40+
private void assertEquals(final JSONObject expected, final JSONObject actual) {
41+
Assert.assertTrue(ObjectComparator.deepEquals(expected, actual));
42+
}
43+
44+
@Test
45+
public void bothEmpty() {
46+
JSONObject actual = subject().extend(get("empty"), get("empty"));
47+
assertEquals(new JSONObject(), actual);
48+
}
49+
50+
private JSONObject get(final String objectName) {
51+
return OBJECTS.getJSONObject(objectName);
52+
}
53+
54+
@Test
55+
public void multiplePropsAreMerged() {
56+
JSONObject actual = subject().extend(get("multipleWithPropTrue"), get("multipleWithPropFalse"));
57+
assertEquals(get("mergedMultiple"), actual);
58+
}
59+
60+
@Test
61+
public void originalPropertyRemainsUnchanged() {
62+
JSONObject actual = subject().extend(get("empty"), get("propIsTrue"));
63+
assertEquals(get("propIsTrue"), actual);
64+
}
65+
66+
private SchemaLoader subject() {
67+
return new SchemaLoader("", new JSONObject(), new JSONObject(),
68+
new HashMap<String, ReferenceSchema.Builder>(), new DefaultSchemaClient());
69+
}
70+
}

core/src/test/java/org/everit/json/schema/loader/SchemaLoaderTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,16 @@ public void pointerResolutionFailure() {
302302
SchemaLoader.load(get("pointerResolutionFailure"));
303303
}
304304

305+
@Test
306+
public void propsAroundRefExtendTheReferredSchema() {
307+
ObjectSchema actual = (ObjectSchema) SchemaLoader
308+
.load(get("propsAroundRefExtendTheReferredSchema"));
309+
ObjectSchema prop = (ObjectSchema) ((ReferenceSchema) actual.getPropertySchemas().get("prop"))
310+
.getReferredSchema();
311+
Assert.assertTrue(prop.requiresObject());
312+
Assert.assertEquals(1, prop.getMinProperties().intValue());
313+
}
314+
305315
@Test
306316
public void recursiveSchema() {
307317
SchemaLoader.load(get("recursiveSchema"));
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"empty" : {},
3+
"propIsTrue" : {
4+
"prop" : true
5+
},
6+
"propIsFalse" : {
7+
"prop" : false
8+
},
9+
"prop2IsFalse" : {
10+
"prop2" : false
11+
},
12+
"propTrueProp2False" : {
13+
"prop" : true,
14+
"prop2" : false
15+
},
16+
"multipleWithPropTrue" : {
17+
"prop" : true,
18+
"a" : "a",
19+
"b" : "b",
20+
"c" : "c"
21+
},
22+
"multipleWithPropFalse" : {
23+
"prop" : false,
24+
"b" : "b2",
25+
"d" : "d"
26+
},
27+
"mergedMultiple" : {
28+
"prop" : true,
29+
"a" : "a",
30+
"b" : "b",
31+
"c" : "c",
32+
"d" : "d"
33+
}
34+
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,5 +283,19 @@
283283
}
284284
}
285285
}
286+
},
287+
"propsAroundRefExtendTheReferredSchema" : {
288+
"definitions" : {
289+
"Object" : {
290+
"type" : "object"
291+
}
292+
},
293+
"properties" : {
294+
"prop" : {
295+
"$ref" : "#/definitions/Object",
296+
"minProperties" : 1
297+
}
298+
}
299+
286300
}
287301
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
<groupId>org.everit.json</groupId>
3131
<artifactId>org.everit.json.schema.parent</artifactId>
32-
<version>1.1.1</version>
32+
<version>1.1.2-SNAPSHOT</version>
3333

3434
<packaging>pom</packaging>
3535

tests/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<parent>
2525
<groupId>org.everit.json</groupId>
2626
<artifactId>org.everit.json.schema.parent</artifactId>
27-
<version>1.1.1</version>
27+
<version>1.1.2-SNAPSHOT</version>
2828
</parent>
2929

3030
<artifactId>org.everit.json.schema.tests</artifactId>

0 commit comments

Comments
 (0)