Skip to content

Commit c4840b3

Browse files
committed
Support custom message per property
1 parent 6a7847d commit c4840b3

Some content is hidden

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

47 files changed

+264
-94
lines changed

doc/cust-msg.md

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The json schema itself has a place for the customised message.
66
## Examples
77
### Example 1 :
88
The custom message can be provided outside properties for each type, as shown in the schema below.
9-
````json
9+
```json
1010
{
1111
"type": "object",
1212
"properties": {
@@ -24,10 +24,10 @@ The custom message can be provided outside properties for each type, as shown in
2424
"type" : "Invalid type"
2525
}
2626
}
27-
````
27+
```
2828
### Example 2 :
2929
To keep custom messages distinct for each type, one can even give them in each property.
30-
````json
30+
```json
3131
{
3232
"type": "object",
3333
"properties": {
@@ -47,14 +47,62 @@ To keep custom messages distinct for each type, one can even give them in each p
4747
}
4848
}
4949
}
50-
````
50+
```
51+
### Example 3 :
52+
For the keywords `required` and `dependencies`, different messages can be specified for different properties.
53+
54+
```json
55+
{
56+
"type": "object",
57+
"properties": {
58+
"foo": {
59+
"type": "number"
60+
},
61+
"bar": {
62+
"type": "string"
63+
}
64+
},
65+
"required": ["foo", "bar"],
66+
"message": {
67+
"type" : "should be an object",
68+
"required": {
69+
"foo" : "'foo' is required",
70+
"bar" : "'bar' is required"
71+
}
72+
}
73+
}
74+
```
75+
### Example 4 :
76+
The message can use arguments but note that single quotes need to be escaped as `java.text.MessageFormat` will be used to format the message.
77+
78+
```json
79+
{
80+
"type": "object",
81+
"properties": {
82+
"foo": {
83+
"type": "number"
84+
},
85+
"bar": {
86+
"type": "string"
87+
}
88+
},
89+
"required": ["foo", "bar"],
90+
"message": {
91+
"type" : "should be an object",
92+
"required": {
93+
"foo" : "{0}: ''foo'' is required",
94+
"bar" : "{0}: ''bar'' is required"
95+
}
96+
}
97+
}
98+
```
5199

52100
## Format
53-
````json
101+
```json
54102
"message": {
55103
[validationType] : [customMessage]
56104
}
57-
````
105+
```
58106
Users can express custom message in the **'message'** field.
59107
The **'validation type'** should be the key and the **'custom message'** should be the value.
60108

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
9797

