Skip to content

Commit 8aa164a

Browse files
authored
Follow-up to #1157: unify exception handling (#1159)
1 parent 45bb3b1 commit 8aa164a

File tree

3 files changed

+63
-34
lines changed

3 files changed

+63
-34
lines changed

src/main/java/com/fasterxml/jackson/core/io/BigDecimalParser.java

+61-32
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,6 @@
33
import ch.randelshofer.fastdoubleparser.JavaBigDecimalParser;
44

55
import java.math.BigDecimal;
6-
import java.util.Arrays;
7-
8-
// Based on a great idea of Eric Obermühlner to use a tree of smaller BigDecimals for parsing
9-
// really big numbers with O(n^1.5) complexity instead of O(n^2) when using the constructor
10-
// for a decimal representation from JDK 8/11:
11-
//
12-
// https://github.com/eobermuhlner/big-math/commit/7a5419aac8b2adba2aa700ccf00197f97b2ad89f
136

147
/**
158
* Internal Jackson Helper class used to implement more optimized parsing of {@link BigDecimal} for REALLY
@@ -37,6 +30,10 @@ private BigDecimalParser() {}
3730

3831
/**
3932
* Internal Jackson method. Please do not use.
33+
*<p>
34+
* Note: Caller MUST pre-validate that given String represents a valid representation
35+
* of {@link BigDecimal} value: parsers in {@code jackson-core} do that; other
36+
* code must do the same.
4037
*
4138
* @param valueStr
4239
* @return BigDecimal value
@@ -48,6 +45,10 @@ public static BigDecimal parse(String valueStr) {
4845

4946
/**
5047
* Internal Jackson method. Please do not use.
48+
*<p>
49+
* Note: Caller MUST pre-validate that given String represents a valid representation
50+
* of {@link BigDecimal} value: parsers in {@code jackson-core} do that; other
51+
* code must do the same.
5152
*
5253
* @return BigDecimal value
5354
* @throws NumberFormatException
@@ -62,25 +63,16 @@ public static BigDecimal parse(final char[] chars, final int off, final int len)
6263
// 20-Aug-2022, tatu: Although "new BigDecimal(...)" only throws NumberFormatException
6364
// operations by "parseBigDecimal()" can throw "ArithmeticException", so handle both:
6465
} catch (ArithmeticException | NumberFormatException e) {
65-
String desc = e.getMessage();
66-
// 05-Feb-2021, tatu: Alas, JDK mostly has null message so:
67-
if (desc == null) {
68-
desc = "Not a valid number representation";
69-
}
70-
String stringToReport;
71-
if (len <= MAX_CHARS_TO_REPORT) {
72-
stringToReport = new String(chars, off, len);
73-
} else {
74-
stringToReport = new String(Arrays.copyOfRange(chars, off, MAX_CHARS_TO_REPORT))
75-
+ "(truncated, full length is " + chars.length + " chars)";
76-
}
77-
throw new NumberFormatException("Value \"" + stringToReport
78-
+ "\" can not be represented as `java.math.BigDecimal`, reason: " + desc);
66+
throw _parseFailure(e, new String(chars, off, len));
7967
}
8068
}
81-
69+
8270
/**
8371
* Internal Jackson method. Please do not use.
72+
*<p>
73+
* Note: Caller MUST pre-validate that given String represents a valid representation
74+
* of {@link BigDecimal} value: parsers in {@code jackson-core} do that; other
75+
* code must do the same.
8476
*
8577
* @param chars
8678
* @return BigDecimal value
@@ -90,25 +82,62 @@ public static BigDecimal parse(char[] chars) {
9082
return parse(chars, 0, chars.length);
9183
}
9284

85+
/**
86+
* Internal Jackson method. Please do not use.
87+
*<p>
88+
* Note: Caller MUST pre-validate that given String represents a valid representation
89+
* of {@link BigDecimal} value: parsers in {@code jackson-core} do that; other
90+
* code must do the same.
91+
*
92+
* @param valueStr
93+
* @return BigDecimal value
94+
* @throws NumberFormatException
95+
*/
9396
public static BigDecimal parseWithFastParser(final String valueStr) {
9497
try {
9598
return JavaBigDecimalParser.parseBigDecimal(valueStr);
96-
} catch (NumberFormatException nfe) {
97-
final String reportNum = valueStr.length() <= MAX_CHARS_TO_REPORT ?
98-
valueStr : valueStr.substring(0, MAX_CHARS_TO_REPORT) + " [truncated]";
99-
throw new NumberFormatException("Value \"" + reportNum
100-
+ "\" can not be represented as `java.math.BigDecimal`, reason: " + nfe.getMessage());
99+
} catch (ArithmeticException | NumberFormatException e) {
100+
throw _parseFailure(e, valueStr);
101101
}
102102
}
103103

