Skip to content

Commit

Permalink
Allow customization of assertion for outputunit (#1033)
Browse files Browse the repository at this point in the history
  • Loading branch information
justin-tay authored May 1, 2024
1 parent d592ac0 commit bc61ef3
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 28 deletions.
38 changes: 36 additions & 2 deletions src/main/java/com/networknt/schema/OutputFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
package com.networknt.schema;

import java.util.Set;
import java.util.function.Function;

import com.networknt.schema.output.HierarchicalOutputUnitFormatter;
import com.networknt.schema.output.ListOutputUnitFormatter;
import com.networknt.schema.output.OutputFlag;
import com.networknt.schema.output.OutputUnit;
import com.networknt.schema.output.OutputUnitData;

/**
* Formats the validation results.
Expand Down Expand Up @@ -132,29 +134,61 @@ public java.lang.Boolean format(JsonSchema jsonSchema, Set<ValidationMessage> va
* The List output format.
*/
public static class List implements OutputFormat<OutputUnit> {
private final Function<ValidationMessage, Object> assertionMapper;

public List() {
this(OutputUnitData::formatAssertion);
}

/**
* Constructor.
*
* @param assertionMapper to map the assertion
*/
public List(Function<ValidationMessage, Object> assertionMapper) {
this.assertionMapper = assertionMapper;
}

@Override
public void customize(ExecutionContext executionContext, ValidationContext validationContext) {
}

@Override
public OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> validationMessages,
ExecutionContext executionContext, ValidationContext validationContext) {
return ListOutputUnitFormatter.format(validationMessages, executionContext, validationContext);
return ListOutputUnitFormatter.format(validationMessages, executionContext, validationContext,
this.assertionMapper);
}
}

