Skip to content

Commit 2879ca3

Browse files
authored
Fix validation messages (#969)
* Generate translations and ensure encoded in ISO-8859-1 for Java 8 * Make how schema errors are reported consistent * Refactor oneOf * Make id error message clearer * Make messages more consistent * Fix * Fix * Fix * Fix
1 parent 7cda40e commit 2879ca3

File tree

76 files changed

+2275
-1476
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+2275
-1476
lines changed

src/main/java/com/networknt/schema/ConstValidator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
4141
if (schemaNode.decimalValue().compareTo(node.decimalValue()) != 0) {
4242
return Collections.singleton(message().instanceNode(node).instanceLocation(instanceLocation)
4343
.locale(executionContext.getExecutionConfig().getLocale())
44-
.failFast(executionContext.isFailFast()).arguments(schemaNode.asText())
44+
.failFast(executionContext.isFailFast()).arguments(schemaNode.asText(), node.asText())
4545
.build());
4646
}
4747
} else if (!schemaNode.equals(node)) {

src/main/java/com/networknt/schema/JsonSchema.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ private static SchemaLocation resolve(SchemaLocation schemaLocation, JsonNode sc
8181
ValidationMessage validationMessage = ValidationMessage.builder()
8282
.code(ValidatorTypeCode.ID.getValue()).type(ValidatorTypeCode.ID.getValue())
8383
.instanceLocation(idSchemaLocation.getFragment())
84-
.arguments(schemaLocation.toString(), id)
84+
.arguments(id, validationContext.getMetaSchema().getIdKeyword(), idSchemaLocation)
8585
.schemaLocation(idSchemaLocation)
8686
.schemaNode(schemaNode)
8787
.messageFormatter(args -> validationContext.getConfig().getMessageSource().getMessage(

src/main/java/com/networknt/schema/MaxItemsValidator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
4646
if (node.size() > max) {
4747
return Collections.singleton(message().instanceNode(node).instanceLocation(instanceLocation)
4848
.locale(executionContext.getExecutionConfig().getLocale())
49-
.failFast(executionContext.isFailFast()).arguments(max).build());
49+
.failFast(executionContext.isFailFast()).arguments(max, node.size()).build());
5050
}
5151
} else if (this.validationContext.getConfig().isTypeLoose()) {
5252
if (1 > max) {
5353
return Collections.singleton(message().instanceNode(node).instanceLocation(instanceLocation)
5454
.locale(executionContext.getExecutionConfig().getLocale())
55-
.failFast(executionContext.isFailFast()).arguments(max).build());
55+
.failFast(executionContext.isFailFast()).arguments(max, 1).build());
5656
}
5757
}
5858

src/main/java/com/networknt/schema/OneOfValidator.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
5555
state.setComplexValidator(true);
5656

5757
int numberOfValidSchema = 0;
58+
int index = 0;
5859
SetView<ValidationMessage> childErrors = null;
60+
List<String> indexes = null;
5961

6062
// Save flag as nested schema evaluation shouldn't trigger fail fast
6163
boolean failFast = executionContext.isFailFast();
@@ -82,10 +84,15 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
8284
continue;
8385
}
8486
numberOfValidSchema++;
87+
if (indexes == null) {
88+
indexes = new ArrayList<>();
89+
}
90+
indexes.add(Integer.toString(index));
8591
}
86-
92+
8793
if (numberOfValidSchema > 1 && canShortCircuit()) {
8894
// short-circuit
95+
// note that the short circuit means that only 2 valid schemas are reported even if could be more
8996
break;
9097
}
9198

