Fix #1239: Add support for non-finite values in schema and data#1240
Fix #1239: Add support for non-finite values in schema and data#1240mjcarman wants to merge 3 commits intonetworknt:masterfrom
Conversation
BigDecimal can't represent non-finite values (±Infinity and NaN). Add checks for nodes containing non-finite floating-point values to numeric validators. Process such values as double/Double/DoubleNode instead.
There was a problem hiding this comment.
Pull request overview
Adds support for non-finite numeric values (Infinity, -Infinity, NaN) when validating YAML-derived schemas and instances, avoiding BigDecimal conversion failures.
Changes:
- Extend numeric threshold validators (
minimum/maximumand exclusive variants) to treatNaNas a validation failure. - Update
enumandmultipleOfhandling to safely process non-finite instance values. - Add a YAML-focused regression test suite covering
const,enum, min/max, andmultipleOfwith non-finite values.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/test/java/com/networknt/schema/NonFiniteTest.java | Adds regression tests for YAML .inf, -.inf, .nan across several numeric keywords. |
| src/main/java/com/networknt/schema/keyword/MultipleOfValidator.java | Rejects non-finite floating-point instance values to avoid BigDecimal conversion errors. |
| src/main/java/com/networknt/schema/keyword/MinimumValidator.java | Treats NaN as crossing the minimum threshold (validation error). |
| src/main/java/com/networknt/schema/keyword/MaximumValidator.java | Treats NaN as crossing the maximum threshold (validation error). |
| src/main/java/com/networknt/schema/keyword/ExclusiveMinimumValidator.java | Treats NaN as crossing the exclusive minimum threshold (validation error). |
| src/main/java/com/networknt/schema/keyword/ExclusiveMaximumValidator.java | Treats NaN as crossing the exclusive maximum threshold (validation error). |
| src/main/java/com/networknt/schema/keyword/EnumValidator.java | Normalizes non-finite numbers as DoubleNode for enum comparisons. |
| src/main/java/com/networknt/schema/keyword/ConstValidator.java | Adds special handling for NaN comparisons in const. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (schemaNode.isNumber() && node.isNumber()) { | ||
| if (schemaNode.decimalValue().compareTo(node.decimalValue()) != 0) { | ||
| if (((NumericNode) schemaNode).isNaN() || ((NumericNode) node).isNaN()) { | ||
| // At least one of the nodes is a non-finite floating-point number and therefore not representable as BigDecimal. | ||
| if (Double.isNaN(schemaNode.doubleValue())) { | ||
| // Treat `const: .nan` in schema as meaning "isNaN()" | ||
| // because NaN != anything (including itself) per IEEE 754. | ||
| if (!Double.isNaN(node.doubleValue())) { | ||
| executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) | ||
| .evaluationPath(executionContext.getEvaluationPath()) | ||
| .locale(executionContext.getExecutionConfig().getLocale()) | ||
| .arguments(schemaNode.asString(schemaNode.toString()), node.asString(node.toString())).build()); | ||
| } | ||
| } | ||
| else if (schemaNode.doubleValue() != node.doubleValue()) { | ||
| executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) | ||
| .evaluationPath(executionContext.getEvaluationPath()) | ||
| .locale(executionContext.getExecutionConfig().getLocale()) | ||
| .arguments(schemaNode.asString(schemaNode.toString()), node.asString(node.toString())).build()); | ||
| } | ||
| } | ||
| else if (schemaNode.decimalValue().compareTo(node.decimalValue()) != 0) { |
There was a problem hiding this comment.
const numeric comparison still falls back to decimalValue() for infinities because the non-finite guard only checks NumericNode.isNaN(). Infinity/-Infinity are not NaN, and decimalValue()/BigDecimal conversion for those values is likely to throw, breaking validation for schemas/data containing .inf/-.inf (the new test covers this).
Consider broadening the guard to treat any non-finite floating-point number (NaN or ±Infinity) using isFloatingPointNumber() + !Double.isFinite(doubleValue()), and then compare using doubleValue() (keeping the special-case semantics for NaN). Also update the comment to match the condition.
| private final static SchemaRegistry REGISTRY = SchemaRegistry.withDialect(Dialects.getDraft202012()); | ||
| private final static String YAML_STRING = | ||
| """ | ||
| --- | ||
| - 10.0 | ||
| - 50.0 | ||
| - .inf | ||
| - -.inf | ||
| - .nan | ||
| """; |
There was a problem hiding this comment.
This test relies on YAML parsing of .inf, -.inf, and .nan, but the current build uses tools.jackson ${version.jackson} (pom.xml currently sets it to 3.1.0) for jackson-dataformat-yaml. Per the PR description, that parsing support only exists in jackson-dataformats-yaml 3.2+, so CI will likely fail unless the dependency is bumped (or the test is made conditional/disabled when unsupported).
Modifies numeric validators to add checks for non-finite values and process them as Double instead of BigDecimal (which would trigger an exception).
Implements #1239
Note: In order to run the test for these changes, you'll need
jackson-dataformats-yamlv3.2 (currently pre-release). In particular, you need the changes in FasterXML/jackson-dataformats-text#627, which added support for properly parsing.inf,-.inf, and.nanin YAML files.