diff --git a/src/main/java/com/networknt/schema/BaseJsonValidator.java b/src/main/java/com/networknt/schema/BaseJsonValidator.java index b2775be7..be816be3 100644 --- a/src/main/java/com/networknt/schema/BaseJsonValidator.java +++ b/src/main/java/com/networknt/schema/BaseJsonValidator.java @@ -392,29 +392,18 @@ public String toString() { */ protected boolean hasAdjacentKeywordInEvaluationPath(String keyword) { JsonSchema schema = getEvaluationParentSchema(); - boolean checkInstance = false; - boolean anchor = false; - boolean stop = false; while (schema != null) { for (JsonValidator validator : schema.getValidators()) { if (keyword.equals(validator.getKeyword())) { return true; } - if (checkInstance) { - if ("properties".equals(validator.getKeyword()) || "items".equals(validator.getKeyword())) { - stop = true; - } else if ("$dynamicAnchor".equals(validator.getKeyword()) || "$recursiveAnchor".equals(validator.getKeyword())) { - anchor = true; - } - } } - if (stop && !anchor) { + Object element = schema.getEvaluationPath().getElement(-1); + if ("properties".equals(element) || "items".equals(element)) { // If there is a change in instance location then return false return false; } schema = schema.getEvaluationParentSchema(); - checkInstance = true; - anchor = false; } return false; } diff --git a/src/test/java/com/networknt/schema/UnevaluatedPropertiesValidatorTest.java b/src/test/java/com/networknt/schema/UnevaluatedPropertiesValidatorTest.java index 447888df..2a8f7c41 100644 --- a/src/test/java/com/networknt/schema/UnevaluatedPropertiesValidatorTest.java +++ b/src/test/java/com/networknt/schema/UnevaluatedPropertiesValidatorTest.java @@ -17,14 +17,18 @@ package com.networknt.schema; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.output.OutputUnit; /** * UnevaluatedPropertiesValidatorTest. @@ -148,4 +152,92 @@ void unevaluatedPropertiesSchema() { assertEquals("type", assertions.get(0).getType()); assertEquals("$.unevaluatedProperties.type", assertions.get(0).getEvaluationPath().toString()); } + + @Test + void ref() { + String schemaData = "{\r\n" + + " \"definitions\": {\r\n" + + " \"other\": {\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"surfboard\": {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n" + + " }\r\n" + + " }\r\n" + + " },\r\n" + + " \"allOf\": [\r\n" + + " {\r\n" + + " \"$ref\": \"#/definitions/other\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"properties\": {\r\n" + + " \"wheels\": {},\r\n" + + " \"headlights\": {}\r\n" + + " }\r\n" + + " },\r\n" + + " {\r\n" + + " \"properties\": {\r\n" + + " \"pontoons\": {}\r\n" + + " }\r\n" + + " },\r\n" + + " {\r\n" + + " \"properties\": {\r\n" + + " \"wings\": {}\r\n" + + " }\r\n" + + " }\r\n" + + " ],\r\n" + + " \"unevaluatedProperties\": false\r\n" + + "}"; + String inputData = "{ \"pontoons\": {}, \"wheels\": {}, \"surfboard\": \"2\" }"; + JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V201909).getSchema(schemaData); + Set messages = schema.validate(inputData, InputFormat.JSON); + assertEquals(0, messages.size()); + } + + @Test + void nestedRef() { + String schemaData = "{\r\n" + + " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\r\n" + + " \"type\": \"object\",\r\n" + + " \"allOf\": [ { \"$ref\": \"https://www.example.org/PrimaryDeviceConfiguration.json#PrimaryDeviceConfiguration\" } ],\r\n" + + " \"properties\": {\r\n" + + " \"__type\": { \"const\": \"dk.cachet.carp.common.application.devices.Smartphone\" }\r\n" + + " },\r\n" + + " \"unevaluatedProperties\": false\r\n" + + "}"; + String primaryDeviceConfiguration = "{\r\n" + + " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\r\n" + + " \"PrimaryDeviceConfiguration\": {\r\n" + + " \"$anchor\": \"PrimaryDeviceConfiguration\",\r\n" + + " \"allOf\": [ { \"$ref\": \"DeviceConfiguration.json#DeviceConfiguration\" } ],\r\n" + + " \"properties\": {\r\n" + + " \"isPrimaryDevice\": { \"const\": true }\r\n" + + " },\r\n" + + " \"required\": [ \"isPrimaryDevice\" ]\r\n" + + " }\r\n" + + " }"; + String deviceConfiguration = "{\r\n" + + " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\r\n" + + " \"DeviceConfiguration\": {\r\n" + + " \"properties\": {\r\n" + + " \"roleName\": { \"type\": \"string\" }\r\n" + + " }\r\n" + + " }\r\n" + + "}"; + Map schemas = new HashMap<>(); + schemas.put("https://www.example.org/PrimaryDeviceConfiguration.json", primaryDeviceConfiguration); + schemas.put("https://www.example.org/DeviceConfiguration.json", deviceConfiguration); + JsonSchema schema = JsonSchemaFactory + .getInstance(VersionFlag.V201909, + builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(schemas))) + .getSchema(schemaData); + String inputData = "{ \"isPrimaryDevice\": true, \"roleName\": \"hello\" }"; + OutputUnit outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.HIERARCHICAL, + executionContext -> { + executionContext.getExecutionConfig().setAnnotationCollectionEnabled(false); + executionContext.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); + }); + assertTrue(outputUnit.isValid()); + } }