/**
* The Hierarchical output format.
*/
public static class Hierarchical implements OutputFormat<OutputUnit> {
private final Function<ValidationMessage, Object> assertionMapper;

public Hierarchical() {
this(OutputUnitData::formatAssertion);
}

/**
* Constructor.
*
* @param assertionMapper to map the assertion
*/
public Hierarchical(Function<ValidationMessage, Object> assertionMapper) {
this.assertionMapper = assertionMapper;
}

@Override
public void customize(ExecutionContext executionContext, ValidationContext validationContext) {
}

@Override
public OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> validationMessages,
ExecutionContext executionContext, ValidationContext validationContext) {
return HierarchicalOutputUnitFormatter.format(jsonSchema, validationMessages, executionContext, validationContext);
return HierarchicalOutputUnitFormatter.format(jsonSchema, validationMessages, executionContext,
validationContext, this.assertionMapper);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.Set;

import com.networknt.schema.ExecutionContext;
Expand All @@ -34,18 +35,7 @@
* HierarchicalOutputUnitFormatter.
*/
public class HierarchicalOutputUnitFormatter {
public static OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> validationMessages,
ExecutionContext executionContext, ValidationContext validationContext) {

OutputUnit root = new OutputUnit();
root.setValid(validationMessages.isEmpty());

root.setInstanceLocation(validationContext.getConfig().getPathType().getRoot());
root.setEvaluationPath(validationContext.getConfig().getPathType().getRoot());
root.setSchemaLocation(jsonSchema.getSchemaLocation().toString());

OutputUnitData data = OutputUnitData.from(validationMessages, executionContext);

public static OutputUnit format(OutputUnit root, OutputUnitData data, JsonNodePath rootPath) {
Map<OutputUnitKey, Boolean> valid = data.getValid();
Map<OutputUnitKey, Map<String, Object>> errors = data.getErrors();
Map<OutputUnitKey, Map<String, Object>> annotations = data.getAnnotations();
Expand All @@ -54,8 +44,8 @@ public static OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> va
// Evaluation path to output unit
Map<JsonNodePath, Map<JsonNodePath, OutputUnit>> index = new LinkedHashMap<>();
Map<JsonNodePath, OutputUnit> r = new LinkedHashMap<>();
r.put(new JsonNodePath(validationContext.getConfig().getPathType()), root);
index.put(new JsonNodePath(validationContext.getConfig().getPathType()), r);
r.put(rootPath, root);
index.put(rootPath, r);

// Get all the evaluation paths with data
// This is a map of evaluation path to instance location
Expand Down Expand Up @@ -116,6 +106,21 @@ public static OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> va
}
return root;
}

public static OutputUnit format(JsonSchema jsonSchema, Set<ValidationMessage> validationMessages,
ExecutionContext executionContext, ValidationContext validationContext,
Function<ValidationMessage, Object> assertionMapper) {
OutputUnit root = new OutputUnit();
root.setValid(validationMessages.isEmpty());

root.setInstanceLocation(validationContext.getConfig().getPathType().getRoot());
root.setEvaluationPath(validationContext.getConfig().getPathType().getRoot());
root.setSchemaLocation(jsonSchema.getSchemaLocation().toString());

OutputUnitData data = OutputUnitData.from(validationMessages, executionContext, assertionMapper);

return format(root, data, new JsonNodePath(validationContext.getConfig().getPathType()));
}

/**
* Builds in the index of evaluation path to output units to be populated later
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.Set;

import com.networknt.schema.ExecutionContext;
Expand All @@ -30,13 +31,7 @@
* ListOutputUnitFormatter.
*/
public class ListOutputUnitFormatter {
public static OutputUnit format(Set<ValidationMessage> validationMessages, ExecutionContext executionContext,
ValidationContext validationContext) {
OutputUnit root = new OutputUnit();
root.setValid(validationMessages.isEmpty());

OutputUnitData data = OutputUnitData.from(validationMessages, executionContext);

public static OutputUnit format(OutputUnit root, OutputUnitData data) {
Map<OutputUnitKey, Boolean> valid = data.getValid();
Map<OutputUnitKey, Map<String, Object>> errors = data.getErrors();
Map<OutputUnitKey, Map<String, Object>> annotations = data.getAnnotations();
Expand Down Expand Up @@ -95,4 +90,11 @@ public static OutputUnit format(Set<ValidationMessage> validationMessages, Execu

return root;
}

public static OutputUnit format(Set<ValidationMessage> validationMessages, ExecutionContext executionContext,
ValidationContext validationContext, Function<ValidationMessage, Object> assertionMapper) {
OutputUnit root = new OutputUnit();
root.setValid(validationMessages.isEmpty());
return format(root, OutputUnitData.from(validationMessages, executionContext, assertionMapper));
}
}
16 changes: 11 additions & 5 deletions src/main/java/com/networknt/schema/output/OutputUnitData.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

import com.networknt.schema.ExecutionContext;
import com.networknt.schema.SchemaLocation;
Expand Down Expand Up @@ -51,6 +52,10 @@ public Map<OutputUnitKey, Map<String, Object>> getDroppedAnnotations() {
return droppedAnnotations;
}

public static String formatAssertion(ValidationMessage validationMessage) {
return formatMessage(validationMessage.getMessage());
}

public static String formatMessage(String message) {
int index = message.indexOf(":");
if (index != -1) {
Expand All @@ -68,7 +73,8 @@ public static String formatMessage(String message) {
}

@SuppressWarnings("unchecked")
public static OutputUnitData from(Set<ValidationMessage> validationMessages, ExecutionContext executionContext) {
public static OutputUnitData from(Set<ValidationMessage> validationMessages, ExecutionContext executionContext,
Function<ValidationMessage, Object> assertionMapper) {
OutputUnitData data = new OutputUnitData();

Map<OutputUnitKey, Boolean> valid = data.valid;
Expand All @@ -85,15 +91,15 @@ public static OutputUnitData from(Set<ValidationMessage> validationMessages, Exe
Map<String, Object> errorMap = errors.computeIfAbsent(key, k -> new LinkedHashMap<>());
Object value = errorMap.get(assertion.getType());
if (value == null) {
errorMap.put(assertion.getType(), formatMessage(assertion.getMessage()));
errorMap.put(assertion.getType(), assertionMapper.apply(assertion));
} else {
// Existing error, make it into a list
if (value instanceof List) {
((List<String>) value).add(formatMessage(assertion.getMessage()));
((List<Object>) value).add(assertionMapper.apply(assertion));
} else {
List<String> values = new ArrayList<>();
List<Object> values = new ArrayList<>();
values.add(value.toString());
values.add(formatMessage(assertion.getMessage()));
values.add(assertionMapper.apply(assertion));
errorMap.put(assertion.getType(), values);
}
}
Expand Down
31 changes: 31 additions & 0 deletions src/test/java/com/networknt/schema/OutputUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

Expand Down Expand Up @@ -339,4 +340,34 @@ void anyOf() throws JsonProcessingException {
assertEquals(expected, output);
}

@Test
void listAssertionMapper() {
String formatSchema = "{\r\n"
+ " \"type\": \"string\"\r\n"
+ "}";
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012);
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
config.setPathType(PathType.JSON_POINTER);
JsonSchema schema = factory.getSchema(formatSchema, config);
OutputUnit outputUnit = schema.validate("1234", InputFormat.JSON, new OutputFormat.List(a -> a));
assertFalse(outputUnit.isValid());
OutputUnit details = outputUnit.getDetails().get(0);
Object assertion = details.getErrors().get("type");
assertInstanceOf(ValidationMessage.class, assertion);
}

@Test
void hierarchicalAssertionMapper() {
String formatSchema = "{\r\n"
+ " \"type\": \"string\"\r\n"
+ "}";
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012);
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
config.setPathType(PathType.JSON_POINTER);
JsonSchema schema = factory.getSchema(formatSchema, config);
OutputUnit outputUnit = schema.validate("1234", InputFormat.JSON, new OutputFormat.Hierarchical(a -> a));
assertFalse(outputUnit.isValid());
Object assertion = outputUnit.getErrors().get("type");
assertInstanceOf(ValidationMessage.class, assertion);
}
}

0 comments on commit bc61ef3

Please sign in to comment.