Skip to content

Commit

Permalink
Fix issue where the parser can read back old number state when parsin…
Browse files Browse the repository at this point in the history
…g later numbers (#1391)
  • Loading branch information
pjfanning authored Jan 27, 2025
1 parent 3ec9738 commit dae16ea
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 1 deletion.
7 changes: 6 additions & 1 deletion release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ a pure JSON library.
=== Releases ===
------------------------------------------------------------------------

2.17.4 (not yet released)

#1391: Fix issue where the parser can read back old number state when
parsing later numbers
(fix contributed by @pjfanning)

2.17.3 (01-Nov-2024)

#1331: Update to FastDoubleParser v1.0.1 to fix `BigDecimal` decoding problem
Expand All @@ -23,7 +29,6 @@ a pure JSON library.
#1352: Fix infinite loop due to integer overflow when reading large strings
(reported by Adam J.S)
(fix contributed by @pjfanning)


2.17.2 (05-Jul-2024)

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,7 @@ public BigInteger getBigIntegerValue() throws IOException
}
if ((_numTypesValid & NR_BIGINT) == 0) {
convertNumberToBigInteger();
return _numberBigInt;
}
}
return _getBigInteger();
Expand All @@ -840,6 +841,7 @@ public float getFloatValue() throws IOException
}
if ((_numTypesValid & NR_FLOAT) == 0) {
convertNumberToFloat();
return _numberFloat;
}
}
return _getNumberFloat();
Expand All @@ -854,6 +856,7 @@ public double getDoubleValue() throws IOException
}
if ((_numTypesValid & NR_DOUBLE) == 0) {
convertNumberToDouble();
return _numberDouble;
}
}
return _getNumberDouble();
Expand All @@ -868,6 +871,7 @@ public BigDecimal getDecimalValue() throws IOException
}
if ((_numTypesValid & NR_BIGDECIMAL) == 0) {
convertNumberToBigDecimal();
return _numberBigDecimal;
}
}
return _getBigDecimal();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.fasterxml.jackson.core.read;

import java.math.BigDecimal;
import java.math.BigInteger;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.core.JUnit5TestBase;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.TokenStreamFactory;

import static org.junit.jupiter.api.Assertions.assertEquals;

class NumberParsingDb4917Test extends JUnit5TestBase
{
private TokenStreamFactory JSON_F = newStreamFactory();

final String INPUT_JSON = a2q("{'decimalHolder':100.00,'number':50}");

// [jackson-databind#4917]
@Test
public void bigDecimal4917Integers() throws Exception
{
for (int mode : ALL_MODES) {
testBigDecimal4917(JSON_F, mode, INPUT_JSON, true, JsonParser.NumberType.BIG_INTEGER);
testBigDecimal4917(JSON_F, mode, INPUT_JSON, true, JsonParser.NumberType.INT);
testBigDecimal4917(JSON_F, mode, INPUT_JSON, true, JsonParser.NumberType.LONG);
}
}

@Test
public void bigDecimal4917Floats() throws Exception
{
for (int mode : ALL_MODES) {
testBigDecimal4917(JSON_F, mode, INPUT_JSON, false, JsonParser.NumberType.DOUBLE);
testBigDecimal4917(JSON_F, mode, INPUT_JSON, true, JsonParser.NumberType.DOUBLE);
testBigDecimal4917(JSON_F, mode, INPUT_JSON, true, JsonParser.NumberType.FLOAT);
testBigDecimal4917(JSON_F, mode, INPUT_JSON, true, JsonParser.NumberType.BIG_DECIMAL);
}
}

private void testBigDecimal4917(final TokenStreamFactory jsonF,
final int mode,
final String json,
final boolean checkFirstNumValues,
final JsonParser.NumberType secondNumTypeCheck) throws Exception
{
// checkFirstNumValues=false reproduces the issue in https://github.com/FasterXML/jackson-databind/issues/4917
// it is useful to check the second number value while requesting different number types
// but the call adjusts state of the parser, so it is better to redo the test and then test w
try (JsonParser p = createParser(jsonF, mode, json)) {
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("decimalHolder", p.currentName());
assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
assertEquals(JsonParser.NumberType.DOUBLE, p.getNumberType());
if (checkFirstNumValues) {
assertEquals(Double.valueOf(100.0), p.getNumberValueDeferred());
assertEquals(new BigDecimal("100.00"), p.getDecimalValue());
}
assertEquals("100.00", p.getText());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("number", p.currentName());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(JsonParser.NumberType.INT, p.getNumberType());
assertEquals(Integer.valueOf(50), p.getNumberValueDeferred());
if (secondNumTypeCheck == JsonParser.NumberType.BIG_DECIMAL) {
assertEquals(new BigDecimal("50"), p.getDecimalValue());
} else if (secondNumTypeCheck == JsonParser.NumberType.BIG_INTEGER) {
assertEquals(new BigInteger("50"), p.getBigIntegerValue());
} else if (secondNumTypeCheck == JsonParser.NumberType.FLOAT) {
assertEquals(50.0f, p.getFloatValue());
} else if (secondNumTypeCheck == JsonParser.NumberType.LONG) {
assertEquals(50L, p.getLongValue());
} else if (secondNumTypeCheck == JsonParser.NumberType.INT) {
assertEquals(50, p.getIntValue());
} else {
assertEquals(50.0d, p.getDoubleValue());
}
assertEquals(50, p.getIntValue());
assertToken(JsonToken.END_OBJECT, p.nextToken());
}
}
}

0 comments on commit dae16ea

Please sign in to comment.