diff --git a/src/main/java/com/networknt/schema/AnyOfValidator.java b/src/main/java/com/networknt/schema/AnyOfValidator.java index 461580e20..4bcf12262 100644 --- a/src/main/java/com/networknt/schema/AnyOfValidator.java +++ b/src/main/java/com/networknt/schema/AnyOfValidator.java @@ -60,6 +60,8 @@ public Set validate(JsonNode node, JsonNode rootNode, String validationContext.enterDiscriminatorContext(this.discriminatorContext, at); } + boolean initialHasMatchedNode = state.hasMatchedNode(); + Set allErrors = new LinkedHashSet(); String typeValidatorName = "anyOf/type"; @@ -72,6 +74,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String try { int numberOfValidSubSchemas = 0; for (JsonSchema schema : schemas) { + state.setMatchedNode(initialHasMatchedNode); Set errors = new HashSet<>(); if (schema.getValidators().containsKey(typeValidatorName)) { TypeValidator typeValidator = ((TypeValidator) schema.getValidators().get(typeValidatorName)); @@ -87,7 +90,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String } else { errors = schema.walk(node, rootNode, at, true); } - + // check if any validation errors have occurred if (errors.isEmpty()) { // check whether there are no errors HOWEVER we have validated the exact validator @@ -96,8 +99,8 @@ public Set validate(JsonNode node, JsonNode rootNode, String } // we found a valid subschema, so increase counter numberOfValidSubSchemas++; - } - + } + if (errors.isEmpty() && (!this.validationContext.getConfig().isOpenAPI3StyleDiscriminators())) { // Clear all errors. allErrors.clear(); @@ -137,6 +140,7 @@ public Set validate(JsonNode node, JsonNode rootNode, String } if (allErrors.isEmpty()) { addEvaluatedProperties(backupEvaluatedProperties); + state.setMatchedNode(true); } else { CollectorContext.getInstance().add(UnEvaluatedPropertiesValidator.EVALUATED_PROPERTIES, backupEvaluatedProperties); } diff --git a/src/test/java/com/networknt/schema/Issue606Test.java b/src/test/java/com/networknt/schema/Issue606Test.java new file mode 100644 index 000000000..d018f172b --- /dev/null +++ b/src/test/java/com/networknt/schema/Issue606Test.java @@ -0,0 +1,34 @@ +package com.networknt.schema; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.InputStream; +import java.util.Set; + +public class Issue606Test { + protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + return factory.getSchema(schemaContent); + } + + protected JsonNode getJsonNodeFromStreamContent(InputStream content) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + JsonNode node = mapper.readTree(content); + return node; + } + + @Test + public void shouldWorkV7() throws Exception { + String schemaPath = "/schema/issue606-v7.json"; + String dataPath = "/data/issue606.json"; + InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); + JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + InputStream dataInputStream = getClass().getResourceAsStream(dataPath); + JsonNode node = getJsonNodeFromStreamContent(dataInputStream); + Set errors = schema.validate(node); + Assertions.assertEquals(0, errors.size()); + } +} diff --git a/src/test/resources/data/issue606.json b/src/test/resources/data/issue606.json new file mode 100644 index 000000000..f3ee32f77 --- /dev/null +++ b/src/test/resources/data/issue606.json @@ -0,0 +1,8 @@ +{ + "V": [ + { + "A": "foo", + "B": "bar" + } + ] +} \ No newline at end of file diff --git a/src/test/resources/schema/issue606-v7.json b/src/test/resources/schema/issue606-v7.json new file mode 100644 index 000000000..f0269072b --- /dev/null +++ b/src/test/resources/schema/issue606-v7.json @@ -0,0 +1,73 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "V": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "X": { + "type": "string" + } + }, + "required": [ + "X" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "A": { + "type": "string" + }, + "B": { + "type": "string" + }, + "C": { + "type": "string" + } + }, + "anyOf": [ + { + "properties": { + "origin": { + "const": "not-present" + } + }, + "required": [ + "A", + "C" + ] + }, + { + "properties": { + "origin": { + "const": "not-present-either" + } + }, + "required": [ + "A", + "B" + ] + } + ], + "additionalProperties": false, + "required": [ + "A" + ], + "not": { + "type": "object", + "required": [ + "X" + ] + } + } + ] + } + } + } +} \ No newline at end of file