9898
if (!allowedProperties.contains(pname) && !handledByPatternProperties) {
9999
if (!allowAdditionalProperties) {
100-
errors.add(buildValidationMessage(at, executionContext.getExecutionConfig().getLocale(), pname));
100+
errors.add(buildValidationMessage(null, at, executionContext.getExecutionConfig().getLocale(), pname));
101101
} else {
102102
if (additionalPropertiesSchema != null) {
103103
ValidatorState state = (ValidatorState) collectorContext.get(ValidatorState.VALIDATOR_STATE_KEY);

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
7777
//If schema has type validator and node type doesn't match with schemaType then ignore it
7878
//For union type, it is a must to call TypeValidator
7979
if (typeValidator.getSchemaType() != JsonType.UNION && !typeValidator.equalsToSchemaType(node)) {
80-
allErrors.add(buildValidationMessage(at, executionContext.getExecutionConfig().getLocale(),
81-
typeValidator.getSchemaType().toString()));
80+
allErrors.add(buildValidationMessage(null, at,
81+
executionContext.getExecutionConfig().getLocale(), typeValidator.getSchemaType().toString()));
8282
continue;
8383
}
8484
}
@@ -107,8 +107,8 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
107107
if (this.discriminatorContext.isDiscriminatorMatchFound()) {
108108
if (!errors.isEmpty()) {
109109
allErrors.addAll(errors);
110-
allErrors.add(buildValidationMessage(at,
111-
executionContext.getExecutionConfig().getLocale(), DISCRIMINATOR_REMARK));
110+
allErrors.add(buildValidationMessage(null,
111+
at, executionContext.getExecutionConfig().getLocale(), DISCRIMINATOR_REMARK));
112112
} else {
113113
// Clear all errors.
114114
allErrors.clear();
@@ -135,8 +135,8 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
135135

136136
if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators() && this.discriminatorContext.isActive()) {
137137
final Set<ValidationMessage> errors = new HashSet<>();
138-
errors.add(buildValidationMessage(at, executionContext.getExecutionConfig().getLocale(),
139-
"based on the provided discriminator. No alternative could be chosen based on the discriminator property"));
138+
errors.add(buildValidationMessage(null, at,
139+
executionContext.getExecutionConfig().getLocale(), "based on the provided discriminator. No alternative could be chosen based on the discriminator property"));
140140
return Collections.unmodifiableSet(errors);
141141
}
142142
} finally {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
3636

3737
if (schemaNode.isNumber() && node.isNumber()) {
3838
if (schemaNode.decimalValue().compareTo(node.decimalValue()) != 0) {
39-
return Collections.singleton(buildValidationMessage(at,
40-
executionContext.getExecutionConfig().getLocale(), schemaNode.asText()));
39+
return Collections.singleton(buildValidationMessage(null,
40+
at, executionContext.getExecutionConfig().getLocale(), schemaNode.asText()));
4141
}
4242
} else if (!schemaNode.equals(node)) {
4343
return Collections.singleton(
44-
buildValidationMessage(at, executionContext.getExecutionConfig().getLocale(), schemaNode.asText()));
44+
buildValidationMessage(null, at, executionContext.getExecutionConfig().getLocale(), schemaNode.asText()));
4545
}
4646
return Collections.emptySet();
4747
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,6 @@ public void preloadJsonSchema() {
112112
}
113113

114114
private Set<ValidationMessage> boundsViolated(String messageKey, Locale locale, String at, int bounds) {
115-
return Collections.singleton(buildValidationMessage(at, messageKey, locale, String.valueOf(bounds), this.schema.getSchemaNode().toString()));
115+
return Collections.singleton(buildValidationMessage(null, at, messageKey, locale, String.valueOf(bounds), this.schema.getSchemaNode().toString()));
116116
}
117117
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
6262
if (deps != null && !deps.isEmpty()) {
6363
for (String field : deps) {
6464
if (node.get(field) == null) {
65-
errors.add(buildValidationMessage(at, executionContext.getExecutionConfig().getLocale(),
66-
propertyDeps.toString()));
65+
errors.add(buildValidationMessage(pname, at,
66+
executionContext.getExecutionConfig().getLocale(), propertyDeps.toString()));
6767
}
6868
}
6969
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
5656
if (dependencies != null && !dependencies.isEmpty()) {
5757
for (String field : dependencies) {
5858
if (node.get(field) == null) {
59-
errors.add(buildValidationMessage(at, executionContext.getExecutionConfig().getLocale(), field,
60-
pname));
59+
errors.add(buildValidationMessage(pname, at, executionContext.getExecutionConfig().getLocale(),
60+
field, pname));
6161
}
6262
}
6363
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
8282

8383
if (node.isNumber()) node = DecimalNode.valueOf(node.decimalValue());
8484
if (!nodes.contains(node) && !( this.validationContext.getConfig().isTypeLoose() && isTypeLooseContainsInEnum(node))) {
85-
return Collections.singleton(buildValidationMessage(at, executionContext.getExecutionConfig().getLocale(), error));
85+
return Collections.singleton(buildValidationMessage(null, at, executionContext.getExecutionConfig().getLocale(), error));
8686
}
8787

8888
return Collections.emptySet();

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.networknt.schema;
1818

19+
import java.util.Map;
20+
1921
public interface ErrorMessageType {
2022
/**
2123
* Your error code. Please ensure global uniqueness. Builtin error codes are sequential numbers.
@@ -26,7 +28,7 @@ public interface ErrorMessageType {
2628
*/
2729
String getErrorCode();
2830

29-
default String getCustomMessage() {
31+
default Map<String, String> getCustomMessage() {
3032
return null;
3133
}
3234

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNo
107107
}
108108

109109
if (typedMaximum.crossesThreshold(node)) {
110-
return Collections.singleton(buildValidationMessage(at, executionContext.getExecutionConfig().getLocale(),
111-
typedMaximum.thresholdValue()));
110+
return Collections.singleton(buildValidationMessage(null, at,
111+
executionContext.getExecutionConfig().getLocale(), typedMaximum.thresholdValue()));
112112
}
113113
return Collections.emptySet();
114114
}

0 commit comments

Comments
 (0)