@@ -95,6 +102,7 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
95102
}
96103
childErrors.union(schemaErrors);
97104
}
105+
index++;
98106
}
99107
} finally {
100108
// Restore flag
@@ -105,9 +113,10 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
105113
// is not equal to 1.
106114
if (numberOfValidSchema != 1) {
107115
ValidationMessage message = message().instanceNode(node).instanceLocation(instanceLocation)
116+
.messageKey(numberOfValidSchema > 1 ? "oneOf.indexes" : "oneOf")
108117
.locale(executionContext.getExecutionConfig().getLocale())
109118
.failFast(executionContext.isFailFast())
110-
.arguments(Integer.toString(numberOfValidSchema)).build();
119+
.arguments(Integer.toString(numberOfValidSchema), numberOfValidSchema > 1 ? String.join(", ", indexes) : "").build();
111120
if (childErrors != null) {
112121
errors = new SetView<ValidationMessage>().union(Collections.singleton(message)).union(childErrors);
113122
} else {

src/main/java/com/networknt/schema/UnevaluatedItemsValidator.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -176,22 +176,22 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
176176
for (int x = validCount; x < node.size(); x++) {
177177
// The schema is either "false" or an object schema
178178
if (!containsEvaluated.contains(x)) {
179-
messages.addAll(
180-
this.schema.validate(executionContext, node.get(x), node, instanceLocation.append(x)));
179+
if (this.schemaNode.isBoolean() && this.schemaNode.booleanValue() == false) {
180+
// All fails as "unevaluatedItems: false"
181+
messages.add(message().instanceNode(node).instanceLocation(instanceLocation).arguments(x)
182+
.locale(executionContext.getExecutionConfig().getLocale())
183+
.failFast(executionContext.isFailFast()).build());
184+
} else {
185+
// Schema errors will be reported as is
186+
messages.addAll(this.schema.validate(executionContext, node.get(x), node,
187+
instanceLocation.append(x)));
188+
}
181189
evaluated = true;
182190
}
183191
}
184192
}
185193
if (messages.isEmpty()) {
186194
valid = true;
187-
} else {
188-
// Report these as unevaluated paths or not matching the unevaluatedItems schema
189-
messages = messages.stream()
190-
.map(m -> message().instanceNode(node).instanceLocation(instanceLocation)
191-
.locale(executionContext.getExecutionConfig().getLocale())
192-
.arguments(m.getInstanceLocation().getName(-1))
193-
.failFast(executionContext.isFailFast()).build())
194-
.collect(Collectors.toCollection(LinkedHashSet::new));
195195
}
196196
}
197197
// If the "unevaluatedItems" subschema is applied to any positions within the

src/main/java/com/networknt/schema/UnevaluatedPropertiesValidator.java

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,11 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
119119
evaluatedProperties.add(fieldName);
120120
if (this.schemaNode.isBoolean() && this.schemaNode.booleanValue() == false) {
121121
// All fails as "unevaluatedProperties: false"
122-
messages.add(message().instanceNode(node).instanceLocation(instanceLocation.append(fieldName))
123-
.locale(executionContext.getExecutionConfig().getLocale())
122+
messages.add(message().instanceNode(node).instanceLocation(instanceLocation).property(fieldName)
123+
.arguments(fieldName).locale(executionContext.getExecutionConfig().getLocale())
124124
.failFast(executionContext.isFailFast()).build());
125125
} else {
126+
// Schema errors will be reported as is
126127
messages.addAll(this.schema.validate(executionContext, node.get(fieldName), node,
127128
instanceLocation.append(fieldName)));
128129
}
@@ -131,17 +132,6 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
131132
} finally {
132133
executionContext.setFailFast(failFast); // restore flag
133134
}
134-
if (!messages.isEmpty()) {
135-
// Report these as unevaluated paths or not matching the unevaluatedProperties
136-
// schema
137-
messages = messages.stream()
138-
.map(m -> message().instanceNode(node).instanceLocation(instanceLocation)
139-
.locale(executionContext.getExecutionConfig().getLocale())
140-
.arguments(m.getInstanceLocation().getName(-1))
141-
.property(m.getInstanceLocation().getName(-1))
142-
.failFast(executionContext.isFailFast()).build())
143-
.collect(Collectors.toCollection(LinkedHashSet::new));
144-
}
145135
executionContext.getAnnotations()
146136
.put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation).evaluationPath(this.evaluationPath)
147137
.schemaLocation(this.schemaLocation).keyword(getKeyword()).value(evaluatedProperties).build());

