Skip to content

Commit fbc1fa2

Browse files
committed
Fixed #1404. And tons of assorted related improvements to try to pipe targetType to input mismatch exception.
1 parent d068a40 commit fbc1fa2

32 files changed

+305
-148
lines changed

src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java

+121-21
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,11 @@ public Object handleMissingInstantiator(Class<?> instClass, JsonParser p,
10121012
}
10131013
h = h.next();
10141014
}
1015-
throw instantiationException(instClass, msg);
1015+
// 06-Oct-2016, tatu: This is input mismatch problem, in that absence of
1016+
// creator implies that incoming content type or structure is wrong
1017+
msg = String.format("Can not construct instance of %s, problem: %s",
1018+
instClass.getName(), msg);
1019+
return reportInputMismatch(instClass, msg);
10161020
}
10171021

10181022
/**
@@ -1108,9 +1112,9 @@ public Object handleUnexpectedToken(Class<?> instClass, JsonToken t,
11081112
if ((instance == null) || instClass.isInstance(instance)) {
11091113
return instance;
11101114
}
1111-
reportInputMismatch(
1115+
reportInputMismatch(instClass,
11121116
"DeserializationProblemHandler.handleUnexpectedToken() for type %s returned value of type %s",
1113-
instClass, instance.getClass());
1117+
instance.getClass());
11141118
}
11151119
h = h.next();
11161120
}
@@ -1123,7 +1127,7 @@ public Object handleUnexpectedToken(Class<?> instClass, JsonToken t,
11231127
_calcName(instClass), t);
11241128
}
11251129
}
1126-
reportInputMismatch(msg);
1130+
reportInputMismatch(instClass, msg);
11271131
return null; // never gets here
11281132
}
11291133

@@ -1189,8 +1193,59 @@ public JavaType handleUnknownTypeId(JavaType baseType, String id,
11891193
* recovery is attempted (via {@link DeserializationProblemHandler}, as
11901194
* problem is considered to be difficult to recover from, in general.
11911195
*
1192-
* @since 2.8
1196+
* @since 2.9
1197+
*/
1198+
public void reportWrongTokenException(JsonDeserializer<?> deser,
1199+
JsonToken expToken, String msg, Object... msgArgs)
1200+
throws JsonMappingException
1201+
{
1202+
if ((msg != null) && (msgArgs.length > 0)) {
1203+
msg = String.format(msg, msgArgs);
1204+
}
1205+
throw wrongTokenException(getParser(), deser.handledType(), expToken, msg);
1206+
}
1207+
1208+
/**
1209+
* Method for deserializers to call
1210+
* when the token encountered was of type different than what <b>should</b>
1211+
* be seen at that position, usually within a sequence of expected tokens.
1212+
* Note that this method will throw a {@link JsonMappingException} and no
1213+
* recovery is attempted (via {@link DeserializationProblemHandler}, as
1214+
* problem is considered to be difficult to recover from, in general.
1215+
*
1216+
* @since 2.9
11931217
*/
1218+
public void reportWrongTokenException(JavaType targetType,
1219+
JsonToken expToken, String msg, Object... msgArgs)
1220+
throws JsonMappingException
1221+
{
1222+
if ((msg != null) && (msgArgs.length > 0)) {
1223+
msg = String.format(msg, msgArgs);
1224+
}
1225+
throw wrongTokenException(getParser(), targetType, expToken, msg);
1226+
}
1227+
1228+
/**
1229+
* Method for deserializers to call
1230+
* when the token encountered was of type different than what <b>should</b>
1231+
* be seen at that position, usually within a sequence of expected tokens.
1232+
* Note that this method will throw a {@link JsonMappingException} and no
1233+
* recovery is attempted (via {@link DeserializationProblemHandler}, as
1234+
* problem is considered to be difficult to recover from, in general.
1235+
*
1236+
* @since 2.9
1237+
*/
1238+
public void reportWrongTokenException(Class<?> targetType,
1239+
JsonToken expToken, String msg, Object... msgArgs)
1240+
throws JsonMappingException
1241+
{
1242+
if ((msg != null) && (msgArgs.length > 0)) {
1243+
msg = String.format(msg, msgArgs);
1244+
}
1245+
throw wrongTokenException(getParser(), targetType, expToken, msg);
1246+
}
1247+
1248+
@Deprecated // since 2.9
11941249
public void reportWrongTokenException(JsonParser p,
11951250
JsonToken expToken, String msg, Object... msgArgs)
11961251
throws JsonMappingException
@@ -1228,7 +1283,10 @@ public void reportUnknownProperty(Object instanceOrClass, String fieldName,
12281283

12291284
/**
12301285
* @since 2.8
1286+
*
1287+
* @deprecated Since 2.9: not clear this ever occurs
12311288
*/
1289+
@Deprecated // since 2.9
12321290
public void reportMissingContent(String msg, Object... msgArgs)
12331291
throws JsonMappingException
12341292
{
@@ -1237,7 +1295,7 @@ public void reportMissingContent(String msg, Object... msgArgs)
12371295
} else if (msgArgs.length > 0) {
12381296
msg = String.format(msg, msgArgs);
12391297
}
1240-
throw InputMismatchException.from(getParser(), msg);
1298+
throw InputMismatchException.from(getParser(), (JavaType) null, msg);
12411299
}
12421300

