Skip to content

Commit bc61ef3

Browse files
authored
Allow customization of assertion for outputunit (#1033)
1 parent d592ac0 commit bc61ef3

File tree

5 files changed

+106
-28
lines changed

5 files changed

+106
-28
lines changed

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

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616
package com.networknt.schema;
1717

1818
import java.util.Set;
19+
import java.util.function.Function;
1920

2021
import com.networknt.schema.output.HierarchicalOutputUnitFormatter;
2122
import com.networknt.schema.output.ListOutputUnitFormatter;
2223
import com.networknt.schema.output.OutputFlag;
2324
import com.networknt.schema.output.OutputUnit;
25+
import com.networknt.schema.output.OutputUnitData;
2426

2527
/**
2628
* Formats the validation results.
@@ -132,29 +134,61 @@ public java.lang.Boolean format(JsonSchema jsonSchema, Set<ValidationMessage> va
132134
* The List output format.
133135
*/
134136
public static class List implements OutputFormat<OutputUnit> {
137+
private final Function<ValidationMessage, Object> assertionMapper;
138+
139+
public List() {
140+
this(OutputUnitData::formatAssertion);
141+
}
142+
143+
/**
144+
* Constructor.
145+
*
146+
* @param assertionMapper to map the assertion
147+
*/
148+
public List(Function<ValidationMessage, Object> assertionMapper) {
149+
this.assertionMapper = assertionMapper;
150+
}
151+
135152
@Override
136153
public void customize(ExecutionContext executionContext, ValidationContext validationContext) {
137154
}
138155

139156
@Override
140157
public OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> validationMessages,
141158
ExecutionContext executionContext, ValidationContext validationContext) {
142-
return ListOutputUnitFormatter.format(validationMessages, executionContext, validationContext);
159+
return ListOutputUnitFormatter.format(validationMessages, executionContext, validationContext,
160+
this.assertionMapper);
143161
}
144162
}
145163

146164
/**
147165
* The Hierarchical output format.
148166
*/
149167
public static class Hierarchical implements OutputFormat<OutputUnit> {
168+
private final Function<ValidationMessage, Object> assertionMapper;
169+
170+
public Hierarchical() {
171+
this(OutputUnitData::formatAssertion);
172+
}
173+
174+
/**
175+
* Constructor.
176+
*
177+
* @param assertionMapper to map the assertion
178+
*/
179+
public Hierarchical(Function<ValidationMessage, Object> assertionMapper) {
180+
this.assertionMapper = assertionMapper;
181+
}
182+
150183
@Override
151184
public void customize(ExecutionContext executionContext, ValidationContext validationContext) {
152185
}
153186

154187
@Override
155188
public OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> validationMessages,
156189
ExecutionContext executionContext, ValidationContext validationContext) {
157-
return HierarchicalOutputUnitFormatter.format(jsonSchema, validationMessages, executionContext, validationContext);
190+
return HierarchicalOutputUnitFormatter.format(jsonSchema, validationMessages, executionContext,
191+
validationContext, this.assertionMapper);
158192
}
159193
}
160194
}

src/main/java/com/networknt/schema/output/HierarchicalOutputUnitFormatter.java

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.LinkedHashSet;
2323
import java.util.Map;
2424
import java.util.Map.Entry;
25+
import java.util.function.Function;
2526
import java.util.Set;
2627

