Skip to content

Commit c4dd84e

Browse files
committed
Fix #508
1 parent 35f3ab4 commit c4dd84e

File tree

8 files changed

+123
-35
lines changed

8 files changed

+123
-35
lines changed

release-notes/VERSION-2.x

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ JSON library.
2828
#496: Create `StreamWriteFeature` to take over non-json-specific `JsonGenerator.Feature`s
2929
#502: Make `DefaultPrettyPrinter.createInstance()` to fail for sub-classes
3030
#506: Add missing type parameter for `TypeReference` in `ObjectCodec`
31+
#508: Add new exception type `InputCoercionException` to be used for failed coercions
32+
like overflow for `int`
3133

3234
2.9.8 (15-Dec-2018)
3335

src/main/java/com/fasterxml/jackson/core/base/ParserBase.java

+8-6
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ private void _parseSlowInt(int expType) throws IOException
846846
} else {
847847
// 16-Oct-2018, tatu: Need to catch "too big" early due to [jackson-core#488]
848848
if ((expType == NR_INT) || (expType == NR_LONG)) {
849-
_reportTooLongInt(expType, numStr);
849+
_reportTooLongIntegral(expType, numStr);
850850
}
851851
if ((expType == NR_DOUBLE) || (expType == NR_FLOAT)) {
852852
_numberDouble = NumberInput.parseDouble(numStr);
@@ -864,11 +864,13 @@ private void _parseSlowInt(int expType) throws IOException
864864
}
865865

866866
// @since 2.9.8
867-
protected void _reportTooLongInt(int expType, String rawNum) throws IOException
867+
protected void _reportTooLongIntegral(int expType, String rawNum) throws IOException
868868
{
869-
final String numDesc = _longIntegerDesc(rawNum);
870-
_reportError("Numeric value (%s) out of range of %s", numDesc,
871-
(expType == NR_LONG) ? "long" : "int");
869+
if (expType == NR_INT) {
870+
reportOverflowInt(rawNum);
871+
} else {
872+
reportOverflowLong(rawNum);
873+
}
872874
}
873875

874876
/*
@@ -884,7 +886,7 @@ protected void convertNumberToInt() throws IOException
884886
// Let's verify it's lossless conversion by simple roundtrip
885887
int result = (int) _numberLong;
886888
if (((long) result) != _numberLong) {
887-
_reportError("Numeric value ("+getText()+") out of range of int");
889+
reportOverflowInt(getText(), currentToken());
888890
}
889891
_numberInt = result;
890892
} else if ((_numTypesValid & NR_BIGINT) != 0) {

src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java

+51-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.math.BigInteger;
66

77
import com.fasterxml.jackson.core.*;
8+
import com.fasterxml.jackson.core.exc.InputCoercionException;
89
import com.fasterxml.jackson.core.io.JsonEOFException;
910
import com.fasterxml.jackson.core.io.NumberInput;
1011
import com.fasterxml.jackson.core.util.ByteArrayBuilder;
@@ -540,18 +541,64 @@ protected void reportUnexpectedNumberChar(int ch, String comment) throws JsonPar
540541
_reportError(msg);
541542
}
542543

544+
/**
545+
* Method called to throw an exception for input token that looks like a number
546+
* based on first character(s), but is not valid according to rules of format.
547+
* In case of JSON this also includes invalid forms like positive sign and
548+
* leading zeroes.
549+
*/
543550
protected void reportInvalidNumber(String msg) throws JsonParseException {
544551
_reportError("Invalid numeric value: "+msg);
545552
}
546553

554+
/**
555+
* Method called to throw an exception for integral (not floating point) input
556+
* token with value outside of Java signed 32-bit range when requested as {@link int}.
557+
* Result will be {@link InputCoercionException} being thrown.
558+
*/
547559
protected void reportOverflowInt() throws IOException {
548-
_reportError(String.format("Numeric value (%s) out of range of int (%d - %s)",
549-
_longIntegerDesc(getText()), Integer.MIN_VALUE, Integer.MAX_VALUE));
560+
reportOverflowInt(getText());
550561
}
551562

563+
// @since 2.10
564+
protected void reportOverflowInt(String numDesc) throws IOException {
565+
reportOverflowInt(numDesc, JsonToken.VALUE_NUMBER_INT);
566+
}
567+
568+
// @since 2.10
569+
protected void reportOverflowInt(String numDesc, JsonToken inputType) throws IOException {
570+
_reportInputCoercion(String.format("Numeric value (%s) out of range of int (%d - %s)",
571+
_longIntegerDesc(numDesc), Integer.MIN_VALUE, Integer.MAX_VALUE),
572+
inputType, Integer.TYPE);
573+
}
574+
575+
/**
576+
* Method called to throw an exception for integral (not floating point) input
577+
* token with value outside of Java signed 64-bit range when requested as {@link long}.
578+
* Result will be {@link InputCoercionException} being thrown.
579+
*/
552580
protected void reportOverflowLong() throws IOException {
553-
_reportError(String.format("Numeric value (%s) out of range of long (%d - %s)",
554-
_longIntegerDesc(getText()), Long.MIN_VALUE, Long.MAX_VALUE));
581+
reportOverflowLong(getText());
582+
}
583+
584+
// @since 2.10
585+
protected void reportOverflowLong(String numDesc) throws IOException {
586+
reportOverflowLong(numDesc, JsonToken.VALUE_NUMBER_INT);
587+
}
588+
589+
// @since 2.10
590+
protected void reportOverflowLong(String numDesc, JsonToken inputType) throws IOException {
591+
_reportInputCoercion(String.format("Numeric value (%s) out of range of long (%d - %s)",
592+
_longIntegerDesc(numDesc), Long.MIN_VALUE, Long.MAX_VALUE),
593+
inputType, Long.TYPE);
594+
}
595+
596+
/**
597+
* @since 2.10
598+
*/
599+
protected void _reportInputCoercion(String msg, JsonToken inputType, Class<?> targetType)
600+
throws InputCoercionException {
601+
throw new InputCoercionException(this, msg, inputType, targetType);
555602
}
556603

557604
// @since 2.9.8

src/main/java/com/fasterxml/jackson/core/exc/InputCoercionException.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public class InputCoercionException extends StreamReadException {
3030
* sets processor (accessible via {@link #getProcessor()}) to
3131
* specified parser.
3232
*/
33-
public InputCoercionException(JsonParser p, JsonToken inputType, Class<?> targetType,
34-
String msg) {
33+
public InputCoercionException(JsonParser p, String msg,
34+
JsonToken inputType, Class<?> targetType) {
3535
super(p, msg);
3636
_inputType = inputType;
3737
_targetType = targetType;

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

+25-9
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
import java.math.BigInteger;
66

77
import com.fasterxml.jackson.core.JsonFactory;
8-
import com.fasterxml.jackson.core.JsonParseException;
98
import com.fasterxml.jackson.core.JsonParser.NumberType;
109
import com.fasterxml.jackson.core.async.AsyncTestBase;
10+
import com.fasterxml.jackson.core.exc.InputCoercionException;
1111
import com.fasterxml.jackson.core.testsupport.AsyncReaderWrapper;
1212
import com.fasterxml.jackson.core.JsonToken;
1313

@@ -72,8 +72,10 @@ public void testToIntFailing() throws Exception
7272
try {
7373
p.getIntValue();
7474
fail("Should not pass");
75-
} catch (JsonParseException e) {
75+
} catch (InputCoercionException e) {
7676
verifyException(e, "out of range of int");
77+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
78+
assertEquals(Integer.TYPE, e.getTargetType());
7779
}
7880
long small = -1L + Integer.MIN_VALUE;
7981
p = createParser(String.valueOf(small));
@@ -83,8 +85,10 @@ public void testToIntFailing() throws Exception
8385
try {
8486
p.getIntValue();
8587
fail("Should not pass");
86-
} catch (JsonParseException e) {
88+
} catch (InputCoercionException e) {
8789
verifyException(e, "out of range of int");
90+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
91+
assertEquals(Integer.TYPE, e.getTargetType());
8892
}
8993

9094
// double -> error
@@ -94,17 +98,21 @@ public void testToIntFailing() throws Exception
9498
try {
9599
p.getIntValue();
96100
fail("Should not pass");
97-
} catch (JsonParseException e) {
101+
} catch (InputCoercionException e) {
98102
verifyException(e, "out of range of int");
103+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
104+
assertEquals(Integer.TYPE, e.getTargetType());
99105
}
100106
p = createParser(String.valueOf(small)+".0");
101107
assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
102108
assertEquals((double) small, p.getDoubleValue());
103109
try {
104110
p.getIntValue();
105111
fail("Should not pass");
106-
} catch (JsonParseException e) {
112+
} catch (InputCoercionException e) {
107113
verifyException(e, "out of range of int");
114+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
115+
assertEquals(Integer.TYPE, e.getTargetType());
108116
}
109117

110118
// BigInteger -> error
@@ -114,17 +122,21 @@ public void testToIntFailing() throws Exception
114122
try {
115123
p.getIntValue();
116124
fail("Should not pass");
117-
} catch (JsonParseException e) {
125+
} catch (InputCoercionException e) {
118126
verifyException(e, "out of range of int");
127+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
128+
assertEquals(Integer.TYPE, e.getTargetType());
119129
}
120130
p = createParser(String.valueOf(small));
121131
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
122132
assertEquals(BigInteger.valueOf(small), p.getBigIntegerValue());
123133
try {
124134
p.getIntValue();
125135
fail("Should not pass");
126-
} catch (JsonParseException e) {
136+
} catch (InputCoercionException e) {
127137
verifyException(e, "out of range of int");
138+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
139+
assertEquals(Integer.TYPE, e.getTargetType());
128140
}
129141
}
130142

@@ -176,8 +188,10 @@ public void testToLongFailing() throws Exception
176188
try {
177189
p.getLongValue();
178190
fail("Should not pass");
179-
} catch (JsonParseException e) {
191+
} catch (InputCoercionException e) {
180192
verifyException(e, "out of range of long");
193+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
194+
assertEquals(Long.TYPE, e.getTargetType());
181195
}
182196
BigInteger small = BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.TEN);
183197
p = createParser(String.valueOf(small));
@@ -186,8 +200,10 @@ public void testToLongFailing() throws Exception
186200
try {
187201
p.getLongValue();
188202
fail("Should not pass");
189-
} catch (JsonParseException e) {
203+
} catch (InputCoercionException e) {
190204
verifyException(e, "out of range of long");
205+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
206+
assertEquals(Long.TYPE, e.getTargetType());
191207
}
192208
}
193209

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

+25-8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.fasterxml.jackson.core.JsonParser;
99
import com.fasterxml.jackson.core.JsonParser.NumberType;
1010
import com.fasterxml.jackson.core.JsonToken;
11+
import com.fasterxml.jackson.core.exc.InputCoercionException;
1112

1213
public class NumberCoercionTest extends BaseTest
1314
{
@@ -66,8 +67,10 @@ public void testToIntFailing() throws Exception
6667
try {
6768
p.getIntValue();
6869
fail("Should not pass");
69-
} catch (JsonParseException e) {
70+
} catch (InputCoercionException e) {
7071
verifyException(e, "out of range of int");
72+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
73+
assertEquals(Integer.TYPE, e.getTargetType());
7174
}
7275
long small = -1L + Integer.MIN_VALUE;
7376
p = createParser(mode, String.valueOf(small));
@@ -77,8 +80,10 @@ public void testToIntFailing() throws Exception
7780
try {
7881
p.getIntValue();
7982
fail("Should not pass");
80-
} catch (JsonParseException e) {
83+
} catch (InputCoercionException e) {
8184
verifyException(e, "out of range of int");
85+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
86+
assertEquals(Integer.TYPE, e.getTargetType());
8287
}
8388

8489
// double -> error
@@ -88,17 +93,21 @@ public void testToIntFailing() throws Exception
8893
try {
8994
p.getIntValue();
9095
fail("Should not pass");
91-
} catch (JsonParseException e) {
96+
} catch (InputCoercionException e) {
9297
verifyException(e, "out of range of int");
98+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
99+
assertEquals(Integer.TYPE, e.getTargetType());
93100
}
94101
p = createParser(mode, String.valueOf(small)+".0");
95102
assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
96103
assertEquals((double) small, p.getDoubleValue());
97104
try {
98105
p.getIntValue();
99106
fail("Should not pass");
100-
} catch (JsonParseException e) {
107+
} catch (InputCoercionException e) {
101108
verifyException(e, "out of range of int");
109+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
110+
assertEquals(Integer.TYPE, e.getTargetType());
102111
}
103112

104113
// BigInteger -> error
@@ -108,17 +117,21 @@ public void testToIntFailing() throws Exception
108117
try {
109118
p.getIntValue();
110119
fail("Should not pass");
111-
} catch (JsonParseException e) {
120+
} catch (InputCoercionException e) {
112121
verifyException(e, "out of range of int");
122+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
123+
assertEquals(Integer.TYPE, e.getTargetType());
113124
}
114125
p = createParser(mode, String.valueOf(small));
115126
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
116127
assertEquals(BigInteger.valueOf(small), p.getBigIntegerValue());
117128
try {
118129
p.getIntValue();
119130
fail("Should not pass");
120-
} catch (JsonParseException e) {
131+
} catch (InputCoercionException e) {
121132
verifyException(e, "out of range of int");
133+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
134+
assertEquals(Integer.TYPE, e.getTargetType());
122135
}
123136
}
124137
}
@@ -175,8 +188,10 @@ public void testToLongFailing() throws Exception
175188
try {
176189
p.getLongValue();
177190
fail("Should not pass");
178-
} catch (JsonParseException e) {
191+
} catch (InputCoercionException e) {
179192
verifyException(e, "out of range of long");
193+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
194+
assertEquals(Long.TYPE, e.getTargetType());
180195
}
181196
BigInteger small = BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.TEN);
182197
p = createParser(mode, String.valueOf(small));
@@ -185,8 +200,10 @@ public void testToLongFailing() throws Exception
185200
try {
186201
p.getLongValue();
187202
fail("Should not pass");
188-
} catch (JsonParseException e) {
203+
} catch (InputCoercionException e) {
189204
verifyException(e, "out of range of long");
205+
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
206+
assertEquals(Long.TYPE, e.getTargetType());
190207
}
191208
}
192209
}

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

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.math.BigInteger;
44

