24
24
import java .util .Map ;
25
25
import java .util .Map .Entry ;
26
26
import java .util .Objects ;
27
+ import java .util .Optional ;
27
28
import java .util .Set ;
28
29
import java .util .regex .Pattern ;
30
+ import java .util .stream .Collectors ;
29
31
import java .util .stream .Stream ;
30
32
31
33
import org .json .JSONObject ;
@@ -247,6 +249,15 @@ public Schema getSchemaOfAdditionalProperties() {
247
249
return schemaOfAdditionalProperties ;
248
250
}
249
251
252
+ private Optional <ValidationException > ifFails (final Schema schema , final Object input ) {
253
+ try {
254
+ schema .validate (input );
255
+ return Optional .empty ();
256
+ } catch (ValidationException e ) {
257
+ return Optional .of (e );
258
+ }
259
+ }
260
+
250
261
private boolean matchesAnyPattern (final String key ) {
251
262
return patternProperties .keySet ().stream ()
252
263
.filter (pattern -> pattern .matcher (key ).find ())
@@ -262,30 +273,45 @@ public boolean requiresObject() {
262
273
return requiresObject ;
263
274
}
264
275
265
- private void testAdditionalProperties (final JSONObject subject ) {
276
+ private List < ValidationException > testAdditionalProperties (final JSONObject subject ) {
266
277
if (!additionalProperties ) {
267
- getAdditionalProperties (subject )
278
+ return getAdditionalProperties (subject )
268
279
.findFirst ()
269
- .ifPresent (unneeded -> failure ("extraneous key [%s] is not permitted" , unneeded ));
280
+ .map (unneeded -> String .format ("extraneous key [%s] is not permitted" , unneeded ))
281
+ .map (msg -> new ValidationException (this , msg ))
282
+ .map (exc -> Arrays .asList (exc ))
283
+ .orElse (Collections .emptyList ());
270
284
} else if (schemaOfAdditionalProperties != null ) {
271
- getAdditionalProperties (subject )
272
- .map (subject ::get )
273
- .forEach (schemaOfAdditionalProperties ::validate );
285
+ List <String > additionalPropNames = getAdditionalProperties (subject )
286
+ .collect (Collectors .toList ());
287
+ List <ValidationException > rval = new ArrayList <ValidationException >();
288
+ for (String propName : additionalPropNames ) {
289
+ Object propVal = subject .get (propName );
290
+ ifFails (schemaOfAdditionalProperties , propVal )
291
+ .map (failure -> failure .prepend (propName , this ))
292
+ .ifPresent (rval ::add );
293
+ }
294
+ return rval ;
274
295
}
296
+ return Collections .emptyList ();
275
297
}
276
298
277
- private void testPatternProperties (final JSONObject subject ) {
299
+ private List < ValidationException > testPatternProperties (final JSONObject subject ) {
278
300
String [] propNames = JSONObject .getNames (subject );
279
301
if (propNames == null || propNames .length == 0 ) {
280
- return ;
302
+ return Collections . emptyList () ;
281
303
}
304
+ List <ValidationException > rval = new ArrayList <>();
282
305
for (Entry <Pattern , Schema > entry : patternProperties .entrySet ()) {
283
306
for (String propName : propNames ) {
284
307
if (entry .getKey ().matcher (propName ).find ()) {
285
- entry .getValue ().validate (subject .get (propName ));
308
+ ifFails (entry .getValue (), subject .get (propName ))
309
+ .map (exc -> exc .prepend (propName , exc .getViolatedSchema ()))
310
+ .ifPresent (rval ::add );
286
311
}
287
312
}
288
313
}
314
+ return rval ;
289
315
}
290
316
291
317
private void testProperties (final JSONObject subject ) {
@@ -301,36 +327,36 @@ private void testProperties(final JSONObject subject) {
301
327
302
328
private void testPropertyDependencies (final JSONObject subject ) {
303
329
propertyDependencies .keySet ().stream ()
304
- .filter (subject ::has )
305
- .flatMap (ifPresent -> propertyDependencies .get (ifPresent ).stream ())
306
- .filter (mustBePresent -> !subject .has (mustBePresent ))
307
- .findFirst ()
308
- .ifPresent (missing -> failure ("property [%s] is required" , missing ));
330
+ .filter (subject ::has )
331
+ .flatMap (ifPresent -> propertyDependencies .get (ifPresent ).stream ())
332
+ .filter (mustBePresent -> !subject .has (mustBePresent ))
333
+ .findFirst ()
334
+ .ifPresent (missing -> failure ("property [%s] is required" , missing ));
309
335
}
310
336
311
337
private void testRequiredProperties (final JSONObject subject ) {
312
338
requiredProperties .stream ()
313
- .filter (key -> !subject .has (key ))
314
- .findFirst ()
315
- .ifPresent (missing -> failure ("required key [%s] not found" , missing ));
339
+ .filter (key -> !subject .has (key ))
340
+ .findFirst ()
341
+ .ifPresent (missing -> failure ("required key [%s] not found" , missing ));
316
342
}
317
343
318
344
private void testSchemaDependencies (final JSONObject subject ) {
319
345
schemaDependencies .keySet ().stream ()
320
- .filter (subject ::has )
321
- .map (schemaDependencies ::get )
322
- .forEach (schema -> schema .validate (subject ));
346
+ .filter (subject ::has )
347
+ .map (schemaDependencies ::get )
348
+ .forEach (schema -> schema .validate (subject ));
323
349
}
324
350
325
351
private void testSize (final JSONObject subject ) {
326
352
int actualSize = subject .length ();
327
353
if (minProperties != null && actualSize < minProperties .intValue ()) {
328
- throw new ValidationException (String .format ("minimum size: [%d], found: [%d]" , minProperties ,
329
- actualSize ));
354
+ throw new ValidationException (this , String .format ("minimum size: [%d], found: [%d]" ,
355
+ minProperties , actualSize ));
330
356
}
331
357
if (maxProperties != null && actualSize > maxProperties .intValue ()) {
332
- throw new ValidationException (String .format ("maximum size: [%d], found: [%d]" , maxProperties ,
333
- actualSize ));
358
+ throw new ValidationException (this , String .format ("maximum size: [%d], found: [%d]" ,
359
+ maxProperties , actualSize ));
334
360
}
335
361
}
336
362
@@ -341,14 +367,18 @@ public void validate(final Object subject) {
341
367
throw new ValidationException (JSONObject .class , subject );
342
368
}
343
369
} else {
370
+ List <ValidationException > failures = new ArrayList <>();
344
371
JSONObject objSubject = (JSONObject ) subject ;
345
372
testProperties (objSubject );
346
373
testRequiredProperties (objSubject );
347
- testAdditionalProperties (objSubject );
374
+ failures . addAll ( testAdditionalProperties (objSubject ) );
348
375
testSize (objSubject );
349
376
testPropertyDependencies (objSubject );
350
377
testSchemaDependencies (objSubject );
351
- testPatternProperties (objSubject );
378
+ failures .addAll (testPatternProperties (objSubject ));
379
+ if (failures .size () == 1 ) {
380
+ throw failures .get (0 );
381
+ }
352
382
}
353
383
}
354
384
0 commit comments