2728
import com.networknt.schema.ExecutionContext;
@@ -34,18 +35,7 @@
3435
* HierarchicalOutputUnitFormatter.
3536
*/
3637
public class HierarchicalOutputUnitFormatter {
37-
public static OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> validationMessages,
38-
ExecutionContext executionContext, ValidationContext validationContext) {
39-
40-
OutputUnit root = new OutputUnit();
41-
root.setValid(validationMessages.isEmpty());
42-
43-
root.setInstanceLocation(validationContext.getConfig().getPathType().getRoot());
44-
root.setEvaluationPath(validationContext.getConfig().getPathType().getRoot());
45-
root.setSchemaLocation(jsonSchema.getSchemaLocation().toString());
46-
47-
OutputUnitData data = OutputUnitData.from(validationMessages, executionContext);
48-
38+
public static OutputUnit format(OutputUnit root, OutputUnitData data, JsonNodePath rootPath) {
4939
Map<OutputUnitKey, Boolean> valid = data.getValid();
5040
Map<OutputUnitKey, Map<String, Object>> errors = data.getErrors();
5141
Map<OutputUnitKey, Map<String, Object>> annotations = data.getAnnotations();
@@ -54,8 +44,8 @@ public static OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> va
5444
// Evaluation path to output unit
5545
Map<JsonNodePath, Map<JsonNodePath, OutputUnit>> index = new LinkedHashMap<>();
5646
Map<JsonNodePath, OutputUnit> r = new LinkedHashMap<>();
57-
r.put(new JsonNodePath(validationContext.getConfig().getPathType()), root);
58-
index.put(new JsonNodePath(validationContext.getConfig().getPathType()), r);
47+
r.put(rootPath, root);
48+
index.put(rootPath, r);
5949

6050
// Get all the evaluation paths with data
6151
// This is a map of evaluation path to instance location
@@ -116,6 +106,21 @@ public static OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> va
116106
}
117107
return root;
118108
}
109+
110+
public static OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> validationMessages,
111+
ExecutionContext executionContext, ValidationContext validationContext,
112+
Function<ValidationMessage, Object> assertionMapper) {
113+
OutputUnit root = new OutputUnit();
114+
root.setValid(validationMessages.isEmpty());
115+
116+
root.setInstanceLocation(validationContext.getConfig().getPathType().getRoot());
117+
root.setEvaluationPath(validationContext.getConfig().getPathType().getRoot());
118+
root.setSchemaLocation(jsonSchema.getSchemaLocation().toString());
119+
120+
OutputUnitData data = OutputUnitData.from(validationMessages, executionContext, assertionMapper);
121+
122+
return format(root, data, new JsonNodePath(validationContext.getConfig().getPathType()));
123+
}
119124

