@@ -126,7 +126,7 @@ public OneOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
126
126
}
127
127
128
128
public Set <ValidationMessage > validate (JsonNode node , JsonNode rootNode , String at ) {
129
- Set <ValidationMessage > errors = new LinkedHashSet <>();
129
+ Set <ValidationMessage > errors = new LinkedHashSet <ValidationMessage >();
130
130
131
131
// As oneOf might contain multiple schemas take a backup of evaluatedProperties.
132
132
Object backupEvaluatedProperties = CollectorContext .getInstance ().get (UnEvaluatedPropertiesValidator .EVALUATED_PROPERTIES );
@@ -143,13 +143,14 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
143
143
state .setComplexValidator (true );
144
144
145
145
int numberOfValidSchema = 0 ;
146
- Set <ValidationMessage > childErrors = new LinkedHashSet <>();
146
+ Set <ValidationMessage > childErrors = new LinkedHashSet <ValidationMessage >();
147
147
// validate that only a single element has been received in the oneOf node
148
148
// validation should not continue, as it contradicts the oneOf requirement of only one
149
149
// if(node.isObject() && node.size()>1) {
150
150
// errors = Collections.singleton(buildValidationMessage(at, ""));
151
151
// return Collections.unmodifiableSet(errors);
152
152
// }
153
+
153
154
for (ShortcutValidator validator : schemas ) {
154
155
Set <ValidationMessage > schemaErrors = null ;
155
156
// Reset state in case the previous validator did not match
@@ -190,15 +191,36 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
190
191
Set <ValidationMessage > childNotRequiredErrors = childErrors .stream ().filter (error -> !ValidatorTypeCode .REQUIRED .getValue ().equals (error .getType ())).collect (Collectors .toSet ());
191
192
192
193
// ensure there is always an "OneOf" error reported if number of valid schemas is not equal to 1.
193
- // TODO We need to break it into two errors in the future.
194
- if (numberOfValidSchema != 1 ) {
194
+ if (numberOfValidSchema > 1 ) {
195
195
final ValidationMessage message = getMultiSchemasValidErrorMsg (at );
196
196
if (failFast ) {
197
197
throw new JsonSchemaException (message );
198
198
}
199
199
errors .add (message );
200
200
}
201
201
202
+ // ensure there is always an "OneOf" error reported if number of valid schemas is not equal to 1.
203
+ else if (numberOfValidSchema < 1 ) {
204
+ if (!childNotRequiredErrors .isEmpty ()) {
205
+ childErrors = childNotRequiredErrors ;
206
+ }
207
+ if (!childErrors .isEmpty ()) {
208
+ if (childErrors .size () > 1 ) {
209
+ Set <ValidationMessage > notAdditionalPropertiesOnly = new LinkedHashSet <>(childErrors .stream ()
210
+ .filter ((ValidationMessage validationMessage ) -> !ValidatorTypeCode .ADDITIONAL_PROPERTIES .getValue ().equals (validationMessage .getType ()))
211
+ .sorted ((vm1 , vm2 ) -> compareValidationMessages (vm1 , vm2 ))
212
+ .collect (Collectors .toList ()));
213
+ if (notAdditionalPropertiesOnly .size () > 0 ) {
214
+ childErrors = notAdditionalPropertiesOnly ;
215
+ }
216
+ }
217
+ errors .addAll (childErrors );
218
+ }
219
+ if (failFast ) {
220
+ throw new JsonSchemaException (errors .toString ());
221
+ }
222
+ }
223
+
202
224
// Make sure to signal parent handlers we matched
203
225
if (errors .isEmpty ())
204
226
state .setMatchedNode (true );
@@ -218,34 +240,84 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
218
240
}
219
241
}
220
242
243
+ /**
244
+ * Sort <code>ValidationMessage</code> by its type
245
+ * @return
246
+ */
247
+ private static int compareValidationMessages (ValidationMessage vm1 , ValidationMessage vm2 ) {
248
+ // ValidationMessage's type has smaller index in the list below has high priority
249
+ final List <String > typeCodes = Arrays .asList (
250
+ ValidatorTypeCode .TYPE .getValue (),
251
+ ValidatorTypeCode .DATETIME .getValue (),
252
+ ValidatorTypeCode .UUID .getValue (),
253
+ ValidatorTypeCode .ID .getValue (),
254
+ ValidatorTypeCode .EXCLUSIVE_MAXIMUM .getValue (),
255
+ ValidatorTypeCode .EXCLUSIVE_MINIMUM .getValue (),
256
+ ValidatorTypeCode .TRUE .getValue (),
257
+ ValidatorTypeCode .FALSE .getValue (),
258
+ ValidatorTypeCode .CONST .getValue (),
259
+ ValidatorTypeCode .CONTAINS .getValue (),
260
+ ValidatorTypeCode .PROPERTYNAMES .getValue ()
261
+ );
262
+
263
+ final int index1 = typeCodes .indexOf (vm1 .getType ());
264
+ final int index2 = typeCodes .indexOf (vm2 .getType ());
265
+
266
+ if (index1 >= 0 ) {
267
+ if (index2 >= 0 ) {
268
+ return Integer .compare (index1 , index2 );
269
+ } else {
270
+ return -1 ;
271
+ }
272
+ } else {
273
+ if (index2 >= 0 ) {
274
+ return 1 ;
275
+ } else {
276
+ return vm1 .getCode ().compareTo (vm2 .getCode ());
277
+ }
278
+ }
279
+ }
280
+
221
281
private void resetValidatorState () {
222
282
ValidatorState state = (ValidatorState ) CollectorContext .getInstance ().get (ValidatorState .VALIDATOR_STATE_KEY );
223
283
state .setComplexValidator (false );
224
284
state .setMatchedNode (true );
225
285
}
226
286
287
+ public List <JsonSchema > getChildSchemas () {
288
+ List <JsonSchema > childJsonSchemas = new ArrayList <JsonSchema >();
289
+ for (ShortcutValidator shortcutValidator : schemas ) {
290
+ childJsonSchemas .add (shortcutValidator .getSchema ());
291
+ }
292
+ return childJsonSchemas ;
293
+ }
294
+
227
295
@ Override
228
296
public Set <ValidationMessage > walk (JsonNode node , JsonNode rootNode , String at , boolean shouldValidateSchema ) {
229
297
HashSet <ValidationMessage > validationMessages = new LinkedHashSet <ValidationMessage >();
230
298
if (shouldValidateSchema ) {
231
299
validationMessages .addAll (validate (node , rootNode , at ));
232
300
} else {
233
301
for (ShortcutValidator validator : schemas ) {
234
- validator .schema .walk (node , rootNode , at , shouldValidateSchema );
302
+ validator .schema .walk (node , rootNode , at , shouldValidateSchema );
235
303
}
236
304
}
237
305
return validationMessages ;
238
306
}
239
307
240
- private ValidationMessage getMultiSchemasValidErrorMsg (String at ) {
241
- List <String > msgStrList = schemas .stream ().map (shortcutValidator -> shortcutValidator .getSchema ().getSchemaNode ().toString ()).collect (Collectors .toList ());
242
- String msg = String .join (", " , msgStrList );
308
+ private ValidationMessage getMultiSchemasValidErrorMsg (String at ){
309
+ String msg ="" ;
310
+ for (ShortcutValidator schema : schemas ){
311
+ String schemaValue = schema .getSchema ().getSchemaNode ().toString ();
312
+ msg = msg .concat (schemaValue );
313
+ }
314
+
243
315
return ValidationMessage .of (getValidatorType ().getValue (), ValidatorTypeCode .ONE_OF , at , msg );
244
316
}
245
317
246
318
@ Override
247
319
public void preloadJsonSchema () {
248
- for (final ShortcutValidator scValidator : schemas ) {
320
+ for (final ShortcutValidator scValidator : schemas ) {
249
321
scValidator .getSchema ().initializeValidators ();
250
322
}
251
323
}
0 commit comments