12431301
/**
@@ -1257,10 +1315,13 @@ public <T> T reportUnresolvedObjectId(ObjectIdReader oidReader, Object bean)
12571315
*
12581316
* @since 2.9
12591317
*/
1260-
public <T> T reportInputMismatch(BeanProperty prop, String msg)
1261-
throws JsonMappingException
1318+
public <T> T reportInputMismatch(BeanProperty prop,
1319+
String msg, Object... msgArgs) throws JsonMappingException
12621320
{
1263-
throw InputMismatchException.from(getParser(), msg);
1321+
if (msgArgs.length > 0) {
1322+
msg = String.format(msg, msgArgs);
1323+
}
1324+
throw InputMismatchException.from(getParser(), prop.getType(), msg);
12641325
}
12651326

12661327
/**
@@ -1269,10 +1330,13 @@ public <T> T reportInputMismatch(BeanProperty prop, String msg)
12691330
*
12701331
* @since 2.9
12711332
*/
1272-
public <T> T reportInputMismatch(JsonDeserializer<?> src, String msg)
1273-
throws JsonMappingException
1333+
public <T> T reportInputMismatch(JsonDeserializer<?> src,
1334+
String msg, Object... msgArgs) throws JsonMappingException
12741335
{
1275-
throw InputMismatchException.from(getParser(), msg);
1336+
if (msgArgs.length > 0) {
1337+
msg = String.format(msg, msgArgs);
1338+
}
1339+
throw InputMismatchException.from(getParser(), src.handledType(), msg);
12761340
}
12771341

12781342
/**
@@ -1281,14 +1345,30 @@ public <T> T reportInputMismatch(JsonDeserializer<?> src, String msg)
12811345
*
12821346
* @since 2.9
12831347
*/
1284-
public <T> T reportInputMismatch(String msg, Object... msgArgs) throws JsonMappingException
1348+
public <T> T reportInputMismatch(Class<?> targetType,
1349+
String msg, Object... msgArgs) throws JsonMappingException
12851350
{
12861351
if (msgArgs.length > 0) {
12871352
msg = String.format(msg, msgArgs);
12881353
}
1289-
throw InputMismatchException.from(getParser(), msg);
1354+
throw InputMismatchException.from(getParser(), targetType, msg);
12901355
}
12911356

