@@ -61,7 +61,7 @@ public class SchemaLoader {
61
61
*/
62
62
@ FunctionalInterface
63
63
private interface CombinedSchemaProvider
64
- extends Function <Collection <Schema >, CombinedSchema .Builder > {
64
+ extends Function <Collection <Schema >, CombinedSchema .Builder > {
65
65
66
66
}
67
67
@@ -115,7 +115,7 @@ public static Schema load(final JSONObject schemaJson) {
115
115
public static Schema load (final JSONObject schemaJson , final SchemaClient httpClient ) {
116
116
String schemaId = schemaJson .optString ("id" );
117
117
return new SchemaLoader (schemaId , schemaJson , schemaJson , new HashMap <>(), httpClient )
118
- .load ().build ();
118
+ .load ().build ();
119
119
}
120
120
121
121
private final SchemaClient httpClient ;
@@ -143,29 +143,29 @@ public static Schema load(final JSONObject schemaJson, final SchemaClient httpCl
143
143
144
144
private void addDependencies (final Builder builder , final JSONObject deps ) {
145
145
Arrays .stream (JSONObject .getNames (deps ))
146
- .forEach (ifPresent -> addDependency (builder , ifPresent , deps .get (ifPresent )));
146
+ .forEach (ifPresent -> addDependency (builder , ifPresent , deps .get (ifPresent )));
147
147
}
148
148
149
149
private void addDependency (final Builder builder , final String ifPresent , final Object deps ) {
150
150
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 ();
159
159
}
160
160
161
161
private void addPropertySchemaDefinition (final String keyOfObj , final Object definition ,
162
162
final ObjectSchema .Builder builder ) {
163
163
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 ();
169
169
}
170
170
171
171
private CombinedSchema .Builder buildAnyOfSchemaForMultipleTypes () {
@@ -188,15 +188,15 @@ private ArraySchema.Builder buildArraySchema() {
188
188
ifPresent ("uniqueItems" , Boolean .class , builder ::uniqueItems );
189
189
if (schemaJson .has ("additionalItems" )) {
190
190
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 ();
194
194
}
195
195
if (schemaJson .has ("items" )) {
196
196
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 ();
200
200
}
201
201
return builder ;
202
202
}
@@ -205,8 +205,8 @@ private EnumSchema.Builder buildEnumSchema() {
205
205
Set <Object > possibleValues = new HashSet <>();
206
206
JSONArray arr = schemaJson .getJSONArray ("enum" );
207
207
IntStream .range (0 , arr .length ())
208
- .mapToObj (arr ::get )
209
- .forEach (possibleValues ::add );
208
+ .mapToObj (arr ::get )
209
+ .forEach (possibleValues ::add );
210
210
return EnumSchema .builder ().possibleValues (possibleValues );
211
211
}
212
212
@@ -231,21 +231,21 @@ private ObjectSchema.Builder buildObjectSchema() {
231
231
ifPresent ("maxProperties" , Integer .class , builder ::maxProperties );
232
232
if (schemaJson .has ("properties" )) {
233
233
typeMultiplexer (schemaJson .get ("properties" ))
234
- .ifObject ().then (propertyDefs -> {
235
- populatePropertySchemas (propertyDefs , builder );
236
- }).requireAny ();
234
+ .ifObject ().then (propertyDefs -> {
235
+ populatePropertySchemas (propertyDefs , builder );
236
+ }).requireAny ();
237
237
}
238
238
if (schemaJson .has ("additionalProperties" )) {
239
239
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 ();
243
243
}
244
244
if (schemaJson .has ("required" )) {
245
245
JSONArray requiredJson = schemaJson .getJSONArray ("required" );
246
246
IntStream .range (0 , requiredJson .length ())
247
- .mapToObj (requiredJson ::getString )
248
- .forEach (builder ::addRequiredProperty );
247
+ .mapToObj (requiredJson ::getString )
248
+ .forEach (builder ::addRequiredProperty );
249
249
}
250
250
if (schemaJson .has ("patternProperties" )) {
251
251
JSONObject patternPropsJson = schemaJson .getJSONObject ("patternProperties" );
@@ -289,11 +289,17 @@ private StringSchema.Builder buildStringSchema() {
289
289
private void buildTupleSchema (final ArraySchema .Builder builder , final JSONArray itemSchema ) {
290
290
for (int i = 0 ; i < itemSchema .length (); ++i ) {
291
291
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 ();
294
294
}
295
295
}
296
296
297
+ /**
298
+ * Underscore-like extend function. Merges the properties of {@code additional} and
299
+ * {@code original}. Neither {@code additional} nor {@code original} will be modified, but the
300
+ * returned object may be referentially the same as one of the parameters (in case the other
301
+ * parameter is an empty object).
302
+ */
297
303
JSONObject extend (final JSONObject additional , final JSONObject original ) {
298
304
String [] additionalNames = JSONObject .getNames (additional );
299
305
if (additionalNames == null ) {
@@ -304,10 +310,8 @@ JSONObject extend(final JSONObject additional, final JSONObject original) {
304
310
return additional ;
305
311
}
306
312
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 )));
313
+ Arrays .stream (originalNames ).forEach (name -> rval .put (name , original .get (name )));
314
+ Arrays .stream (additionalNames ).forEach (name -> rval .put (name , additional .get (name )));
311
315
return rval ;
312
316
}
313
317
@@ -390,23 +394,23 @@ private Schema.Builder<?> loadForType(final Object type) {
390
394
/**
391
395
* Returns a schema builder instance after looking up the JSON pointer.
392
396
*/
393
- private Schema .Builder <?> lookupReference (final String relPointerString , final JSONObject context ) {
397
+ private Schema .Builder <?> lookupReference (final String relPointerString , final JSONObject ctx ) {
394
398
String absPointerString = ReferenceResolver .resolve (id , relPointerString );
395
399
if (pointerSchemas .containsKey (absPointerString )) {
396
400
return pointerSchemas .get (absPointerString );
397
401
}
398
402
JSONPointer pointer = absPointerString .startsWith ("#" )
399
403
? JSONPointer .forDocument (rootSchemaJson , absPointerString )
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 ;
404
+ : JSONPointer .forURL (httpClient , absPointerString );
405
+ ReferenceSchema .Builder refBuilder = ReferenceSchema .builder ();
406
+ pointerSchemas .put (absPointerString , refBuilder );
407
+ QueryResult result = pointer .query ();
408
+ JSONObject resultObject = extend (withoutRef ( ctx ) , result .getQueryResult ());
409
+ SchemaLoader childLoader = new SchemaLoader (id , resultObject ,
410
+ result .getContainingDocument (), pointerSchemas , httpClient );
411
+ Schema referredSchema = childLoader .load ().build ();
412
+ refBuilder .build ().setReferredSchema (referredSchema );
413
+ return refBuilder ;
410
414
}
411
415
412
416
private void populatePropertySchemas (final JSONObject propertyDefs ,
@@ -481,4 +485,20 @@ private TypeBasedMultiplexer typeMultiplexer(final String keyOfObj, final Object
481
485
});
482
486
return multiplexer ;
483
487
}
488
+
489
+ /**
490
+ * Rerurns a shallow copy of the {@code original} object, but it does not copy the {@code $ref}
491
+ * key, in case it is present in {@code original}.
492
+ */
493
+ JSONObject withoutRef (final JSONObject original ) {
494
+ String [] names = JSONObject .getNames (original );
495
+ if (names == null ) {
496
+ return original ;
497
+ }
498
+ JSONObject rval = new JSONObject ();
499
+ Arrays .stream (names )
500
+ .filter (name -> !"$ref" .equals (name ))
501
+ .forEach (name -> rval .put (name , original .get (name )));
502
+ return rval ;
503
+ }
484
504
}
0 commit comments