Skip to content

Commit 7e9375f

Browse files
authored
Add schemaPath to ValidationMessage. (#552)
Co-authored-by: Ziqian Zhang <[email protected]>
1 parent e68be00 commit 7e9375f

File tree

11 files changed

+152
-9
lines changed

11 files changed

+152
-9
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ public Set<ValidationMessage> validate(JsonNode node) {
3434
}
3535

3636
protected ValidationMessage buildValidationMessage(ErrorMessageType errorMessageType, String at, String... arguments) {
37-
return ValidationMessage.of(keyword, errorMessageType, at, arguments);
37+
return ValidationMessage.of(keyword, errorMessageType, at, null, arguments);
3838
}
3939

4040
protected ValidationMessage buildValidationMessage(ErrorMessageType errorMessageType, String at, Map<String, Object> details) {
41-
return ValidationMessage.of(keyword, errorMessageType, at, details);
41+
return ValidationMessage.of(keyword, errorMessageType, at, null, details);
4242
}
4343

4444
protected Set<ValidationMessage> pass() {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ protected void parseErrorCode(String errorCodeKey) {
137137
}
138138

139139
protected ValidationMessage buildValidationMessage(String at, String... arguments) {
140-
final ValidationMessage message = ValidationMessage.of(getValidatorType().getValue(), errorMessageType, at, arguments);
140+
final ValidationMessage message = ValidationMessage.of(getValidatorType().getValue(), errorMessageType, at, schemaPath, arguments);
141141
if (failFast && !isPartOfOneOfMultipleType()) {
142142
throw new JsonSchemaException(message);
143143
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ private URI combineCurrentUriWithIds(URI currentUri, JsonNode schemaNode) {
108108
throw new JsonSchemaException(ValidationMessage.of(ValidatorTypeCode.ID.getValue(),
109109
ValidatorTypeCode.ID,
110110
id,
111+
schemaPath,
111112
currentUri == null ? "null" : currentUri.toString()));
112113
}
113114
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ private ValidationMessage getMultiSchemasValidErrorMsg(String at){
312312
msg = msg.concat(schemaValue);
313313
}
314314

315-
return ValidationMessage.of(getValidatorType().getValue(), ValidatorTypeCode.ONE_OF, at, msg);
315+
return ValidationMessage.of(getValidatorType().getValue(), ValidatorTypeCode.ONE_OF, at, schemaPath, msg);
316316
}
317317

318318
@Override

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public RefValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSch
4646
if (schema == null) {
4747
throw new JsonSchemaException(
4848
ValidationMessage.of(ValidatorTypeCode.REF.getValue(),
49-
CustomErrorMessageType.of("internal.unresolvedRef", new MessageFormat("{0}: Reference {1} cannot be resolved")), schemaPath, refValue));
49+
CustomErrorMessageType.of("internal.unresolvedRef", new MessageFormat("{0}: Reference {1} cannot be resolved")), schemaPath, schemaPath, refValue));
5050
}
5151
}
5252

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

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class ValidationMessage {
2626
private String type;
2727
private String code;
2828
private String path;
29+
private String schemaPath;
2930
private String[] arguments;
3031
private Map<String, Object> details;
3132
private String message;
@@ -41,6 +42,9 @@ void setCode(String code) {
4142
this.code = code;
4243
}
4344

45+
/**
46+
* @return The path to the input json
47+
*/
4448
public String getPath() {
4549
return path;
4650
}
@@ -49,6 +53,17 @@ void setPath(String path) {
4953
this.path = path;
5054
}
5155

56+
/**
57+
* @return The path to the schema
58+
*/
59+
public String getSchemaPath() {
60+
return schemaPath;
61+
}
62+
63+
public void setSchemaPath(String schemaPath) {
64+
this.schemaPath = schemaPath;
65+
}
66+
5267
public String[] getArguments() {
5368
return arguments;
5469
}
@@ -88,6 +103,7 @@ public boolean equals(Object o) {
88103
if (type != null ? !type.equals(that.type) : that.type != null) return false;
89104
if (code != null ? !code.equals(that.code) : that.code != null) return false;
90105
if (path != null ? !path.equals(that.path) : that.path != null) return false;
106+
if (schemaPath != null ? !schemaPath.equals(that.schemaPath) : that.schemaPath != null) return false;
91107
if (details != null ? !details.equals(that.details) : that.details != null) return false;
92108
if (!Arrays.equals(arguments, that.arguments)) return false;
93109
return !(message != null ? !message.equals(that.message) : that.message != null);
@@ -99,6 +115,7 @@ public int hashCode() {
99115
int result = type != null ? type.hashCode() : 0;
100116
result = 31 * result + (code != null ? code.hashCode() : 0);
101117
result = 31 * result + (path != null ? path.hashCode() : 0);
118+
result = 31 * result + (schemaPath != null ? schemaPath.hashCode() : 0);
102119
result = 31 * result + (details != null ? details.hashCode() : 0);
103120
result = 31 * result + (arguments != null ? Arrays.hashCode(arguments) : 0);
104121
result = 31 * result + (message != null ? message.hashCode() : 0);
@@ -113,17 +130,17 @@ public void setType(String type) {
113130
this.type = type;
114131
}
115132

116-
public static ValidationMessage of(String type, ErrorMessageType errorMessageType, String at, String... arguments) {
133+
public static ValidationMessage of(String type, ErrorMessageType errorMessageType, String at, String schemaPath, String... arguments) {
117134
ValidationMessage.Builder builder = new ValidationMessage.Builder();
118-
builder.code(errorMessageType.getErrorCode()).path(at).arguments(arguments)
135+
builder.code(errorMessageType.getErrorCode()).path(at).schemaPath(schemaPath).arguments(arguments)
119136
.format(errorMessageType.getMessageFormat()).type(type)
120137
.customMessage(errorMessageType.getCustomMessage());
121138
return builder.build();
122139
}
123140

124-
public static ValidationMessage of(String type, ErrorMessageType errorMessageType, String at, Map<String, Object> details) {
141+
public static ValidationMessage of(String type, ErrorMessageType errorMessageType, String at, String schemaPath, Map<String, Object> details) {
125142
ValidationMessage.Builder builder = new ValidationMessage.Builder();
126-
builder.code(errorMessageType.getErrorCode()).path(at).details(details)
143+
builder.code(errorMessageType.getErrorCode()).path(at).schemaPath(schemaPath).details(details)
127144
.format(errorMessageType.getMessageFormat()).type(type);
128145
return builder.build();
129146
}
@@ -132,6 +149,7 @@ public static class Builder {
132149
private String type;
133150
private String code;
134151
private String path;
152+
private String schemaPath;
135153
private String[] arguments;
136154
private Map<String, Object> details;
137155
private MessageFormat format;
@@ -152,6 +170,11 @@ public Builder path(String path) {
152170
return this;
153171
}
154172

173+
public Builder schemaPath(String schemaPath) {
174+
this.schemaPath = schemaPath;
175+
return this;
176+
}
177+
155178
public Builder arguments(String... arguments) {
156179
this.arguments = arguments;
157180
return this;
@@ -177,6 +200,7 @@ public ValidationMessage build() {
177200
msg.setType(type);
178201
msg.setCode(code);
179202
msg.setPath(path);
203+
msg.setSchemaPath(schemaPath);
180204
msg.setArguments(arguments);
181205
msg.setDetails(details);
182206

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.networknt.schema;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import org.junit.jupiter.api.Assertions;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.io.InputStream;
9+
import java.util.Set;
10+
11+
12+
public class Issue550Test {
13+
protected JsonSchema getJsonSchemaFromStreamContentV7(String schemaPath) {
14+
InputStream schemaContent = getClass().getResourceAsStream(schemaPath);
15+
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7);
16+
return factory.getSchema(schemaContent);
17+
}
18+
19+
protected JsonNode getJsonNodeFromStreamContent(String dataPath) throws Exception {
20+
InputStream content = getClass().getResourceAsStream(dataPath);
21+
ObjectMapper mapper = new ObjectMapper();
22+
JsonNode node = mapper.readTree(content);
23+
return node;
24+
}
25+
26+
@Test
27+
void testValidationMessageDoContainSchemaPath() throws Exception {
28+
String schemaPath = "/schema/issue500_1-v7.json";
29+
String dataPath = "/data/issue500_1.json";
30+
JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaPath);
31+
JsonNode node = getJsonNodeFromStreamContent(dataPath);
32+
33+
Set<ValidationMessage> errors = schema.validate(node);
34+
ValidationMessage validationMessage = errors.stream().findFirst().get();
35+
36+
Assertions.assertEquals("#/properties/age/minimum", validationMessage.getSchemaPath());
37+
Assertions.assertEquals(1, errors.size());
38+
}
39+
40+
@Test
41+
void testValidationMessageDoContainSchemaPathForOneOf() throws Exception {
42+
String schemaPath = "/schema/issue500_2-v7.json";
43+
String dataPath = "/data/issue500_2.json";
44+
JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaPath);
45+
JsonNode node = getJsonNodeFromStreamContent(dataPath);
46+
47+
Set<ValidationMessage> errors = schema.validate(node);
48+
ValidationMessage validationMessage = errors.stream().findFirst().get();
49+
50+
// Instead of capturing all subSchema within oneOf, a pointer to oneOf should be provided.
51+
Assertions.assertEquals("#/oneOf", validationMessage.getSchemaPath());
52+
Assertions.assertEquals(1, errors.size());
53+
}
54+
55+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"firstName": "John",
3+
"lastName": "Doe",
4+
"age": -21
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"firstName": "John",
3+
"lastName": "Doe",
4+
"age": 15
5+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"$id": "https://example.com/person.schema.json",
3+
"$schema": "http://json-schema.org/draft-07/schema#",
4+
"title": "Person",
5+
"type": "object",
6+
"properties": {
7+
"firstName": {
8+
"type": "string"
9+
},
10+
"lastName": {
11+
"type": "string"
12+
},
13+
"age": {
14+
"type": "integer",
15+
"minimum": 0
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)