Skip to content

Make BigInteger and BigDecimal parsing lazy #828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 23, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ public abstract class ParserBase extends ParserMinimalBase

protected BigDecimal _numberBigDecimal;

protected String _numberString;

// And then other information about value itself

/**
Expand Down Expand Up @@ -607,7 +609,7 @@ public Number getNumberValue() throws IOException
return _numberLong;
}
if ((_numTypesValid & NR_BIGINT) != 0) {
return _numberBigInt;
return getBigInteger();
}
_throwInternal();
}
Expand Down Expand Up @@ -641,7 +643,7 @@ public Number getNumberValueExact() throws IOException
return _numberLong;
}
if ((_numTypesValid & NR_BIGINT) != 0) {
return _numberBigInt;
return getBigInteger();
}
_throwInternal();
}
Expand Down Expand Up @@ -731,7 +733,7 @@ public BigInteger getBigIntegerValue() throws IOException
convertNumberToBigInteger();
}
}
return _numberBigInt;
return getBigInteger();
}

@Override
Expand Down Expand Up @@ -930,8 +932,9 @@ private void _parseSlowInt(int expType) throws IOException
_numberDouble = NumberInput.parseDouble(numStr, isEnabled(Feature.USE_FAST_DOUBLE_PARSER));
_numTypesValid = NR_DOUBLE;
} else {
// nope, need the heavy guns... (rare case)
_numberBigInt = NumberInput.parseBigInteger(numStr);
// nope, need the heavy guns... (rare case) - since Jackson v2.14, BigInteger parsing is lazy
_numberBigInt = null;
_numberString = numStr;
_numTypesValid = NR_BIGINT;
}
}
Expand Down Expand Up @@ -968,11 +971,12 @@ protected void convertNumberToInt() throws IOException
}
_numberInt = result;
} else if ((_numTypesValid & NR_BIGINT) != 0) {
if (BI_MIN_INT.compareTo(_numberBigInt) > 0
|| BI_MAX_INT.compareTo(_numberBigInt) < 0) {
final BigInteger bigInteger = getBigInteger();
if (BI_MIN_INT.compareTo(bigInteger) > 0
|| BI_MAX_INT.compareTo(bigInteger) < 0) {
reportOverflowInt();
}
_numberInt = _numberBigInt.intValue();
_numberInt = bigInteger.intValue();
} else if ((_numTypesValid & NR_DOUBLE) != 0) {
// Need to check boundaries
if (_numberDouble < MIN_INT_D || _numberDouble > MAX_INT_D) {
Expand All @@ -996,11 +1000,12 @@ protected void convertNumberToLong() throws IOException
if ((_numTypesValid & NR_INT) != 0) {
_numberLong = (long) _numberInt;
} else if ((_numTypesValid & NR_BIGINT) != 0) {
if (BI_MIN_LONG.compareTo(_numberBigInt) > 0
|| BI_MAX_LONG.compareTo(_numberBigInt) < 0) {
final BigInteger bigInteger = getBigInteger();
if (BI_MIN_LONG.compareTo(bigInteger) > 0
|| BI_MAX_LONG.compareTo(bigInteger) < 0) {
reportOverflowLong();
}
_numberLong = _numberBigInt.longValue();
_numberLong = bigInteger.longValue();
} else if ((_numTypesValid & NR_DOUBLE) != 0) {
// Need to check boundaries
if (_numberDouble < MIN_LONG_D || _numberDouble > MAX_LONG_D) {
Expand Down Expand Up @@ -1047,7 +1052,7 @@ protected void convertNumberToDouble() throws IOException
if ((_numTypesValid & NR_BIGDECIMAL) != 0) {
_numberDouble = _numberBigDecimal.doubleValue();
} else if ((_numTypesValid & NR_BIGINT) != 0) {
_numberDouble = _numberBigInt.doubleValue();
_numberDouble = getBigInteger().doubleValue();
} else if ((_numTypesValid & NR_LONG) != 0) {
_numberDouble = (double) _numberLong;
} else if ((_numTypesValid & NR_INT) != 0) {
Expand All @@ -1071,7 +1076,7 @@ protected void convertNumberToFloat() throws IOException
if ((_numTypesValid & NR_BIGDECIMAL) != 0) {
_numberFloat = _numberBigDecimal.floatValue();
} else if ((_numTypesValid & NR_BIGINT) != 0) {
_numberFloat = _numberBigInt.floatValue();
_numberFloat = getBigInteger().floatValue();
} else if ((_numTypesValid & NR_LONG) != 0) {
_numberFloat = (float) _numberLong;
} else if ((_numTypesValid & NR_INT) != 0) {
Expand All @@ -1098,7 +1103,7 @@ protected void convertNumberToBigDecimal() throws IOException
*/
_numberBigDecimal = NumberInput.parseBigDecimal(getText());
} else if ((_numTypesValid & NR_BIGINT) != 0) {
_numberBigDecimal = new BigDecimal(_numberBigInt);
_numberBigDecimal = new BigDecimal(getBigInteger());
} else if ((_numTypesValid & NR_LONG) != 0) {
_numberBigDecimal = BigDecimal.valueOf(_numberLong);
} else if ((_numTypesValid & NR_INT) != 0) {
Expand Down Expand Up @@ -1345,4 +1350,15 @@ protected void loadMoreGuaranteed() throws IOException {

// Can't declare as deprecated, for now, but shouldn't be needed
protected void _finishString() throws IOException { }

private BigInteger getBigInteger() {
if (_numberBigInt != null) {
return _numberBigInt;
} else if (_numberString == null) {
throw new IllegalStateException("cannot get BigInteger from current parser state");
}
_numberBigInt = NumberInput.parseBigInteger(_numberString);
_numberString = null;
return _numberBigInt;
}
}