-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
JsonNumber.of(double) passes hardcoded (decimalOffset=0, exponentOffset=0) to JsonNumberImpl, which causes toLong() to fail even for whole numbers like 1.0, 1000.0, or 1e10.
This bug exists in upstream OpenJDK jdk-sandbox json branch as well.
Steps to Reproduce
On the sync-upstream-api branch, run the demo class:
git checkout sync-upstream-api
mvn -pl json-java21 clean compile test-compile
java -cp json-java21/target/classes:json-java21/target/test-classes \
jdk.sandbox.internal.util.json.PrReviewIssuesDemoExpected Behavior
JsonNumber.of(1.0).toLong() // Should return 1L
JsonNumber.of(1000.0).toLong() // Should return 1000L
JsonNumber.of(1e10).toLong() // Should return 10000000000LActual Behavior
Test: JsonNumber.of(1.0)
toString() = '1.0'
toLong() threw: 1.0 cannot be represented as a long. Path: "". Location: line 0, position 0.
[CONFIRMED BUG]
Test: JsonNumber.of(1000.0)
toString() = '1000.0'
toLong() threw: 1000.0 cannot be represented as a long. Path: "". Location: line 0, position 0.
[CONFIRMED BUG]
Test: JsonNumber.of(1e10) - produces '1.0E10'
toString() = '1.0E10'
toLong() threw: 1.0E10 cannot be represented as a long. Path: "". Location: line 0, position 0.
[CONFIRMED BUG]
However, parsing the same value from a JSON string works correctly:
Control: Json.parse("1.0") - parsed from string
toString() = '1.0'
toLong() = 1 [Parser sets correct offsets]
Root Cause
In JsonNumber.java line 79-80:
static JsonNumber of(double num) {
if (!Double.isFinite(num)) {
throw new IllegalArgumentException("Not a valid JSON number");
}
var str = Double.toString(num);
return new JsonNumberImpl(str.toCharArray(), 0, str.length(), 0, 0);
// ^ ^
// decimalOffset exponentOffset
}The problem is decimalOffset=0 and exponentOffset=0 are passed regardless of where (or if) the decimal point and exponent actually appear in the string.
For "1.0":
- Actual decimal position is at index 1
- Passed
decimalOffset=0(wrong)
The initNumLong() method in JsonNumberImpl uses these offsets to determine how to parse the number. When decimalOffset != -1, it takes a branch that expects the decimal at that position, leading to incorrect parsing.
Upstream Reference
This bug exists in upstream OpenJDK:
Potential Fix
Compute the actual decimal and exponent offsets from the string:
static JsonNumber of(double num) {
if (!Double.isFinite(num)) {
throw new IllegalArgumentException("Not a valid JSON number");
}
var str = Double.toString(num);
var chars = str.toCharArray();
int decOff = str.indexOf('.');
int expOff = Math.max(str.indexOf('e'), str.indexOf('E'));
return new JsonNumberImpl(chars, 0, chars.length, decOff, expOff);
}Decision Required
Since this is a backport, we have options:
- Keep as-is - faithfully reproduce upstream bug, document the limitation
- Fix locally - diverge from upstream to fix the bug (may complicate future syncs)
- Report upstream - file a bug with OpenJDK and wait for their fix
Related
- PR feat: sync API with latest upstream java.util.json #115 - sync API with latest upstream
- Codex review comment that identified this issue