diff --git a/src/main/java/com/networknt/schema/ItemsValidator.java b/src/main/java/com/networknt/schema/ItemsValidator.java index 7912ebd8b..d08ee99d3 100644 --- a/src/main/java/com/networknt/schema/ItemsValidator.java +++ b/src/main/java/com/networknt/schema/ItemsValidator.java @@ -19,9 +19,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.networknt.schema.annotation.JsonNodeAnnotation; -import com.networknt.schema.utils.JsonSchemaRefs; import com.networknt.schema.utils.SetView; - +import com.networknt.schema.utils.Defaults; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -241,7 +240,7 @@ public Set walk(ExecutionContext executionContext, JsonNode n ArrayNode arrayNode = (ArrayNode) node; JsonNode defaultNode = null; if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { - defaultNode = getDefaultNode(this.schema); + defaultNode = Defaults.getDefaultNode(this.schema); } for (int i = 0; i < count; i++) { JsonNode n = arrayNode.get(i); @@ -266,7 +265,7 @@ else if (this.tupleSchema != null) { JsonNode defaultNode = null; JsonNode n = arrayNode.get(i); if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { - defaultNode = getDefaultNode(this.tupleSchema.get(i)); + defaultNode = Defaults.getDefaultNode(this.tupleSchema.get(i)); } if (n != null) { if (n.isNull() && defaultNode != null) { @@ -293,7 +292,7 @@ else if (this.tupleSchema != null) { JsonNode defaultNode = null; JsonNode n = arrayNode.get(i); if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { - defaultNode = getDefaultNode(this.additionalSchema); + defaultNode = Defaults.getDefaultNode(this.additionalSchema); } if (n != null) { if (n.isNull() && defaultNode != null) { @@ -326,17 +325,6 @@ else if (this.tupleSchema != null) { return validationMessages; } - private static JsonNode getDefaultNode(JsonSchema schema) { - JsonNode result = schema.getSchemaNode().get("default"); - if (result == null) { - JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); - if (schemaRef != null) { - result = getDefaultNode(schemaRef.getSchema()); - } - } - return result; - } - private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema, Set validationMessages, String keyword) { boolean executeWalk = this.validationContext.getConfig().getItemWalkListenerRunner().runPreWalkListeners(executionContext, keyword, diff --git a/src/main/java/com/networknt/schema/ItemsValidator202012.java b/src/main/java/com/networknt/schema/ItemsValidator202012.java index 9edcb37ef..065db6c16 100644 --- a/src/main/java/com/networknt/schema/ItemsValidator202012.java +++ b/src/main/java/com/networknt/schema/ItemsValidator202012.java @@ -19,7 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.networknt.schema.annotation.JsonNodeAnnotation; -import com.networknt.schema.utils.JsonSchemaRefs; +import com.networknt.schema.utils.Defaults; import com.networknt.schema.utils.SetView; import org.slf4j.Logger; @@ -120,7 +120,7 @@ public Set walk(ExecutionContext executionContext, JsonNode n JsonNode defaultNode = null; if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults() && this.schema != null) { - defaultNode = getDefaultNode(this.schema); + defaultNode = Defaults.getDefaultNode(this.schema); } boolean evaluated = false; for (int i = this.prefixCount; i < node.size(); ++i) { @@ -155,17 +155,7 @@ public Set walk(ExecutionContext executionContext, JsonNode n return validationMessages; } - private static JsonNode getDefaultNode(JsonSchema schema) { - JsonNode result = schema.getSchemaNode().get("default"); - if (result == null) { - JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); - if (schemaRef != null) { - result = getDefaultNode(schemaRef.getSchema()); - } - } - return result; - } - + private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema, Set validationMessages) { //@formatter:off diff --git a/src/main/java/com/networknt/schema/PrefixItemsValidator.java b/src/main/java/com/networknt/schema/PrefixItemsValidator.java index ccda85859..987aaa929 100644 --- a/src/main/java/com/networknt/schema/PrefixItemsValidator.java +++ b/src/main/java/com/networknt/schema/PrefixItemsValidator.java @@ -19,7 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.networknt.schema.annotation.JsonNodeAnnotation; -import com.networknt.schema.utils.JsonSchemaRefs; +import com.networknt.schema.utils.Defaults; import com.networknt.schema.utils.SetView; import org.slf4j.Logger; @@ -110,7 +110,7 @@ public Set walk(ExecutionContext executionContext, JsonNode n for (int i = 0; i < count; ++i) { JsonNode n = node.get(i); if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { - JsonNode defaultNode = getDefaultNode(this.tupleSchema.get(i)); + JsonNode defaultNode = Defaults.getDefaultNode(this.tupleSchema.get(i)); if (n != null) { // Defaults only set if array index is explicitly null if (n.isNull() && defaultNode != null) { @@ -150,16 +150,6 @@ public Set walk(ExecutionContext executionContext, JsonNode n return validationMessages; } - private static JsonNode getDefaultNode(JsonSchema schema) { - JsonNode result = schema.getSchemaNode().get("default"); - if (result == null) { - JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); - if (schemaRef != null) { - result = getDefaultNode(schemaRef.getSchema()); - } - } - return result; - } private void doWalk(ExecutionContext executionContext, Set validationMessages, int i, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { diff --git a/src/main/java/com/networknt/schema/PropertiesValidator.java b/src/main/java/com/networknt/schema/PropertiesValidator.java index f378905ee..b6147548e 100644 --- a/src/main/java/com/networknt/schema/PropertiesValidator.java +++ b/src/main/java/com/networknt/schema/PropertiesValidator.java @@ -21,7 +21,7 @@ import com.fasterxml.jackson.databind.node.MissingNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.networknt.schema.annotation.JsonNodeAnnotation; -import com.networknt.schema.utils.JsonSchemaRefs; +import com.networknt.schema.utils.Defaults; import com.networknt.schema.utils.SetView; import com.networknt.schema.walk.WalkListenerRunner; import org.slf4j.Logger; @@ -192,7 +192,7 @@ private void applyPropertyDefaults(ObjectNode node) { for (Map.Entry entry : this.schemas.entrySet()) { JsonNode propertyNode = node.get(entry.getKey()); - JsonNode defaultNode = getDefaultNode(entry.getValue()); + JsonNode defaultNode = Defaults.getDefaultNode(entry.getValue()); if (defaultNode == null) { continue; } @@ -204,17 +204,6 @@ private void applyPropertyDefaults(ObjectNode node) { } } - private static JsonNode getDefaultNode(JsonSchema schema) { - JsonNode result = schema.getSchemaNode().get("default"); - if (result == null) { - JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); - if (schemaRef != null) { - result = getDefaultNode(schemaRef.getSchema()); - } - } - return result; - } - private void walkSchema(ExecutionContext executionContext, Map.Entry entry, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema, SetView validationMessages, WalkListenerRunner propertyWalkListenerRunner) { diff --git a/src/main/java/com/networknt/schema/utils/Defaults.java b/src/main/java/com/networknt/schema/utils/Defaults.java new file mode 100644 index 000000000..23b26631e --- /dev/null +++ b/src/main/java/com/networknt/schema/utils/Defaults.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.networknt.schema.utils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.JsonSchema; +import com.networknt.schema.JsonSchemaRef; + +/** + * The 'Defaults' class provides utility methods for retrieving default values + * from a JSON schema. + * + * This class contains a single static method, 'getDefaultNode', which takes a + * 'JsonSchema' object as input + * and returns the default value specified in the schema. If the schema does not + * have a default value, + * it checks if the schema has a reference to another schema and recursively + * calls itself with the referenced schema. + * + * Usage: + * JsonSchema schema = ...; // create or obtain a JSON schema + * JsonNode defaultNode = Defaults.getDefaultNode(schema); // retrieve the + * default value from the schema + * + * Note: This class requires the 'com.networknt.schema.JsonSchema' and + * 'com.networknt.schema.JsonSchemaRef' classes + * from the 'networknt/json-schema-validator' library. + */ +public class Defaults { + /** + * Retrieves the default value specified in the JSON schema. + * + * This method takes a 'JsonSchema' object as input and returns the default + * value specified in the schema. + * If the schema does not have a default value, it checks if the schema has a + * reference to another schema + * and recursively calls itself with the referenced schema. + * + * @param schema the JSON schema from which to retrieve the default value + * @return the default value specified in the schema, or null if no default + * value is found + */ + public static JsonNode getDefaultNode(JsonSchema schema) { + JsonNode result = schema.getSchemaNode().get("default"); + if (result == null) { + JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); + if (schemaRef != null) { + result = getDefaultNode(schemaRef.getSchema()); + } + } + return result; + } +} diff --git a/src/test/java/com/networknt/schema/utils/DefaultsTest.java b/src/test/java/com/networknt/schema/utils/DefaultsTest.java new file mode 100644 index 000000000..67b68dfd3 --- /dev/null +++ b/src/test/java/com/networknt/schema/utils/DefaultsTest.java @@ -0,0 +1,53 @@ +package com.networknt.schema.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.InputStream; + +import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.JsonSchema; +import com.networknt.schema.JsonSchemaFactory; +import com.networknt.schema.SpecVersion.VersionFlag; +public class DefaultsTest { + + @Test + void testGetDefaultNodeNotNull() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + JsonNode node = mapper.readTree("{\"default\": \"defaultValue\"}"); + JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7); + JsonSchema schema = factory.getSchema(node); + JsonNode result = Defaults.getDefaultNode(schema); + assertNotNull(result, "Default node should not be null"); + } + + @Test + void testGetDefaultNodeWhenDefaultNotFound() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + // Create a JsonNode without a "default" field + JsonNode node = mapper.readTree("{\"notDefault\": \"value\"}"); + JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7); + JsonSchema schema = factory.getSchema(node); + JsonNode result = Defaults.getDefaultNode(schema); + // Assert that the result is null, as there's no "default" node in the schema + assertNull(result, "Default node should be null when 'default' node is not found in the schema"); + } + + @Test + void testGetDefaultNodeWhenDefaultInRef() throws Exception { + InputStream mainSchemaInputStream = DefaultsTest.class.getResourceAsStream("/mainSchema.json"); + InputStream referredSchemaInputStream = DefaultsTest.class.getResourceAsStream("/referredSchema.json"); + ObjectMapper mapper = new ObjectMapper(); + JsonNode mainSchemaNode = mapper.readTree(mainSchemaInputStream); + JsonNode referredSchemaNode = mapper.readTree(referredSchemaInputStream); + JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7); + JsonSchema mainSchema = factory.getSchema(referredSchemaNode); // Use referred schema here + JsonNode result = Defaults.getDefaultNode(mainSchema); + assertNotNull(result, "Default node should not be null when 'default' node is in the referred schema"); + assertEquals("defaultValue", result.asText(), "Default node should have the default value in the referred schema"); + } + +} \ No newline at end of file diff --git a/src/test/resources/mainSchema.json b/src/test/resources/mainSchema.json new file mode 100644 index 000000000..87b45735e --- /dev/null +++ b/src/test/resources/mainSchema.json @@ -0,0 +1,3 @@ +{ + "$ref": "referredSchema.json" +} diff --git a/src/test/resources/referredSchema.json b/src/test/resources/referredSchema.json new file mode 100644 index 000000000..147ef1fcc --- /dev/null +++ b/src/test/resources/referredSchema.json @@ -0,0 +1,4 @@ +{ + "type": "string", + "default": "defaultValue" +}