diff --git a/src/main/java/com/networknt/schema/keyword/BaseKeywordValidator.java b/src/main/java/com/networknt/schema/keyword/BaseKeywordValidator.java index 342b1136..62f86436 100644 --- a/src/main/java/com/networknt/schema/keyword/BaseKeywordValidator.java +++ b/src/main/java/com/networknt/schema/keyword/BaseKeywordValidator.java @@ -17,6 +17,7 @@ package com.networknt.schema.keyword; import tools.jackson.databind.JsonNode; + import com.networknt.schema.ErrorMessages; import com.networknt.schema.Schema; import com.networknt.schema.MessageSourceError; @@ -83,12 +84,23 @@ public Schema getParentSchema() { return this.parentSchema; } - protected String getNodeFieldType() { + protected boolean hasType(String type) { JsonNode typeField = this.getParentSchema().getSchemaNode().get("type"); if (typeField != null) { - return typeField.asString(); + switch (typeField.getNodeType()) { + case STRING: + return type.equals(typeField.stringValue()); + case ARRAY: + for (JsonNode item : typeField.values()) { + if (item.isString() && type.equals(item.stringValue())) { + return true; + } + } + default: + return false; + } } - return null; + return false; } protected void preloadSchemas(final Collection schemas) { diff --git a/src/main/java/com/networknt/schema/keyword/ExclusiveMaximumValidator.java b/src/main/java/com/networknt/schema/keyword/ExclusiveMaximumValidator.java index c73dee01..9a4fb481 100644 --- a/src/main/java/com/networknt/schema/keyword/ExclusiveMaximumValidator.java +++ b/src/main/java/com/networknt/schema/keyword/ExclusiveMaximumValidator.java @@ -41,7 +41,7 @@ public ExclusiveMaximumValidator(SchemaLocation schemaLocation, final JsonNode s throw new SchemaException("exclusiveMaximum value is not a number"); } final String maximumText = schemaNode.asString(); - if ((schemaNode.isLong() || schemaNode.isInt()) && (JsonType.INTEGER.toString().equals(getNodeFieldType()))) { + if ((schemaNode.isLong() || schemaNode.isInt()) && hasType(JsonType.INTEGER.toString())) { // "integer", and within long range final long lm = schemaNode.asLong(); typedMaximum = new ThresholdMixin() { diff --git a/src/main/java/com/networknt/schema/keyword/ExclusiveMinimumValidator.java b/src/main/java/com/networknt/schema/keyword/ExclusiveMinimumValidator.java index 600e37dc..6b017064 100644 --- a/src/main/java/com/networknt/schema/keyword/ExclusiveMinimumValidator.java +++ b/src/main/java/com/networknt/schema/keyword/ExclusiveMinimumValidator.java @@ -45,7 +45,7 @@ public ExclusiveMinimumValidator(SchemaLocation schemaLocation, final JsonNode s throw new SchemaException("exclusiveMinimum value is not a number"); } final String minimumText = schemaNode.asString(); - if ((schemaNode.isLong() || schemaNode.isInt()) && JsonType.INTEGER.toString().equals(getNodeFieldType())) { + if ((schemaNode.isLong() || schemaNode.isInt()) && hasType(JsonType.INTEGER.toString())) { // "integer", and within long range final long lmin = schemaNode.asLong(); typedMinimum = new ThresholdMixin() { diff --git a/src/main/java/com/networknt/schema/keyword/MaximumValidator.java b/src/main/java/com/networknt/schema/keyword/MaximumValidator.java index 2d38e2f0..0dd131eb 100644 --- a/src/main/java/com/networknt/schema/keyword/MaximumValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MaximumValidator.java @@ -54,7 +54,7 @@ public MaximumValidator(SchemaLocation schemaLocation, final JsonNode schemaNode } final String maximumText = schemaNode.asString(); - if ((schemaNode.isLong() || schemaNode.isInt()) && (JsonType.INTEGER.toString().equals(getNodeFieldType()))) { + if ((schemaNode.isLong() || schemaNode.isInt()) && hasType(JsonType.INTEGER.toString())) { // "integer", and within long range final long lm = schemaNode.asLong(); this.typedMaximum = new ThresholdMixin() { diff --git a/src/main/java/com/networknt/schema/keyword/MinimumValidator.java b/src/main/java/com/networknt/schema/keyword/MinimumValidator.java index 25012b7d..57851140 100644 --- a/src/main/java/com/networknt/schema/keyword/MinimumValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MinimumValidator.java @@ -58,7 +58,7 @@ public MinimumValidator(SchemaLocation schemaLocation, final JsonNode schemaNode } final String minimumText = schemaNode.asString(); - if ((schemaNode.isLong() || schemaNode.isInt()) && JsonType.INTEGER.toString().equals(getNodeFieldType())) { + if ((schemaNode.isLong() || schemaNode.isInt()) && hasType(JsonType.INTEGER.toString())) { // "integer", and within long range final long lmin = schemaNode.asLong(); this.typedMinimum = new ThresholdMixin() { diff --git a/src/test/java/com/networknt/schema/ExclusiveMaximumValidatorTest.java b/src/test/java/com/networknt/schema/ExclusiveMaximumValidatorTest.java new file mode 100644 index 00000000..287b3e0b --- /dev/null +++ b/src/test/java/com/networknt/schema/ExclusiveMaximumValidatorTest.java @@ -0,0 +1,40 @@ +/* + * 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; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import com.networknt.schema.dialect.Dialects; + +/** + * Test ExclusiveMaximumValidator validator. + */ +class ExclusiveMaximumValidatorTest { + @Test + void exclusiveMaximum() { + final String schemaString = """ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": ["null", "integer"], + "exclusiveMaximum": 10 + } + """; + final SchemaRegistry schemaRegistry = SchemaRegistry.withDialect(Dialects.getDraft7()); + assertEquals(1, schemaRegistry.getSchema(schemaString).validate("10", InputFormat.JSON).size()); + } +} diff --git a/src/test/java/com/networknt/schema/ExclusiveMinimumValidatorTest.java b/src/test/java/com/networknt/schema/ExclusiveMinimumValidatorTest.java index 48e17dff..f5da433e 100644 --- a/src/test/java/com/networknt/schema/ExclusiveMinimumValidatorTest.java +++ b/src/test/java/com/networknt/schema/ExclusiveMinimumValidatorTest.java @@ -92,4 +92,17 @@ void draftV7ShouldNotAllowExclusiveMinimumBoolean() { SchemaRegistry factory = SchemaRegistry.withDialect(dialect); assertThrows(SchemaException.class, () -> factory.getSchema(schemaData)); } + + @Test + void exclusiveMinimum() { + final String schemaString = """ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": ["null", "integer"], + "exclusiveMinimum": 10 + } + """; + final SchemaRegistry schemaRegistry = SchemaRegistry.withDialect(Dialects.getDraft7()); + assertEquals(1, schemaRegistry.getSchema(schemaString).validate("10", InputFormat.JSON).size()); + } } diff --git a/src/test/java/com/networknt/schema/MaximumValidatorTest.java b/src/test/java/com/networknt/schema/MaximumValidatorTest.java index ada7c642..c7c96f4a 100644 --- a/src/test/java/com/networknt/schema/MaximumValidatorTest.java +++ b/src/test/java/com/networknt/schema/MaximumValidatorTest.java @@ -21,11 +21,14 @@ import tools.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; +import com.networknt.schema.dialect.Dialects; + import java.io.IOException; import java.math.BigDecimal; import java.util.List; import static java.lang.String.format; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -326,6 +329,19 @@ private static void expectSomeMessages(String[][] values, String schemaTemplate, assertFalse(messages.isEmpty(), format(MaximumValidatorTest.NEGATIVE_TEST_CASE_TEMPLATE, value, maximum)); } } + + @Test + void maximumWithArrayType() { + final String schemaString = """ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": ["null", "integer"], + "maximum": 10 + } + """; + final SchemaRegistry schemaRegistry = SchemaRegistry.withDialect(Dialects.getDraft7()); + assertEquals(1, schemaRegistry.getSchema(schemaString).validate("11", InputFormat.JSON).size()); + } } diff --git a/src/test/java/com/networknt/schema/MinimumValidatorTest.java b/src/test/java/com/networknt/schema/MinimumValidatorTest.java index 55f63351..d5ef94c7 100644 --- a/src/test/java/com/networknt/schema/MinimumValidatorTest.java +++ b/src/test/java/com/networknt/schema/MinimumValidatorTest.java @@ -18,6 +18,7 @@ import static com.networknt.schema.MaximumValidatorTest.augmentWithQuotes; import static java.lang.String.format; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -28,6 +29,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.networknt.schema.dialect.Dialects; + import tools.jackson.databind.DeserializationFeature; import tools.jackson.databind.JsonNode; import tools.jackson.databind.ObjectMapper; @@ -298,6 +301,20 @@ private void expectNoMessages(String[][] values, String integer, ObjectMapper ma assertTrue(messages.isEmpty(), format(MinimumValidatorTest.POSITIVT_MESSAGE_TEMPLATE, value, minimum)); } } + + @Test + void minimumWithArrayType() { + final String schemaString = """ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": ["null", "integer"], + "minimum": 10 + } + """; + final SchemaRegistry schemaRegistry = SchemaRegistry.withDialect(Dialects.getDraft7()); + assertEquals(1, schemaRegistry.getSchema(schemaString).validate("9", InputFormat.JSON).size()); + } + }