Skip to content

Commit 19b2207

Browse files
authored
Refactor and remove validation message handler (#1196)
1 parent db71780 commit 19b2207

File tree

12 files changed

+452
-441
lines changed

12 files changed

+452
-441
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ protected Set<ValidationMessage> validate(ExecutionContext executionContext, Jso
8989
final ObjectNode discriminator = currentDiscriminatorContext
9090
.getDiscriminatorForPath(allOfEntry.get("$ref").asText());
9191
if (null != discriminator) {
92-
registerAndMergeDiscriminator(currentDiscriminatorContext, discriminator,
92+
DiscriminatorValidator.registerAndMergeDiscriminator(currentDiscriminatorContext, discriminator,
9393
this.parentSchema, instanceLocation);
9494
// now we have to check whether we have hit the right target
9595
final String discriminatorPropertyName = discriminator.get("propertyName").asText();
@@ -98,7 +98,7 @@ protected Set<ValidationMessage> validate(ExecutionContext executionContext, Jso
9898
: discriminatorNode.textValue();
9999

100100
final JsonSchema jsonSchema = this.parentSchema;
101-
checkDiscriminatorMatch(currentDiscriminatorContext, discriminator,
101+
DiscriminatorValidator.checkDiscriminatorMatch(currentDiscriminatorContext, discriminator,
102102
discriminatorPropertyValue, jsonSchema);
103103
}
104104
}

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

Lines changed: 44 additions & 219 deletions
Large diffs are not rendered by default.

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

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,127 @@ public String getPropertyName() {
8181
public Map<String, String> getMapping() {
8282
return mapping;
8383
}
84+
85+
/**
86+
* Checks based on the current {@link DiscriminatorContext} whether the provided {@link JsonSchema} a match against
87+
* the current discriminator.
88+
*
89+
* @param currentDiscriminatorContext the currently active {@link DiscriminatorContext}
90+
* @param discriminator the discriminator to use for the check
91+
* @param discriminatorPropertyValue the value of the <code>discriminator/propertyName</code> field
92+
* @param jsonSchema the {@link JsonSchema} to check
93+
*/
94+
public static void checkDiscriminatorMatch(final DiscriminatorContext currentDiscriminatorContext,
95+
final ObjectNode discriminator,
96+
final String discriminatorPropertyValue,
97+
final JsonSchema jsonSchema) {
98+
if (discriminatorPropertyValue == null) {
99+
currentDiscriminatorContext.markIgnore();
100+
return;
101+
}
102+
103+
final JsonNode discriminatorMapping = discriminator.get("mapping");
104+
if (null == discriminatorMapping) {
105+
checkForImplicitDiscriminatorMappingMatch(currentDiscriminatorContext,
106+
discriminatorPropertyValue,
107+
jsonSchema);
108+
} else {
109+
checkForExplicitDiscriminatorMappingMatch(currentDiscriminatorContext,
110+
discriminatorPropertyValue,
111+
discriminatorMapping,
112+
jsonSchema);
113+
if (!currentDiscriminatorContext.isDiscriminatorMatchFound()
114+
&& noExplicitDiscriminatorKeyOverride(discriminatorMapping, jsonSchema)) {
115+
checkForImplicitDiscriminatorMappingMatch(currentDiscriminatorContext,
116+
discriminatorPropertyValue,
117+
jsonSchema);
118+
}
119+
}
120+
}
121+
122+
/**
123+
* Rolls up all nested and compatible discriminators to the root discriminator of the type. Detects attempts to redefine
124+
* the <code>propertyName</code> or mappings.
125+
*
126+
* @param currentDiscriminatorContext the currently active {@link DiscriminatorContext}
127+
* @param discriminator the discriminator to use for the check
128+
* @param schema the value of the <code>discriminator/propertyName</code> field
129+
* @param instanceLocation the logging prefix
130+
*/
131+
public static void registerAndMergeDiscriminator(final DiscriminatorContext currentDiscriminatorContext,
132+
final ObjectNode discriminator,
133+
final JsonSchema schema,
134+
final JsonNodePath instanceLocation) {
135+
final JsonNode discriminatorOnSchema = schema.schemaNode.get("discriminator");
136+
if (null != discriminatorOnSchema && null != currentDiscriminatorContext
137+
.getDiscriminatorForPath(schema.schemaLocation)) {
138+
// this is where A -> B -> C inheritance exists, A has the root discriminator and B adds to the mapping
139+
final JsonNode propertyName = discriminatorOnSchema.get("propertyName");
140+
if (null != propertyName) {
141+
throw new JsonSchemaException(instanceLocation + " schema " + schema + " attempts redefining the discriminator property");
142+
}
143+
final ObjectNode mappingOnContextDiscriminator = (ObjectNode) discriminator.get("mapping");
144+
final ObjectNode mappingOnCurrentSchemaDiscriminator = (ObjectNode) discriminatorOnSchema.get("mapping");
145+
if (null == mappingOnContextDiscriminator && null != mappingOnCurrentSchemaDiscriminator) {
146+
// here we have a mapping on a nested discriminator and none on the root discriminator, so we can simply
147+
// make it the root's
148+
discriminator.set("mapping", discriminatorOnSchema);
149+
} else if (null != mappingOnContextDiscriminator && null != mappingOnCurrentSchemaDiscriminator) {
150+
// here we have to merge. The spec doesn't specify anything on this, but here we don't accept redefinition of
151+
// mappings that already exist
152+
final Iterator<Map.Entry<String, JsonNode>> fieldsToAdd = mappingOnCurrentSchemaDiscriminator.fields();
153+
while (fieldsToAdd.hasNext()) {
154+
final Map.Entry<String, JsonNode> fieldToAdd = fieldsToAdd.next();
155+
final String mappingKeyToAdd = fieldToAdd.getKey();
156+
final JsonNode mappingValueToAdd = fieldToAdd.getValue();
157+
158+
final JsonNode currentMappingValue = mappingOnContextDiscriminator.get(mappingKeyToAdd);
159+
if (null != currentMappingValue && currentMappingValue != mappingValueToAdd) {
160+
throw new JsonSchemaException(instanceLocation + "discriminator mapping redefinition from " + mappingKeyToAdd
161+
+ "/" + currentMappingValue + " to " + mappingValueToAdd);
162+
} else if (null == currentMappingValue) {
163+
mappingOnContextDiscriminator.set(mappingKeyToAdd, mappingValueToAdd);
164+
}
165+
}
166+
}
167+
}
168+
currentDiscriminatorContext.registerDiscriminator(schema.schemaLocation, discriminator);
169+
}
170+
171+
private static void checkForImplicitDiscriminatorMappingMatch(final DiscriminatorContext currentDiscriminatorContext,
172+
final String discriminatorPropertyValue,
173+
final JsonSchema schema) {
174+
if (schema.schemaLocation.getFragment().getName(-1).equals(discriminatorPropertyValue)) {
175+
currentDiscriminatorContext.markMatch();
176+
}
177+
}
178+
179+
private static void checkForExplicitDiscriminatorMappingMatch(final DiscriminatorContext currentDiscriminatorContext,
180+
final String discriminatorPropertyValue,
181+
final JsonNode discriminatorMapping,
182+
final JsonSchema schema) {
183+
final Iterator<Map.Entry<String, JsonNode>> explicitMappings = discriminatorMapping.fields();
184+
while (explicitMappings.hasNext()) {
185+
final Map.Entry<String, JsonNode> candidateExplicitMapping = explicitMappings.next();
186+
if (candidateExplicitMapping.getKey().equals(discriminatorPropertyValue)
187+
&& ("#" + schema.schemaLocation.getFragment().toString())
188+
.equals(candidateExplicitMapping.getValue().asText())) {
189+
currentDiscriminatorContext.markMatch();
190+
break;
191+
}
192+
}
193+
}
194+
195+
private static boolean noExplicitDiscriminatorKeyOverride(final JsonNode discriminatorMapping,
196+
final JsonSchema parentSchema) {
197+
final Iterator<Map.Entry<String, JsonNode>> explicitMappings = discriminatorMapping.fields();
198+
while (explicitMappings.hasNext()) {
199+
final Map.Entry<String, JsonNode> candidateExplicitMapping = explicitMappings.next();
200+
if (candidateExplicitMapping.getValue().asText()
201+
.equals(parentSchema.schemaLocation.getFragment().toString())) {
202+
return false;
203+
}
204+
}
205+
return true;
206+
}
84207
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.networknt.schema;
2+
3+
import java.util.Collections;
4+
import java.util.LinkedHashMap;
5+
import java.util.Map;
6+
7+
import com.fasterxml.jackson.databind.JsonNode;
8+
9+
/**
10+
* ErrorMessages.
11+
*/
12+
public class ErrorMessages {
13+
/**
14+
* Gets the custom error message to use.
15+
*
16+
* @param parentSchema the parent schema
17+
* @param errorMessageKeyword the error message keyword
18+
* @param keyword the keyword
19+
* @return the custom error message
20+
*/
21+
public static Map<String, String> getErrorMessage(JsonSchema parentSchema, String errorMessageKeyword,
22+
String keyword) {
23+
final JsonNode message = getMessageNode(errorMessageKeyword, parentSchema.schemaNode, parentSchema, keyword);
24+
if (message != null) {
25+
JsonNode messageNode = message.get(keyword);
26+
if (messageNode != null) {
27+
if (messageNode.isTextual()) {
28+
return Collections.singletonMap("", messageNode.asText());
29+
} else if (messageNode.isObject()) {
30+
Map<String, String> result = new LinkedHashMap<>();
31+
messageNode.fields()
32+
.forEachRemaining(entry -> result.put(entry.getKey(), entry.getValue().textValue()));
33+
if (!result.isEmpty()) {
34+
return result;
35+
}
36+
}
37+
}
38+
}
39+
return Collections.emptyMap();
40+
}
41+
42+
protected static JsonNode getMessageNode(String errorMessageKeyword, JsonNode schemaNode, JsonSchema parentSchema,
43+
String pname) {
44+
if (schemaNode.get(errorMessageKeyword) != null && schemaNode.get(errorMessageKeyword).get(pname) != null) {
45+
return schemaNode.get(errorMessageKeyword);
46+
}
47+
JsonNode messageNode;
48+
messageNode = schemaNode.get(errorMessageKeyword);
49+
if (messageNode == null && parentSchema != null) {
50+
messageNode = parentSchema.schemaNode.get(errorMessageKeyword);
51+
if (messageNode == null) {
52+
return getMessageNode(errorMessageKeyword, parentSchema.schemaNode, parentSchema.getParentSchema(),
53+
pname);
54+
}
55+
}
56+
return messageNode;
57+
}
58+
}

0 commit comments

Comments
 (0)