Skip to content

return BigInteger for json integers beyond long range#2619

Open
netliomax25-code wants to merge 1 commit into
apache:masterfrom
netliomax25-code:json-bigint-overflow
Open

return BigInteger for json integers beyond long range#2619
netliomax25-code wants to merge 1 commit into
apache:masterfrom
netliomax25-code:json-bigint-overflow

Conversation

@netliomax25-code

Copy link
Copy Markdown
Contributor
  1. JsonSlurper's default CHAR_BUFFER parser, the INDEX_OVERLAY and LAX overlay parsers, and the CHARACTER_SOURCE parser each pick a JSON integer's Java type with only an int-or-long check, so a value past Long.MAX_VALUE is never promoted to BigInteger.
  2. CHAR_BUFFER (CharScanner.parseJsonNumber) and the overlay parsers (NumberValue.doToValue) fall through to parseLongFromTo, which wraps silently, so parsing 9999999999999999999 yields -8446744073709551617. CHARACTER_SOURCE (JsonParserUsingCharacterSource.decodeNumber) has no branch past isLong and returns null instead.
  3. The lexer-based path (JsonToken.getValue) already returns Integer, Long, or BigInteger, so the parser types disagree on the same input.

Added the missing BigInteger branch at the three decode sites so every parser type matches the JsonToken contract. The new regression test runs across all four parser types and fails before the change.

@testlens-app

testlens-app Bot commented Jun 22, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

⚠️ TestLens detected flakiness ⚠️

Test Summary

Build and test / lts (17, windows-latest, 1) > :test

Test Runs
GenericsSTCTest > testReturnTypeInferenceWithMethodGenerics18() 🚫 ❌ ✅
GenericsSTCTest > testReturnTypeInferenceWithMethodGenerics18a() 🚫 ❌ ✅
GenericsStaticCompileTest > testReturnTypeInferenceWithMethodGenerics18() 🚫 ❌ ✅
GenericsStaticCompileTest > testReturnTypeInferenceWithMethodGenerics18a() 🚫 ❌ ✅

🏷️ Commit: 71ffc3b
▶️ Tests: 20273 executed
⚪️ Checks: 22/22 completed


Learn more about TestLens at testlens.app.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns JsonSlurper’s integer type-selection behavior across its parser implementations so that JSON integers exceeding the long range are returned as BigInteger (instead of overflowing/wrapping or returning null), matching the existing JsonToken contract.

Changes:

  • Extend integer decoding in the CHAR_BUFFER parser (CharScanner.parseJsonNumber) to promote beyond-long integers to BigInteger.
  • Extend integer decoding in overlay parsers (NumberValue.doToValue) to promote beyond-long integers to BigInteger.
  • Extend integer decoding in the CHARACTER_SOURCE parser (JsonParserUsingCharacterSource.decodeNumber) to return BigInteger for beyond-long integers, and add a regression test.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy Adds a regression test for parsing an integer beyond Long.MAX_VALUE (note: as written, it only exercises the default parser type).
subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/NumberValue.java Updates overlay-backed integer conversion to select BigInteger when the value doesn’t fit in int or long.
subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserUsingCharacterSource.java Updates character-source number decoding to construct a BigInteger when the value doesn’t fit in int or long.
subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharScanner.java Updates CHAR_BUFFER number parsing to construct a BigInteger for integer tokens that exceed long range.

Comment on lines +744 to +752
@Test
void testParseIntegerBeyondLongRange() {
// 9999999999999999999 exceeds Long.MAX_VALUE; it must round-trip as a
// BigInteger rather than silently overflowing to a wrong (negative) long.
def raw = parser.parseText('9999999999999999999')
def value = raw instanceof Value ? raw.toValue() : raw
assertTrue(value instanceof BigInteger)
assertEquals(new BigInteger('9999999999999999999'), value)
}
@paulk-asert

Copy link
Copy Markdown
Contributor

Thanks again for another contribution. Did you want to create a Jira and address the Copilot comment?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants