Skip to content

Commit cb5deb9

Browse files
committed
added ReferenceSchema for handling self-schema references. 263/261 tests passing, all needs a cleanup
1 parent 2ef1625 commit cb5deb9

File tree

5 files changed

+110
-27
lines changed

5 files changed

+110
-27
lines changed

core/src/main/java/org/everit/jsonvalidator/EmptySchema.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ public class EmptySchema extends Schema {
2222

2323
public static final EmptySchema INSTANCE = new EmptySchema(builder());
2424

25-
public static class Builder extends Schema.Builder {
25+
/**
26+
* Builder class for {@link EmptySchema}.
27+
*/
28+
public static class Builder extends Schema.Builder<EmptySchema> {
2629

30+
@Override
2731
public EmptySchema build() {
2832
return new EmptySchema(this);
2933
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package org.everit.jsonvalidator;
2+
3+
public class ReferenceSchema extends Schema {
4+
5+
public static class Builder extends Schema.Builder {
6+
7+
private ReferenceSchema retval;
8+
9+
@Override
10+
public ReferenceSchema build() {
11+
if (retval == null) {
12+
retval = new ReferenceSchema(this);
13+
}
14+
return retval;
15+
}
16+
17+
}
18+
19+
public static Builder builder() {
20+
return new Builder();
21+
}
22+
23+
private Schema referredSchema;
24+
25+
public ReferenceSchema(final Builder builder) {
26+
super(builder);
27+
}
28+
29+
@Override
30+
void validate(final Object subject) {
31+
if (referredSchema == null) {
32+
throw new IllegalStateException("referredSchema must be injected before validation");
33+
}
34+
referredSchema.validate(subject);
35+
}
36+
37+
public Schema getReferredSchema() {
38+
return referredSchema;
39+
}
40+
41+
public void setReferredSchema(final Schema referredSchema) {
42+
if (this.referredSchema != null) {
43+
throw new IllegalStateException("referredSchema can be injected only once");
44+
}
45+
this.referredSchema = referredSchema;
46+
}
47+
48+
}

core/src/main/java/org/everit/jsonvalidator/loader/SchemaLoader.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.everit.jsonvalidator.NumberSchema;
4242
import org.everit.jsonvalidator.ObjectSchema;
4343
import org.everit.jsonvalidator.ObjectSchema.Builder;
44+
import org.everit.jsonvalidator.ReferenceSchema;
4445
import org.everit.jsonvalidator.Schema;
4546
import org.everit.jsonvalidator.SchemaException;
4647
import org.everit.jsonvalidator.StringSchema;
@@ -82,7 +83,11 @@ public class SchemaLoader {
8283
}
8384

8485
public static Schema load(final JSONObject schemaJson) {
85-
return new SchemaLoader(schemaJson.optString("id"), schemaJson, schemaJson).load().build();
86+
SchemaLoader loader = new SchemaLoader(schemaJson.optString("id"), schemaJson, schemaJson, null);
87+
Schema.Builder<?> schemaBuilder = loader.load();
88+
Schema schema = schemaBuilder.build();
89+
loader.rootReferences.forEach(ref -> ref.build().setReferredSchema(schema));
90+
return schema;
8691

8792
}
8893

@@ -183,17 +188,20 @@ TypeBasedMultiplexer typeMultiplexer(final String keyOfObj, final Object obj) {
183188
return new TypeBasedMultiplexer(keyOfObj, obj);
184189
}
185190

191+
private final Collection<ReferenceSchema.Builder> rootReferences;
192+
186193
private String id = null;
187194

188195
private final JSONObject schemaJson;
189196

190197
private final JSONObject rootSchemaJson;
191198

192199
public SchemaLoader(final String id, final JSONObject schemaJson,
193-
final JSONObject rootSchemaJson) {
200+
final JSONObject rootSchemaJson, final Collection<ReferenceSchema.Builder> rootReferences) {
194201
this.schemaJson = Objects.requireNonNull(schemaJson, "schemaJson cannot be null");
195202
this.rootSchemaJson = Objects.requireNonNull(rootSchemaJson, "rootSchemaJson cannot be null");
196203
this.id = id;
204+
this.rootReferences = rootReferences == null ? new ArrayList<>() : rootReferences;
197205
}
198206

199207
private void addDependencies(final Builder builder, final JSONObject deps) {
@@ -343,7 +351,7 @@ private <E> void ifPresent(final String key, final Class<E> expectedType,
343351
}
344352

345353
/**
346-
* Populates a {@code Schema} instance from the {@code schemaJson} schema definition.
354+
* Populates a {@code Schema.Builder} instance from the {@code schemaJson} schema definition.
347355
*/
348356
public Schema.Builder<?> load() {
349357
Schema.Builder<?> builder;
@@ -385,7 +393,7 @@ private EnumSchema.Builder buildEnumSchema() {
385393
}
386394

387395
private Schema.Builder<?> loadChild(final JSONObject childJson) {
388-
return new SchemaLoader(id, childJson, rootSchemaJson).load();
396+
return new SchemaLoader(id, childJson, rootSchemaJson, rootReferences).load();
389397
}
390398

391399
private Schema.Builder<?> loadForExplicitType(final String typeString) {
@@ -411,7 +419,9 @@ private Schema.Builder<?> loadForExplicitType(final String typeString) {
411419

412420
private Schema.Builder<?> lookupReference(final String relPointerString) {
413421
if (relPointerString.equals("#")) {
414-
throw new UnsupportedOperationException("recursive reference");
422+
ReferenceSchema.Builder rval = new ReferenceSchema.Builder();
423+
rootReferences.add(rval);
424+
return rval;
415425
}
416426
JSONPointer pointer;
417427
String absPointerString = id + relPointerString;
@@ -421,7 +431,8 @@ private Schema.Builder<?> lookupReference(final String relPointerString) {
421431
pointer = JSONPointer.forURL(HttpClients.createDefault(), absPointerString);
422432
}
423433
QueryResult result = pointer.query();
424-
return new SchemaLoader(id, result.getQueryResult(), result.getContainingDocument()).load();
434+
return new SchemaLoader(id, result.getQueryResult(), result.getContainingDocument(),
435+
rootReferences).load();
425436
}
426437

427438
private boolean schemaHasAnyOf(final Collection<String> propNames) {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.everit.jsonvalidator;
2+
3+
import org.everit.jsonvalidator.ReferenceSchema.Builder;
4+
import org.junit.Assert;
5+
import org.junit.Test;
6+
7+
public class ReferenceSchemaTest {
8+
9+
@Test
10+
public void constructorMustRunOnlyOnce() {
11+
Builder builder = ReferenceSchema.builder();
12+
Assert.assertSame(builder.build(), builder.build());
13+
}
14+
15+
@Test(expected = IllegalStateException.class)
16+
public void setterShouldWorkOnlyOnce() {
17+
ReferenceSchema subject = ReferenceSchema.builder().build();
18+
subject.setReferredSchema(BooleanSchema.INSTANCE);
19+
subject.setReferredSchema(BooleanSchema.INSTANCE);
20+
}
21+
22+
}

core/src/test/java/org/everit/jsonvalidator/loader/SchemaLoaderTest.java

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import org.json.JSONTokener;
3636
import org.junit.Assert;
3737
import org.junit.BeforeClass;
38-
import org.junit.Ignore;
3938
import org.junit.Test;
4039

4140
public class SchemaLoaderTest {
@@ -44,32 +43,32 @@ public class SchemaLoaderTest {
4443

4544
@Test
4645
public void typeBasedMultiplexerTest() {
47-
SchemaLoader loader = new SchemaLoader(null, new JSONObject(), new JSONObject());
46+
SchemaLoader loader = new SchemaLoader(null, new JSONObject(), new JSONObject(), null);
4847
loader.typeMultiplexer(new JSONObject())
49-
.ifObject().then(jsonObj -> {
50-
})
51-
.ifIs(JSONArray.class).then(jsonArr -> {
52-
})
53-
.orElse(obj -> {
54-
});
48+
.ifObject().then(jsonObj -> {
49+
})
50+
.ifIs(JSONArray.class).then(jsonArr -> {
51+
})
52+
.orElse(obj -> {
53+
});
5554

5655
loader.typeMultiplexer(new JSONObject())
57-
.ifObject().then(jsonObj -> {
58-
})
59-
.ifIs(JSONArray.class).then(jsonArr -> {
60-
})
61-
.requireAny();
56+
.ifObject().then(jsonObj -> {
57+
})
58+
.ifIs(JSONArray.class).then(jsonArr -> {
59+
})
60+
.requireAny();
6261
}
6362

6463
@Test(expected = SchemaException.class)
6564
public void typeBasedMultiplexerFailure() {
66-
SchemaLoader loader = new SchemaLoader(null, new JSONObject(), new JSONObject());
65+
SchemaLoader loader = new SchemaLoader(null, new JSONObject(), new JSONObject(), null);
6766
loader.typeMultiplexer("foo")
68-
.ifObject().then(o -> {
69-
})
70-
.ifIs(JSONArray.class).then(o -> {
71-
})
72-
.requireAny();
67+
.ifObject().then(o -> {
68+
})
69+
.ifIs(JSONArray.class).then(o -> {
70+
})
71+
.requireAny();
7372
}
7473

7574
@BeforeClass
@@ -336,7 +335,6 @@ public void emptySchemaWithDefault() {
336335
}
337336

338337
@Test
339-
@Ignore
340338
public void selfRecursiveSchema() {
341339
SchemaLoader.load(get("selfRecursiveSchema"));
342340
}

0 commit comments

Comments
 (0)