1357+
/**
1358+
* Helper method used to indicate a problem with input in cases where more
1359+
* specific <code>reportXxx()</code> method was not available.
1360+
*
1361+
* @since 2.9
1362+
*/
1363+
public <T> T reportInputMismatch(JavaType targetType,
1364+
String msg, Object... msgArgs) throws JsonMappingException
1365+
{
1366+
if (msgArgs.length > 0) {
1367+
msg = String.format(msg, msgArgs);
1368+
}
1369+
throw InputMismatchException.from(getParser(), targetType, msg);
1370+
}
1371+
12921372
/*
12931373
/**********************************************************
12941374
/* Methods for problem reporting, in cases where recovery
@@ -1352,16 +1432,36 @@ public <T> T reportBadDefinition(JavaType type, String msg) throws JsonMappingEx
13521432
* Note that most of the time this method should NOT be directly called;
13531433
* instead, {@link #reportWrongTokenException} should be called and will
13541434
* call this method as necessary.
1435+
*
1436+
* @since 2.9
13551437
*/
1356-
public JsonMappingException wrongTokenException(JsonParser p, JsonToken expToken,
1357-
String msg0)
1438+
public JsonMappingException wrongTokenException(JsonParser p, JavaType targetType,
1439+
JsonToken expToken, String msg0)
13581440
{
13591441
String msg = String.format("Unexpected token (%s), expected %s",
13601442
p.getCurrentToken(), expToken);
13611443
if (msg0 != null) {
13621444
msg = msg + ": "+msg0;
13631445
}
1364-
return InputMismatchException.from(p, msg);
1446+
return InputMismatchException.from(p, targetType, msg);
1447+
}
1448+
1449+
public JsonMappingException wrongTokenException(JsonParser p, Class<?> targetType,
1450+
JsonToken expToken, String msg0)
1451+
{
1452+
String msg = String.format("Unexpected token (%s), expected %s",
1453+
p.getCurrentToken(), expToken);
1454+
if (msg0 != null) {
1455+
msg = msg + ": "+msg0;
1456+
}
1457+
return InputMismatchException.from(p, targetType, msg);
1458+
}
1459+
1460+
@Deprecated // since 2.9
1461+
public JsonMappingException wrongTokenException(JsonParser p, JsonToken expToken,
1462+
String msg)
1463+
{
1464+
return wrongTokenException(p, (JavaType) null, expToken, msg);
13651465
}
13661466

13671467
/**
@@ -1489,7 +1589,7 @@ public JsonMappingException unknownTypeException(JavaType type, String id,
14891589
if (extraDesc != null) {
14901590
msg = msg + ": "+extraDesc;
14911591
}
1492-
return JsonMappingException.from(_parser, msg);
1592+
return InputMismatchException.from(_parser, type, msg);
14931593
}
14941594

14951595
/**
@@ -1500,8 +1600,8 @@ public JsonMappingException unknownTypeException(JavaType type, String id,
15001600
*/
15011601
@Deprecated
15021602
public JsonMappingException endOfInputException(Class<?> instClass) {
1503-
return JsonMappingException.from(_parser, "Unexpected end-of-input when trying to deserialize a "
1504-
+instClass.getName());
1603+
return InputMismatchException.from(_parser, instClass,
1604+
"Unexpected end-of-input when trying to deserialize a "+instClass.getName());
15051605
}
15061606

15071607
/*
@@ -1519,7 +1619,7 @@ public JsonMappingException endOfInputException(Class<?> instClass) {
15191619
* @since 2.8
15201620
*
15211621
* @deprecate Since 2.9: use a more specific method, or {@link #reportBadDefinition(JavaType, String)},
1522-
* or {@link #reportInputMismatch(String, Object...)} instead
1622+
* or {@link #reportInputMismatch} instead
15231623
*/
15241624
@Deprecated // since 2.9
15251625
public void reportMappingException(String msg, Object... msgArgs)