104+
/**
105+
* Internal Jackson method. Please do not use.
106+
*<p>
107+
* Note: Caller MUST pre-validate that given String represents a valid representation
108+
* of {@link BigDecimal} value: parsers in {@code jackson-core} do that; other
109+
* code must do the same.
110+
*
111+
* @return BigDecimal value
112+
* @throws NumberFormatException
113+
*/
104114
public static BigDecimal parseWithFastParser(final char[] ch, final int off, final int len) {
105115
try {
106116
return JavaBigDecimalParser.parseBigDecimal(ch, off, len);
107-
} catch (NumberFormatException nfe) {
108-
final String reportNum = len <= MAX_CHARS_TO_REPORT ?
109-
new String(ch, off, len) : new String(ch, off, MAX_CHARS_TO_REPORT) + " [truncated]";
110-
throw new NumberFormatException("Value \"" + reportNum
111-
+ "\" can not be represented as `java.math.BigDecimal`, reason: " + nfe.getMessage());
117+
} catch (ArithmeticException | NumberFormatException e) {
118+
throw _parseFailure(e, new String(ch, off, len));
112119
}
113120
}
121+
122+
private static NumberFormatException _parseFailure(Exception e, String fullValue) {
123+
String desc = e.getMessage();
124+
// 05-Feb-2021, tatu: Alas, JDK mostly has null message so:
125+
if (desc == null) {
126+
desc = "Not a valid number representation";
127+
}
128+
String valueToReport = _getValueDesc(fullValue);
129+
return new NumberFormatException("Value " + valueToReport
130+
+ " can not be deserialized as `java.math.BigDecimal`, reason: " + desc);
131+
}
132+
133+
private static String _getValueDesc(String fullValue) {
134+
final int len = fullValue.length();
135+
if (len <= MAX_CHARS_TO_REPORT) {
136+
return String.format("\"%s\"", fullValue);
137+
}
138+
return String.format("\"%s\" (truncated to %d chars (from %d))",
139+
fullValue.substring(0, MAX_CHARS_TO_REPORT),
140+
MAX_CHARS_TO_REPORT, len);
141+
}
142+
114143
}

src/test/java/com/fasterxml/jackson/core/json/async/AsyncNaNHandlingTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ private void _testAllowNaN(JsonFactory f, String doc, int readBytes) throws Exce
6060
/*BigDecimal dec =*/ p.getDecimalValue();
6161
fail("Should fail when trying to access NaN as BigDecimal");
6262
} catch (NumberFormatException e) {
63-
verifyException(e, "can not be represented as `java.math.BigDecimal`");
63+
verifyException(e, "can not be deserialized as `java.math.BigDecimal`");
6464
}
6565

6666
assertToken(JsonToken.END_ARRAY, p.nextToken());

src/test/java/com/fasterxml/jackson/core/read/NonStandardParserFeaturesTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ private void _testAllowNaN(int mode) throws Exception
186186
/*BigDecimal dec =*/ p.getDecimalValue();
187187
fail("Should fail when trying to access NaN as BigDecimal");
188188
} catch (NumberFormatException e) {
189-
verifyException(e, "can not be represented as `java.math.BigDecimal`");
189+
verifyException(e, "can not be deserialized as `java.math.BigDecimal`");
190190
}
191191

192192
assertToken(JsonToken.END_ARRAY, p.nextToken());

0 commit comments

Comments
 (0)