Support handling of non-finite numbers if present#1241
Support handling of non-finite numbers if present#1241stevehu merged 2 commits intonetworknt:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the validator to handle non-finite numeric values (NaN, Infinity, -Infinity) by treating them as not valid JSON numbers for type and numeric comparison keywords, while still allowing const/enum matching by value when those non-finite values appear in schemas and instances.
Changes:
- Added non-finite detection (
isNonFiniteNumber) and used it to exclude non-finite values fromnumber/integertype classification. - Updated
const/enumnumeric normalization/comparison paths to support non-finite values. - Added/updated tests across type and numeric keywords to cover non-finite handling.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/com/networknt/schema/utils/JsonNodeTypes.java | Adds isNonFiniteNumber and excludes non-finite values from isNumber. |
| src/main/java/com/networknt/schema/utils/TypeFactory.java | Returns UNKNOWN for non-finite numeric nodes instead of NUMBER. |
| src/main/java/com/networknt/schema/keyword/MultipleOfValidator.java | Skips multipleOf validation when instance value is non-finite. |
| src/main/java/com/networknt/schema/keyword/EnumValidator.java | Normalizes non-finite numeric enum values using DoubleNode to enable matching. |
| src/main/java/com/networknt/schema/keyword/ConstValidator.java | Adds a non-finite comparison branch for numeric const validation. |
| src/test/java/com/networknt/schema/TypeValidatorTest.java | Adds tests asserting non-finite values fail integer/number type validation. |
| src/test/java/com/networknt/schema/MultipleOfValidatorTest.java | Adds tests asserting multipleOf does not validate non-finite instance numbers. |
| src/test/java/com/networknt/schema/MinimumValidatorTest.java | Adds non-finite tests; modifies overflow-related assertions. |
| src/test/java/com/networknt/schema/MaximumValidatorTest.java | Adds non-finite tests; modifies overflow-related assertions. |
| src/test/java/com/networknt/schema/ExclusiveMinimumValidatorTest.java | Adds tests asserting exclusiveMinimum ignores non-finite instance numbers. |
| src/test/java/com/networknt/schema/ExclusiveMaximumValidatorTest.java | Adds tests asserting exclusiveMaximum ignores non-finite instance numbers. |
| src/test/java/com/networknt/schema/EnumValidatorTest.java | Adds enum tests for NaN/±Infinity matching and mismatch cases. |
| src/test/java/com/networknt/schema/ConstValidatorTest.java | Adds const tests for NaN/±Infinity matching and mismatch cases. |
Comments suppressed due to low confidence (4)
src/test/java/com/networknt/schema/MaximumValidatorTest.java:213
- Filtering out "type" errors here can mask expected type violations for non-finite/overflow-to-Infinity values. Prefer asserting the type error(s) explicitly or adjust the schema under test.
List<Error> messages2 = v.validate(doc).stream().filter(e -> !e.getKeyword().equals("type")).toList();
if (Double.valueOf(maximum).equals(Double.POSITIVE_INFINITY)) {
assertTrue(messages2.isEmpty(), format("Maximum %s and value %s are equal, thus no schema violation should be reported", maximum, value));
} else {
assertFalse(messages2.isEmpty(), format("Maximum %s is smaller than value %s , should be validation error reported", maximum, value));
}
src/test/java/com/networknt/schema/MaximumValidatorTest.java:225
- Filtering out "type" keyword errors and asserting emptiness can conceal expected type failures for non-finite values. Prefer asserting the type error(s) or removing "type" from the schema for this scenario.
List<Error> messages3 = v.validate(doc).stream().filter(e -> !e.getKeyword().equals("type")).toList();
//when the schema and value are both using BigDecimal, the value should be parsed in same mechanism.
String theValue = value.toLowerCase().replace("\"", "");
if (maximum.toLowerCase().equals(theValue)) {
assertTrue(messages3.isEmpty(), format("Maximum %s and value %s are equal, thus no schema violation should be reported", maximum, value));
} else {
assertFalse(messages3.isEmpty(), format("Maximum %s is smaller than value %s , should be validation error reported", maximum, value));
}
src/test/java/com/networknt/schema/MaximumValidatorTest.java:281
- Filtering out "type" errors here can hide expected type failures for non-finite values. Prefer asserting the type error(s) explicitly or adjust the schema under test. Also remove the extra semicolon after toList().
messages = v.validate(doc).stream().filter(e -> !e.getKeyword().equals("type")).toList();;
// "1.7976931348623158e+308" == "1.7976931348623157e+308" == Double.MAX_VALUE
// new BigDecimal("1.7976931348623158e+308").compareTo(new BigDecimal("1.7976931348623157e+308")) > 0
assertTrue(messages.isEmpty(), "Validation should success because the bug of bigDecimalMapper, it will treat 1.7976931348623159e+308 as INFINITY");
src/test/java/com/networknt/schema/MaximumValidatorTest.java:294
- Filtering out "type" errors and asserting only maximum behavior can mask expected type failures for non-finite values. Prefer asserting the type error(s) or removing "type" from the schema for this scenario. Also remove the extra semicolon after toList().
messages = v.validate(doc).stream().filter(e -> !e.getKeyword().equals("type")).toList();;
// Before 2.16.0 messages will be empty due to bug https://github.com/FasterXML/jackson-databind/issues/1770
// assertTrue(messages.isEmpty(), "Validation should success because the bug of bigDecimalMapper, it will treat 1.7976931348623159e+308 as INFINITY");
assertFalse(messages.isEmpty(), "Validation should fail as Incorrect deserialization for BigDecimal numbers is fixed in 2.16.0");
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
I haven't tested this, but presumably it would solve the problem that caused me to create #1239, and for that I thank you. That said, the approach in this pull request seems to contradict your comment on that issue:
If I created a custom The changes is my pull request make those validators robust with respect to infinity and NaN without limiting them to strict |
|
Don't see how it contradicts. Essentially Essentially if you wish to add any different semantics you need to create a new set of validators for This library is really an implementation of JSON Schema and the YAML support is largely to support OpenAPI and not that this library is supposed to be some generic YAML validator. Again if you disagree you should discuss your case at https://github.com/json-schema-org/json-schema-spec/issues. |
Closes #1239, Closes #1240
If
NaN,Infinity,-Infinityvalues are present they are not treated as a JSON number type as it is not valid JSON.When used in
constandenumcomparison is done by checking the values and not using numeric comparison. I.e. forconstNaNthe instance dataNaNwill pass validation.When used in
typesuch non-finite numbers are not considerednumber.When used in
minimum,maximum,exclusiveMaximum,exclusiveMinimumandmultipleOfas these are not numbers no validation is performed similar to when the instance data is astring.