src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -317,12 +317,12 @@ public static JsonMappingException from(SerializerProvider ctxt, String msg, Thr
317317
* Factory method used when "upgrading" an {@link IOException} into
318318
* {@link JsonMappingException}: usually only needed to comply with
319319
* a signature.
320+
*<p>
321+
* NOTE: since 2.9 should usually NOT be used on input-side (deserialization)
322+
* exceptions; instead use method(s) of <code>InputMismatchException</code>
320323
*
321324
* @since 2.1
322-
*
323-
* @deprecated Since 2.9 call method on {@link InputMismatchException} instead
324325
*/
325-
@Deprecated
326326
public static JsonMappingException fromUnexpectedIOE(IOException src) {
327327
return new JsonMappingException(null,
328328
String.format("Unexpected IOException (of type %s): %s",

src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java

+23-15
Original file line numberDiff line numberDiff line change
@@ -3065,7 +3065,7 @@ public String writeValueAsString(Object value)
30653065
} catch (JsonProcessingException e) {
30663066
throw e;
30673067
} catch (IOException e) { // shouldn't really happen, but is declared as possibility so:
3068-
throw InputMismatchException.fromUnexpectedIOE(e);
3068+
throw JsonMappingException.fromUnexpectedIOE(e);
30693069
}
30703070
return sw.getAndClear();
30713071
}
@@ -3089,7 +3089,7 @@ public byte[] writeValueAsBytes(Object value)
30893089
} catch (JsonProcessingException e) { // to support [JACKSON-758]
30903090
throw e;
30913091
} catch (IOException e) { // shouldn't really happen, but is declared as possibility so:
3092-
throw InputMismatchException.fromUnexpectedIOE(e);
3092+
throw JsonMappingException.fromUnexpectedIOE(e);
30933093
}
30943094
byte[] result = bb.toByteArray();
30953095
bb.release();
@@ -3578,7 +3578,7 @@ protected Object _convert(Object fromValue, JavaType toValueType)
35783578
Object result;
35793579
// ok to pass in existing feature flags; unwrapping handled by mapper
35803580
final DeserializationConfig deserConfig = getDeserializationConfig();
3581-
JsonToken t = _initForReading(p);
3581+
JsonToken t = _initForReading(p, toValueType);
35823582
if (t == JsonToken.VALUE_NULL) {
35833583
DeserializationContext ctxt = createDeserializationContext(p, deserConfig);
35843584
result = _findRootDeserializer(ctxt, toValueType).getNullValue(ctxt);
@@ -3752,15 +3752,16 @@ protected DefaultDeserializationContext createDeserializationContext(JsonParser
37523752
/**
37533753
* Actual implementation of value reading+binding operation.
37543754
*/
3755-
protected Object _readValue(DeserializationConfig cfg, JsonParser p, JavaType valueType)
3755+
protected Object _readValue(DeserializationConfig cfg, JsonParser p,
3756+
JavaType valueType)
37563757
throws IOException
37573758
{
37583759
/* First: may need to read the next token, to initialize
37593760
* state (either before first read from parser, or after
37603761
* previous token has been cleared)
37613762
*/
37623763
Object result;
3763-
JsonToken t = _initForReading(p);
3764+
JsonToken t = _initForReading(p, valueType);
37643765
if (t == JsonToken.VALUE_NULL) {
37653766
// Ask JsonDeserializer what 'null value' to use:
37663767
DeserializationContext ctxt = createDeserializationContext(p, cfg);
@@ -3781,13 +3782,13 @@ protected Object _readValue(DeserializationConfig cfg, JsonParser p, JavaType va
37813782
p.clearCurrentToken();
37823783
return result;
37833784
}
3784-
3785+
37853786
protected Object _readMapAndClose(JsonParser p0, JavaType valueType)
37863787
throws IOException
37873788
{
37883789
try (JsonParser p = p0) {
37893790
Object result;
3790-
JsonToken t = _initForReading(p);
3791+
JsonToken t = _initForReading(p, valueType);
37913792
if (t == JsonToken.VALUE_NULL) {
37923793
// Ask JsonDeserializer what 'null value' to use:
37933794
DeserializationContext ctxt = createDeserializationContext(p,
@@ -3827,7 +3828,7 @@ protected Object _readMapAndClose(JsonParser p0, JavaType valueType)
38273828
* content to map (note: Json "null" value is considered content;
38283829
* enf-of-stream not)
38293830
*/
3830-
protected JsonToken _initForReading(JsonParser p) throws IOException
3831+
protected JsonToken _initForReading(JsonParser p, JavaType targetType) throws IOException
38313832
{
38323833
_deserializationConfig.initialize(p); // since 2.5
38333834

@@ -3842,12 +3843,18 @@ protected JsonToken _initForReading(JsonParser p) throws IOException
38423843
if (t == null) {
38433844
// Throw mapping exception, since it's failure to map,
38443845
// not an actual parsing problem
3845-
throw InputMismatchException.from(p, "No content to map due to end-of-input");
3846+
throw InputMismatchException.from(p, targetType,
3847+
"No content to map due to end-of-input");
38463848
}
38473849
}
38483850
return t;
38493851
}
38503852

3853+
@Deprecated // since 2.9, use method that takes JavaType too
3854+
protected JsonToken _initForReading(JsonParser p) throws IOException {
3855+
return _initForReading(p, null);
3856+
}
3857+
38513858
protected Object _unwrapAndDeserialize(JsonParser p, DeserializationContext ctxt,
38523859
DeserializationConfig config,
38533860
JavaType rootType, JsonDeserializer<Object> deser)
@@ -3857,33 +3864,34 @@ protected Object _unwrapAndDeserialize(JsonParser p, DeserializationContext ctxt
38573864
// 12-Jun-2015, tatu: Should try to support namespaces etc but...
38583865
String expSimpleName = expRootName.getSimpleName();
38593866
if (p.getCurrentToken() != JsonToken.START_OBJECT) {
3860-
ctxt.reportWrongTokenException(p, JsonToken.START_OBJECT,
3867+
ctxt.reportWrongTokenException(rootType, JsonToken.START_OBJECT,
38613868
"Current token not START_OBJECT (needed to unwrap root name '%s'), but %s",
38623869
expSimpleName, p.getCurrentToken());
38633870

38643871
}
38653872
if (p.nextToken() != JsonToken.FIELD_NAME) {
3866-
ctxt.reportWrongTokenException(p, JsonToken.FIELD_NAME,
3873+
ctxt.reportWrongTokenException(rootType, JsonToken.FIELD_NAME,
38673874
"Current token not FIELD_NAME (to contain expected root name '"
38683875
+expSimpleName+"'), but "+p.getCurrentToken());
38693876
}
38703877
String actualName = p.getCurrentName();
38713878
if (!expSimpleName.equals(actualName)) {
3872-
ctxt.reportInputMismatch("Root name '%s' does not match expected ('%s') for type %s",
3873-
actualName, expSimpleName, rootType);
3879+
ctxt.reportInputMismatch(rootType,
3880+
"Root name '%s' does not match expected ('%s') for type %s",
3881+
actualName, expSimpleName);
38743882
}
38753883
// ok, then move to value itself....
38763884
p.nextToken();
38773885
Object result = deser.deserialize(p, ctxt);
38783886
// and last, verify that we now get matching END_OBJECT
38793887
if (p.nextToken() != JsonToken.END_OBJECT) {
3880-
ctxt.reportWrongTokenException(p, JsonToken.END_OBJECT,
3888+
ctxt.reportWrongTokenException(rootType, JsonToken.END_OBJECT,
38813889
"Current token not END_OBJECT (to match wrapper object with root name '%s'), but %s",
38823890
expSimpleName, p.getCurrentToken());
38833891
}
38843892
return result;
38853893
}
3886-
3894+
38873895
/*
38883896
/**********************************************************
38893897
/* Internal methods, other

0 commit comments

Comments
 (0)