120125
/**
121126
* Builds in the index of evaluation path to output units to be populated later

src/main/java/com/networknt/schema/output/ListOutputUnitFormatter.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.List;
2121
import java.util.Map;
2222
import java.util.Map.Entry;
23+
import java.util.function.Function;
2324
import java.util.Set;
2425

2526
import com.networknt.schema.ExecutionContext;
@@ -30,13 +31,7 @@
3031
* ListOutputUnitFormatter.
3132
*/
3233
public class ListOutputUnitFormatter {
33-
public static OutputUnit format(Set<ValidationMessage> validationMessages, ExecutionContext executionContext,
34-
ValidationContext validationContext) {
35-
OutputUnit root = new OutputUnit();
36-
root.setValid(validationMessages.isEmpty());
37-
38-
OutputUnitData data = OutputUnitData.from(validationMessages, executionContext);
39-
34+
public static OutputUnit format(OutputUnit root, OutputUnitData data) {
4035
Map<OutputUnitKey, Boolean> valid = data.getValid();
4136
Map<OutputUnitKey, Map<String, Object>> errors = data.getErrors();
4237
Map<OutputUnitKey, Map<String, Object>> annotations = data.getAnnotations();
@@ -95,4 +90,11 @@ public static OutputUnit format(Set<ValidationMessage> validationMessages, Execu
9590

9691
return root;
9792
}
93+
94+
public static OutputUnit format(Set<ValidationMessage> validationMessages, ExecutionContext executionContext,
95+
ValidationContext validationContext, Function<ValidationMessage, Object> assertionMapper) {
96+
OutputUnit root = new OutputUnit();
97+
root.setValid(validationMessages.isEmpty());
98+
return format(root, OutputUnitData.from(validationMessages, executionContext, assertionMapper));
99+
}
98100
}

src/main/java/com/networknt/schema/output/OutputUnitData.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.List;
2121
import java.util.Map;
2222
import java.util.Set;
23+
import java.util.function.Function;
2324

2425
import com.networknt.schema.ExecutionContext;
2526
import com.networknt.schema.SchemaLocation;
@@ -51,6 +52,10 @@ public Map<OutputUnitKey, Map<String, Object>> getDroppedAnnotations() {
5152
return droppedAnnotations;
5253
}
5354

55+
public static String formatAssertion(ValidationMessage validationMessage) {
56+
return formatMessage(validationMessage.getMessage());
57+
}
58+
5459
public static String formatMessage(String message) {
5560
int index = message.indexOf(":");
5661
if (index != -1) {
@@ -68,7 +73,8 @@ public static String formatMessage(String message) {
6873
}
6974

7075
@SuppressWarnings("unchecked")
71-
public static OutputUnitData from(Set<ValidationMessage> validationMessages, ExecutionContext executionContext) {
76+
public static OutputUnitData from(Set<ValidationMessage> validationMessages, ExecutionContext executionContext,
77+
Function<ValidationMessage, Object> assertionMapper) {
7278
OutputUnitData data = new OutputUnitData();
7379

7480
Map<OutputUnitKey, Boolean> valid = data.valid;
@@ -85,15 +91,15 @@ public static OutputUnitData from(Set<ValidationMessage> validationMessages, Exe
8591
Map<String, Object> errorMap = errors.computeIfAbsent(key, k -> new LinkedHashMap<>());
8692
Object value = errorMap.get(assertion.getType());
8793
if (value == null) {
88-
errorMap.put(assertion.getType(), formatMessage(assertion.getMessage()));
94+
errorMap.put(assertion.getType(), assertionMapper.apply(assertion));
8995
} else {
9096
// Existing error, make it into a list
9197
if (value instanceof List) {
92-
((List<String>) value).add(formatMessage(assertion.getMessage()));
98+
((List<Object>) value).add(assertionMapper.apply(assertion));
9399
} else {
94-
List<String> values = new ArrayList<>();
100+
List<Object> values = new ArrayList<>();
95101
values.add(value.toString());
96-
values.add(formatMessage(assertion.getMessage()));
102+
values.add(assertionMapper.apply(assertion));
97103
errorMap.put(assertion.getType(), values);
98104
}
99105
}

src/test/java/com/networknt/schema/OutputUnitTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static org.junit.jupiter.api.Assertions.assertEquals;
1919
import static org.junit.jupiter.api.Assertions.assertFalse;
20+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
2021
import static org.junit.jupiter.api.Assertions.assertNotNull;
2122
import static org.junit.jupiter.api.Assertions.assertTrue;
2223

@@ -339,4 +340,34 @@ void anyOf() throws JsonProcessingException {
339340
assertEquals(expected, output);
340341
}
341342

343+
@Test
344+
void listAssertionMapper() {
345+
String formatSchema = "{\r\n"
346+
+ " \"type\": \"string\"\r\n"
347+
+ "}";
348+
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012);
349+
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
350+
config.setPathType(PathType.JSON_POINTER);
351+
JsonSchema schema = factory.getSchema(formatSchema, config);
352+
OutputUnit outputUnit = schema.validate("1234", InputFormat.JSON, new OutputFormat.List(a -> a));
353+
assertFalse(outputUnit.isValid());
354+
OutputUnit details = outputUnit.getDetails().get(0);
355+
Object assertion = details.getErrors().get("type");
356+
assertInstanceOf(ValidationMessage.class, assertion);
357+
}
358+
359+
@Test
360+
void hierarchicalAssertionMapper() {
361+
String formatSchema = "{\r\n"
362+
+ " \"type\": \"string\"\r\n"
363+
+ "}";
364+
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012);
365+
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
366+
config.setPathType(PathType.JSON_POINTER);
367+
JsonSchema schema = factory.getSchema(formatSchema, config);
368+
OutputUnit outputUnit = schema.validate("1234", InputFormat.JSON, new OutputFormat.Hierarchical(a -> a));
369+
assertFalse(outputUnit.isValid());
370+
Object assertion = outputUnit.getErrors().get("type");
371+
assertInstanceOf(ValidationMessage.class, assertion);
372+
}
342373
}

0 commit comments

Comments
 (0)