Skip to content

Commit dc6c798

Browse files
committed
making MetaSchemaTest pass
1 parent 302ef08 commit dc6c798

File tree

2 files changed

+135
-126
lines changed

2 files changed

+135
-126
lines changed

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

Lines changed: 133 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -55,60 +55,6 @@
5555
*/
5656
public class SchemaLoader {
5757

58-
private static final List<String> ARRAY_SCHEMA_PROPS = Arrays.asList("items", "additionalItems",
59-
"minItems",
60-
"maxItems",
61-
"uniqueItems");
62-
63-
private static final List<String> OBJECT_SCHEMA_PROPS = Arrays.asList("properties", "required",
64-
"minProperties",
65-
"maxProperties",
66-
"dependencies",
67-
"patternProperties",
68-
"additionalProperties");
69-
70-
private static final List<String> NUMBER_SCHEMA_PROPS = Arrays.asList("minimum", "maximum",
71-
"minimumExclusive", "maximumExclusive", "multipleOf");
72-
73-
private static final List<String> STRING_SCHEMA_PROPS = Arrays.asList("minLength", "maxLength",
74-
"pattern");
75-
76-
private static final Map<String, Function<Collection<Schema>, CombinedSchema.Builder>> //
77-
COMBINED_SUBSCHEMA_PROVIDERS = new HashMap<>(3);
78-
79-
static {
80-
COMBINED_SUBSCHEMA_PROVIDERS.put("allOf", CombinedSchema::allOf);
81-
COMBINED_SUBSCHEMA_PROVIDERS.put("anyOf", CombinedSchema::anyOf);
82-
COMBINED_SUBSCHEMA_PROVIDERS.put("oneOf", CombinedSchema::oneOf);
83-
}
84-
85-
/**
86-
* Loads a JSON schema to a schema validator using a {@link DefaultSchemaClient default HTTP
87-
* client}.
88-
*
89-
* @param schemaJson
90-
* the JSON representation of the schema.
91-
* @return the schema validator object
92-
*/
93-
public static Schema load(final JSONObject schemaJson) {
94-
return load(schemaJson, new DefaultSchemaClient());
95-
}
96-
97-
/**
98-
* Creates Schema instance from its JSON representation.
99-
*
100-
* @param schemaJson
101-
* the JSON representation of the schema.
102-
* @param httpClient
103-
* the HTTP client to be used for resolving remote JSON references.
104-
* @return the created schema
105-
*/
106-
public static Schema load(final JSONObject schemaJson, final SchemaClient httpClient) {
107-
String schemaId = schemaJson.optString("id");
108-
return new SchemaLoader(schemaId, schemaJson, schemaJson, new HashMap<>(), httpClient)
109-
.load().build();
110-
}
111-
11258
/**
11359
* Created and used by {@link TypeBasedMultiplexer} to set actions (consumers) for matching
11460
* classes.
@@ -136,26 +82,6 @@ interface OnTypeConsumer<E> {
13682
*/
13783
class TypeBasedMultiplexer {
13884

139-
/**
140-
* Default implementation of {@link OnTypeConsumer}, instantiated by
141-
* {@link TypeBasedMultiplexer#ifIs(Class)}.
142-
*/
143-
private class OnTypeConsumerImpl<E> implements OnTypeConsumer<E> {
144-
145-
protected final Class<?> key;
146-
147-
public OnTypeConsumerImpl(final Class<?> key) {
148-
this.key = key;
149-
}
150-
151-
@Override
152-
public TypeBasedMultiplexer then(final Consumer<E> consumer) {
153-
actions.put(key, consumer);
154-
return TypeBasedMultiplexer.this;
155-
}
156-
157-
}
158-
15985
/**
16086
* An {@link OnTypeConsumer} implementation which wraps the action ({@code obj} consumer} set by
16187
* {@link #then(Consumer)} into an other consumer which maintains {@link SchemaLoader#id}.
@@ -189,12 +115,39 @@ public TypeBasedMultiplexer then(final Consumer<JSONObject> consumer) {
189115

190116
}
191117

118+
/**
119+
* Default implementation of {@link OnTypeConsumer}, instantiated by
120+
* {@link TypeBasedMultiplexer#ifIs(Class)}.
121+
*/
122+
private class OnTypeConsumerImpl<E> implements OnTypeConsumer<E> {
123+
124+
protected final Class<?> key;
125+
126+
public OnTypeConsumerImpl(final Class<?> key) {
127+
this.key = key;
128+
}
129+
130+
@Override
131+
public TypeBasedMultiplexer then(final Consumer<E> consumer) {
132+
actions.put(key, consumer);
133+
return TypeBasedMultiplexer.this;
134+
}
135+
136+
}
137+
192138
private final String keyOfObj;
193139

194140
private final Object obj;
195141

196142
private final Map<Class<?>, Consumer<?>> actions = new HashMap<>();
197143

144+
/**
145+
* Constructor with {@code null} {@code keyOfObj}.
146+
*/
147+
public TypeBasedMultiplexer(final Object obj) {
148+
this(null, obj);
149+
}
150+
198151
/**
199152
* Constructor.
200153
*
@@ -210,13 +163,6 @@ public TypeBasedMultiplexer(final String keyOfObj, final Object obj) {
210163
this.obj = obj;
211164
}
212165

213-
/**
214-
* Constructor with {@code null} {@code keyOfObj}.
215-
*/
216-
public TypeBasedMultiplexer(final Object obj) {
217-
this(null, obj);
218-
}
219-
220166
/**
221167
* Creates a setter which will be invoked by {@link #orElse(Consumer)} or {@link #requireAny()}
222168
* if {@code obj} is an instance of {@code predicateClass}.
@@ -256,10 +202,10 @@ public OnTypeConsumer<JSONObject> ifObject() {
256202
public void orElse(final Consumer<Object> orElseConsumer) {
257203
@SuppressWarnings("unchecked")
258204
Consumer<Object> consumer = (Consumer<Object>) actions.keySet().stream()
259-
.filter(clazz -> clazz.isAssignableFrom(obj.getClass()))
260-
.findFirst()
261-
.map(actions::get)
262-
.orElse(orElseConsumer::accept);
205+
.filter(clazz -> clazz.isAssignableFrom(obj.getClass()))
206+
.findFirst()
207+
.map(actions::get)
208+
.orElse(orElseConsumer::accept);
263209
consumer.accept(obj);
264210

265211
}
@@ -276,12 +222,58 @@ public void requireAny() {
276222
}
277223
}
278224

279-
TypeBasedMultiplexer typeMultiplexer(final Object obj) {
280-
return new TypeBasedMultiplexer(obj);
225+
private static final List<String> ARRAY_SCHEMA_PROPS = Arrays.asList("items", "additionalItems",
226+
"minItems",
227+
"maxItems",
228+
"uniqueItems");
229+
230+
private static final List<String> OBJECT_SCHEMA_PROPS = Arrays.asList("properties", "required",
231+
"minProperties",
232+
"maxProperties",
233+
"dependencies",
234+
"patternProperties",
235+
"additionalProperties");
236+
237+
private static final List<String> NUMBER_SCHEMA_PROPS = Arrays.asList("minimum", "maximum",
238+
"minimumExclusive", "maximumExclusive", "multipleOf");
239+
240+
private static final List<String> STRING_SCHEMA_PROPS = Arrays.asList("minLength", "maxLength",
241+
"pattern");
242+
243+
private static final Map<String, Function<Collection<Schema>, CombinedSchema.Builder>> //
244+
COMBINED_SUBSCHEMA_PROVIDERS = new HashMap<>(3);
245+
246+
static {
247+
COMBINED_SUBSCHEMA_PROVIDERS.put("allOf", CombinedSchema::allOf);
248+
COMBINED_SUBSCHEMA_PROVIDERS.put("anyOf", CombinedSchema::anyOf);
249+
COMBINED_SUBSCHEMA_PROVIDERS.put("oneOf", CombinedSchema::oneOf);
281250
}
282251

283-
TypeBasedMultiplexer typeMultiplexer(final String keyOfObj, final Object obj) {
284-
return new TypeBasedMultiplexer(keyOfObj, obj);
252+
/**
253+
* Loads a JSON schema to a schema validator using a {@link DefaultSchemaClient default HTTP
254+
* client}.
255+
*
256+
* @param schemaJson
257+
* the JSON representation of the schema.
258+
* @return the schema validator object
259+
*/
260+
public static Schema load(final JSONObject schemaJson) {
261+
return load(schemaJson, new DefaultSchemaClient());
262+
}
263+
264+
/**
265+
* Creates Schema instance from its JSON representation.
266+
*
267+
* @param schemaJson
268+
* the JSON representation of the schema.
269+
* @param httpClient
270+
* the HTTP client to be used for resolving remote JSON references.
271+
* @return the created schema
272+
*/
273+
public static Schema load(final JSONObject schemaJson, final SchemaClient httpClient) {
274+
String schemaId = schemaJson.optString("id");
275+
return new SchemaLoader(schemaId, schemaJson, schemaJson, new HashMap<>(), httpClient)
276+
.load().build();
285277
}
286278

287279
private String id = null;
@@ -309,19 +301,19 @@ TypeBasedMultiplexer typeMultiplexer(final String keyOfObj, final Object obj) {
309301

310302
private void addDependencies(final Builder builder, final JSONObject deps) {
311303
Arrays.stream(JSONObject.getNames(deps))
312-
.forEach(ifPresent -> addDependency(builder, ifPresent, deps.get(ifPresent)));
304+
.forEach(ifPresent -> addDependency(builder, ifPresent, deps.get(ifPresent)));
313305
}
314306

315307
private void addDependency(final Builder builder, final String ifPresent, final Object deps) {
316308
typeMultiplexer(deps)
317-
.ifObject().then(obj -> {
318-
builder.schemaDependency(ifPresent, loadChild(obj).build());
319-
})
320-
.ifIs(JSONArray.class).then(propNames -> {
321-
IntStream.range(0, propNames.length())
309+
.ifObject().then(obj -> {
310+
builder.schemaDependency(ifPresent, loadChild(obj).build());
311+
})
312+
.ifIs(JSONArray.class).then(propNames -> {
313+
IntStream.range(0, propNames.length())
322314
.mapToObj(i -> propNames.getString(i))
323315
.forEach(dependency -> builder.propertyDependency(ifPresent, dependency));
324-
}).requireAny();
316+
}).requireAny();
325317
}
326318

327319
private CombinedSchema.Builder buildAnyOfSchemaForMultipleTypes() {
@@ -350,13 +342,22 @@ private ArraySchema.Builder buildArraySchema() {
350342
}
351343
if (schemaJson.has("items")) {
352344
typeMultiplexer("items", schemaJson.get("items"))
353-
.ifObject().then(itemSchema -> builder.allItemSchema(loadChild(itemSchema).build()))
354-
.ifIs(JSONArray.class).then(arr -> buildTupleSchema(builder, arr))
355-
.requireAny();
345+
.ifObject().then(itemSchema -> builder.allItemSchema(loadChild(itemSchema).build()))
346+
.ifIs(JSONArray.class).then(arr -> buildTupleSchema(builder, arr))
347+
.requireAny();
356348
}
357349
return builder;
358350
}
359351

352+
private EnumSchema.Builder buildEnumSchema() {
353+
Set<Object> possibleValues = new HashSet<>();
354+
JSONArray arr = schemaJson.getJSONArray("enum");
355+
IntStream.range(0, arr.length())
356+
.mapToObj(arr::get)
357+
.forEach(possibleValues::add);
358+
return EnumSchema.builder().possibleValues(possibleValues);
359+
}
360+
360361
private NotSchema.Builder buildNotSchema() {
361362
Schema mustNotMatch = loadChild(schemaJson.getJSONObject("not")).build();
362363
return NotSchema.builder().mustNotMatch(mustNotMatch);
@@ -379,8 +380,8 @@ private ObjectSchema.Builder buildObjectSchema() {
379380
if (schemaJson.has("properties")) {
380381
JSONObject propertyDefs = schemaJson.getJSONObject("properties");
381382
Arrays.stream(Optional.ofNullable(JSONObject.getNames(propertyDefs)).orElse(new String[0]))
382-
.forEach(key -> builder.addPropertySchema(key,
383-
loadChild(propertyDefs.getJSONObject(key)).build()));
383+
.forEach(key -> builder.addPropertySchema(key,
384+
loadChild(propertyDefs.getJSONObject(key)).build()));
384385
}
385386
if (schemaJson.has("additionalProperties")) {
386387
typeMultiplexer("additionalProperties", schemaJson.get("additionalProperties"))
@@ -391,8 +392,8 @@ private ObjectSchema.Builder buildObjectSchema() {
391392
if (schemaJson.has("required")) {
392393
JSONArray requiredJson = schemaJson.getJSONArray("required");
393394
IntStream.range(0, requiredJson.length())
394-
.mapToObj(requiredJson::getString)
395-
.forEach(builder::addRequiredProperty);
395+
.mapToObj(requiredJson::getString)
396+
.forEach(builder::addRequiredProperty);
396397
}
397398
if (schemaJson.has("patternProperties")) {
398399
JSONObject patternPropsJson = schemaJson.getJSONObject("patternProperties");
@@ -481,25 +482,6 @@ private Schema.Builder<?> load() {
481482
return builder;
482483
}
483484

484-
private Schema.Builder<?> loadForType(final Object type) {
485-
if (type instanceof JSONArray) {
486-
return buildAnyOfSchemaForMultipleTypes();
487-
} else if (type instanceof String) {
488-
return loadForExplicitType((String) type);
489-
} else {
490-
throw new SchemaException("type", Arrays.asList(JSONArray.class, String.class), type);
491-
}
492-
}
493-
494-
private EnumSchema.Builder buildEnumSchema() {
495-
Set<Object> possibleValues = new HashSet<>();
496-
JSONArray arr = schemaJson.getJSONArray("enum");
497-
IntStream.range(0, arr.length())
498-
.mapToObj(arr::get)
499-
.forEach(possibleValues::add);
500-
return EnumSchema.builder().possibleValues(possibleValues);
501-
}
502-
503485
private Schema.Builder<?> loadChild(final JSONObject childJson) {
504486
return new SchemaLoader(id, childJson, rootSchemaJson, pointerSchemas,
505487
httpClient).load();
@@ -526,6 +508,16 @@ private Schema.Builder<?> loadForExplicitType(final String typeString) {
526508
}
527509
}
528510

511+
private Schema.Builder<?> loadForType(final Object type) {
512+
if (type instanceof JSONArray) {
513+
return buildAnyOfSchemaForMultipleTypes();
514+
} else if (type instanceof String) {
515+
return loadForExplicitType((String) type);
516+
} else {
517+
throw new SchemaException("type", Arrays.asList(JSONArray.class, String.class), type);
518+
}
519+
}
520+
529521
/**
530522
* Returns a schema builder instance after looking up the JSON pointer.
531523
*/
@@ -547,11 +539,19 @@ private Schema.Builder<?> lookupReference(final String relPointerString) {
547539
return refBuilder;
548540
}
549541
} else {
542+
if (pointerSchemas.containsKey(absPointerString)) {
543+
return pointerSchemas.get(absPointerString);
544+
}
545+
ReferenceSchema.Builder refBuilder = ReferenceSchema.builder();
546+
pointerSchemas.put(absPointerString, refBuilder);
550547
pointer = JSONPointer.forURL(httpClient, absPointerString);
548+
QueryResult result = pointer.query();
549+
SchemaLoader childLoader = new SchemaLoader(id, result.getQueryResult(),
550+
result.getContainingDocument(), pointerSchemas, httpClient);
551+
Schema referredSchema = childLoader.load().build();
552+
refBuilder.build().setReferredSchema(referredSchema);
553+
return refBuilder;
551554
}
552-
QueryResult result = pointer.query();
553-
return new SchemaLoader(id, result.getQueryResult(), result.getContainingDocument(),
554-
pointerSchemas, httpClient).load();
555555
}
556556

557557
private boolean schemaHasAnyOf(final Collection<String> propNames) {
@@ -603,4 +603,12 @@ private CombinedSchema.Builder tryCombinedSchema() {
603603
return null;
604604
}
605605
}
606+
607+
TypeBasedMultiplexer typeMultiplexer(final Object obj) {
608+
return new TypeBasedMultiplexer(obj);
609+
}
610+
611+
TypeBasedMultiplexer typeMultiplexer(final String keyOfObj, final Object obj) {
612+
return new TypeBasedMultiplexer(keyOfObj, obj);
613+
}
606614
}

core/src/main/java/org/everit/json/schema/loader/internal/JSONPointer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,9 @@ public QueryResult query() {
152152
if (fragment.isEmpty()) {
153153
return new QueryResult(document, document);
154154
}
155+
System.out.println("\tquerying " + fragment);
155156
String[] path = fragment.split("/");
156-
if ( path[0] == null || !path[0].startsWith("#")) {
157+
if (path[0] == null || !path[0].startsWith("#")) {
157158
throw new IllegalArgumentException("JSON pointers must start with a '#'");
158159
}
159160
Object current = document;

0 commit comments

Comments
 (0)