55
import com.fasterxml.jackson.core.*;
6+
import com.fasterxml.jackson.core.exc.InputCoercionException;
67

78
public class NumberOverflowTest
89
extends com.fasterxml.jackson.core.BaseTest
@@ -39,7 +40,7 @@ public void testSimpleLongOverflow() throws Exception
3940
try {
4041
long x = p.getLongValue();
4142
fail("Expected an exception for underflow (input "+p.getText()+"): instead, got long value: "+x);
42-
} catch (JsonParseException e) {
43+
} catch (InputCoercionException e) {
4344
verifyException(e, "out of range of long");
4445
}
4546
p.close();
@@ -49,7 +50,7 @@ public void testSimpleLongOverflow() throws Exception
4950
try {
5051
long x = p.getLongValue();
5152
fail("Expected an exception for underflow (input "+p.getText()+"): instead, got long value: "+x);
52-
} catch (JsonParseException e) {
53+
} catch (InputCoercionException e) {
5354
verifyException(e, "out of range of long");
5455
}
5556
p.close();
@@ -70,7 +71,7 @@ public void testMaliciousLongOverflow() throws Exception
7071
try {
7172
p.getLongValue();
7273
fail("Should not pass");
73-
} catch (JsonParseException e) {
74+
} catch (InputCoercionException e) {
7475
verifyException(e, "out of range of long");
7576
verifyException(e, "Integer with "+BIG_NUM_LEN+" digits");
7677
}
@@ -90,7 +91,7 @@ public void testMaliciousIntOverflow() throws Exception
9091
try {
9192
p.getIntValue();
9293
fail("Should not pass");
93-
} catch (JsonParseException e) {
94+
} catch (InputCoercionException e) {
9495
verifyException(e, "out of range of int");
9596
verifyException(e, "Integer with "+BIG_NUM_LEN+" digits");
9697
}

0 commit comments

Comments
 (0)