src/main/java/com/networknt/schema/ValidatorTypeCode.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ enum VersionCode {
4444
private final EnumSet<VersionFlag> versions;
4545

4646
VersionCode(SpecVersion.VersionFlag[] versionFlags) {
47-
this.versions = EnumSet.noneOf(VersionFlag.class);
47+
this.versions = EnumSet.noneOf(VersionFlag.class);
4848
for (VersionFlag flag: versionFlags) {
49-
this.versions.add(flag);
49+
this.versions.add(flag);
5050
}
5151
}
5252

@@ -63,12 +63,10 @@ public enum ValidatorTypeCode implements Keyword, ErrorMessageType {
6363
CONTAINS("contains", "1043", ContainsValidator::new, VersionCode.MinV6),
6464
CONTENT_ENCODING("contentEncoding", "1052", ContentEncodingValidator::new, VersionCode.V7),
6565
CONTENT_MEDIA_TYPE("contentMediaType", "1053", ContentMediaTypeValidator::new, VersionCode.V7),
66-
CROSS_EDITS("crossEdits", "1004", null, VersionCode.AllVersions),
6766
DEPENDENCIES("dependencies", "1007", DependenciesValidator::new, VersionCode.AllVersions),
6867
DEPENDENT_REQUIRED("dependentRequired", "1045", DependentRequired::new, VersionCode.MinV201909),
6968
DEPENDENT_SCHEMAS("dependentSchemas", "1046", DependentSchemas::new, VersionCode.MinV201909),
7069
DYNAMIC_REF("$dynamicRef", "1051", DynamicRefValidator::new, VersionCode.MinV202012),
71-
EDITS("edits", "1005", null, VersionCode.AllVersions),
7270
ENUM("enum", "1008", EnumValidator::new, VersionCode.AllVersions),
7371
EXCLUSIVE_MAXIMUM("exclusiveMaximum", "1038", ExclusiveMaximumValidator::new, VersionCode.MinV6),
7472
EXCLUSIVE_MINIMUM("exclusiveMinimum", "1039", ExclusiveMinimumValidator::new, VersionCode.MinV6),
@@ -111,7 +109,6 @@ public enum ValidatorTypeCode implements Keyword, ErrorMessageType {
111109
UNEVALUATED_PROPERTIES("unevaluatedProperties","1047",UnevaluatedPropertiesValidator::new,VersionCode.MinV201909),
112110
UNION_TYPE("unionType", "1030", UnionTypeValidator::new, VersionCode.AllVersions),
113111
UNIQUE_ITEMS("uniqueItems", "1031", UniqueItemsValidator::new, VersionCode.AllVersions),
114-
UUID("uuid", "1035", null, VersionCode.AllVersions),
115112
WRITE_ONLY("writeOnly", "1027", WriteOnlyValidator::new, VersionCode.MinV7),
116113
;
117114

src/main/java/com/networknt/schema/i18n/Locales.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ public class Locales {
3030
/**
3131
* The list of locale resource bundles.
3232
*/
33-
public static final String[] SUPPORTED_LANGUAGE_TAGS = new String[] { "ar-EG", "cs-CZ", "da-DK", "de", "fa-IR",
34-
"fi-FI", "fr-CA", "fr", "he-IL", "hr-HR", "hu-HU", "it", "ja-JP", "ko-KR", "nb-NO", "nl-NL", "pl-PL",
35-
"pt-BR", "ro-RO", "ru-RU", "sk-SK", "sv-SE", "th-TH", "tr-TR", "uk-UA", "vi-VN", "zh-CN", "zh-TW" };
33+
public static final String[] SUPPORTED_LANGUAGE_TAGS = new String[] { "ar", "cs", "da", "de", "fa", "fi", "fr",
34+
"iw", "he", "hr", "hu", "it", "ja", "ko", "nb", "nl", "pl", "pt", "ro", "ru", "sk", "sv", "th", "tr", "uk",
35+
"vi", "zh-CN", "zh-TW" };
3636

3737
/**
3838
* The supported locales.

src/main/resources/jsv-messages.properties

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ additionalItems = {0}: index ''{1}'' is not defined in the schema and the schema
33
additionalProperties = {0}: property ''{1}'' is not defined in the schema and the schema does not allow additional properties
44
allOf = {0}: must be valid to all the schemas {1}
55
anyOf = {0}: must be valid to any of the schemas {1}
6-
const = {0}: must be the constant value {1}
6+
const = {0}: must be the constant value ''{1}''
77
contains = {0}: does not contain an element that passes these validations: {2}
8-
contains.max = {0}: must contain fewer than {1} element(s) that passes these validations: {2}
8+
contains.max = {0}: must contain at most {1} element(s) that passes these validations: {2}
99
contains.min = {0}: must contain at least {1} element(s) that passes these validations: {2}
10-
crossEdits = {0}: has an error with ''cross edits''
1110
dependencies = {0}: has an error with dependencies {1}
12-
dependentRequired = {0}: has a missing property "{1}" which is dependent required because "{2}" is present
11+
dependentRequired = {0}: has a missing property ''{1}'' which is dependent required because ''{2}'' is present
1312
dependentSchemas = {0}: has an error with dependentSchemas {1}
14-
edits = {0}: has an error with ''edits''
1513
enum = {0}: does not have a value in the enumeration {1}
1614
exclusiveMaximum = {0}: must have an exclusive maximum value of {1}
1715
exclusiveMinimum = {0}: must have an exclusive minimum value of {1}
@@ -37,23 +35,24 @@ format.hostname = {0}: does not match the {1} pattern must be a valid RFC 1123 h
3735
format.json-pointer = {0}: does not match the {1} pattern must be a valid RFC 6901 JSON Pointer
3836
format.relative-json-pointer = {0}: does not match the {1} pattern must be a valid IETF Relative JSON Pointer
3937
format.unknown = {0}: has an unknown format ''{1}''
40-
id = {0}: {1} is an invalid segment for URI {2}
38+
id = {0}: ''{1}'' is not a valid {2}
4139
items = {0}: index ''{1}'' is not defined in the schema and the schema does not allow additional items
4240
maxContains = {0}: must be a non-negative integer in {1}
43-
maxItems = {0}: must have a maximum of {1} items in the array
41+
maxItems = {0}: must have at most {1} items but found {2}
4442
maxLength = {0}: must be at most {1} characters long
45-
maxProperties = {0}: must only have a maximum of {1} properties
43+
maxProperties = {0}: must have at most {1} properties
4644
maximum = {0}: must have a maximum value of {1}
4745
minContains = {0}: must be a non-negative integer in {1}
4846
minContainsVsMaxContains = {0}: minContains must less than or equal to maxContains in {1}
49-
minItems = {0}: expected at least {1} items but found {2}
47+
minItems = {0}: must have at least {1} items but found {2}
5048
minLength = {0}: must be at least {1} characters long
51-
minProperties = {0}: must have a minimum of {1} properties
49+
minProperties = {0}: must have at least {1} properties
5250
minimum = {0}: must have a minimum value of {1}
5351
multipleOf = {0}: must be multiple of {1}
5452
not = {0}: must not be valid to the schema {1}
5553
notAllowed = {0}: property ''{1}'' is not allowed but it is in the data
5654
oneOf = {0}: must be valid to one and only one schema, but {1} are valid
55+
oneOf.indexes = {0}: must be valid to one and only one schema, but {1} are valid with indexes ''{2}''
5756
pattern = {0}: does not match the regex pattern {1}
5857
patternProperties = {0}: has some error with ''pattern properties''
5958
prefixItems = {0}: no validator found at this index
@@ -62,11 +61,10 @@ propertyNames = {0}: property ''{1}'' name is not valid: {2}
6261
readOnly = {0}: is a readonly field, it cannot be changed
6362
required = {0}: required property ''{1}'' not found
6463
type = {0}: {1} found, {2} expected
65-
unevaluatedItems = {0}: index ''{1}'' must not be unevaluated or must match unevaluated items schema
66-
unevaluatedProperties = {0}: property ''{1}'' must not be unevaluated
67-
unionType = {0}: {1} found, but {2} is required
68-
uniqueItems = {0}: the items in the array must be unique
69-
uuid = {0}: {1} is an invalid {2}
64+
unevaluatedItems = {0}: index ''{1}'' is not evaluated and the schema does not allow unevaluated items
65+
unevaluatedProperties = {0}: property ''{1}'' is not evaluated and the schema does not allow unevaluated properties
66+
unionType = {0}: {1} found, {2} expected
67+
uniqueItems = {0}: must have only unique items in the array
7068
writeOnly = {0}: is a write-only field, it cannot appear in the data
7169
contentEncoding = {0}: does not match content encoding {1}
72-
contentMediaType = {0}: is not a content media type
70+
contentMediaType = {0}: is not a content media type

0 commit comments

Comments
 (0)