Skip to content

Commit 609a0f8

Browse files
committed
further work on #1207, now first of 2 instantion problem handlers
1 parent e75731b commit 609a0f8

12 files changed

+182
-64
lines changed

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

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,23 @@ public Object handleWeirdNumberValue(Class<?> targetClass, Number value,
959959
}
960960

961961
/**
962+
* Method that deserializers should call if they encounter a type id
963+
* (for polymorphic deserialization) that can not be resolved to an
964+
* actual type; usually since there is no mapping defined.
965+
* Default implementation will try to call {@link DeserializationProblemHandler#handleUnknownTypeId}
966+
* on configured handlers, if any, to allow for recovery; if recovery does not
967+
* succeed, will throw exception constructed with {@link #unknownTypeIdException}.
968+
*
969+
* @param baseType Base type from which resolution starts
970+
* @param id Type id that could not be converted
971+
* @param extraDesc Additional problem description to add to default exception message,
972+
* if resolution fails.
973+
*
974+
* @return {@link JavaType} that id resolves to
975+
*
976+
* @throws IOException To indicate unrecoverable problem, if resolution can not
977+
* be made to work
978+
*
962979
* @since 2.8
963980
*/
964981
public JavaType handleUnknownTypeId(JavaType baseType, String id,
@@ -984,6 +1001,43 @@ public JavaType handleUnknownTypeId(JavaType baseType, String id,
9841001
throw unknownTypeIdException(baseType, id, extraDesc);
9851002
}
9861003

1004+
/**
1005+
* Method that deserializers should call if they fail to instantiate value
1006+
* due to an exception that was thrown by constructor (or other mechanism used
1007+
* to create instances).
1008+
* Default implementation will try to call {@link DeserializationProblemHandler#handleInstantiationProblem}
1009+
* on configured handlers, if any, to allow for recovery; if recovery does not
1010+
* succeed, will throw exception constructed with {@link #instantiationException}.
1011+
*
1012+
* @param instClass Type that was to be instantiated
1013+
* @param argument (optional) Argument that was passed to constructor or equivalent
1014+
* instantiator; often a {@link java.lang.String}.
1015+
* @param t Exception that caused failure
1016+
*
1017+
* @return Object that should be constructed, if any; has to be of type <code>instClass</code>
1018+
*
1019+
* @since 2.8
1020+
*/
1021+
public Object handleInstantiationProblem(Class<?> instClass, Object argument,
1022+
Throwable t)
1023+
throws IOException
1024+
{
1025+
LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
1026+
while (h != null) {
1027+
// Can bail out if it's handled
1028+
Object key = h.value().handleInstantiationProblem(this, instClass, argument, t);
1029+
if (key != DeserializationProblemHandler.NOT_HANDLED) {
1030+
return key;
1031+
}
1032+
h = h.next();
1033+
}
1034+
// 18-May-2016, tatu: Only wrap if not already a valid type to throw
1035+
if (t instanceof IOException) {
1036+
throw (IOException) t;
1037+
}
1038+
throw instantiationException(instClass, t);
1039+
}
1040+
9871041
/*
9881042
/**********************************************************
9891043
/* Methods for problem reporting
@@ -1015,15 +1069,6 @@ public void reportUnknownProperty(Object instanceOrClass, String fieldName,
10151069
instanceOrClass, fieldName, propIds);
10161070
}
10171071

1018-
/**
1019-
* @since 2.8
1020-
*/
1021-
public void reportInstantiationException(Class<?> instClass, Throwable t)
1022-
throws JsonMappingException
1023-
{
1024-
throw instantiationException(instClass, t);
1025-
}
1026-
10271072
/**
10281073
* @since 2.8
10291074
*/

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,7 @@ protected Object _deserializeUsingPropertyBased(final JsonParser p, final Deseri
394394
try {
395395
bean = creator.build(ctxt, buffer);
396396
} catch (Exception e) {
397-
wrapInstantiationProblem(e, ctxt);
398-
bean = null; // never gets here
397+
bean = wrapInstantiationProblem(e, ctxt);
399398
}
400399
if (bean == null) {
401400
ctxt.reportInstantiationException(_beanType.getRawClass(),
@@ -686,8 +685,7 @@ protected Object deserializeUsingPropertyBasedWithUnwrapped(JsonParser p, Deseri
686685
try {
687686
bean = creator.build(ctxt, buffer);
688687
} catch (Exception e) {
689-
wrapInstantiationProblem(e, ctxt);
690-
continue; // never gets here
688+
bean = wrapInstantiationProblem(e, ctxt);
691689
}
692690
// [databind#631]: Assign current value, to be accessible by custom serializers
693691
p.setCurrentValue(bean);
@@ -905,8 +903,7 @@ protected Object deserializeUsingPropertyBasedWithExternalTypeId(JsonParser p, D
905903
try {
906904
return ext.complete(p, ctxt, buffer, creator);
907905
} catch (Exception e) {
908-
wrapInstantiationProblem(e, ctxt);
909-
return null; // never gets here
906+
return wrapInstantiationProblem(e, ctxt);
910907
}
911908
}
912909
}

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,8 +1320,7 @@ public Object deserializeFromArray(JsonParser p, DeserializationContext ctxt) th
13201320
}
13211321
return bean;
13221322
} catch (Exception e) {
1323-
wrapInstantiationProblem(e, ctxt);
1324-
return null;
1323+
return wrapInstantiationProblem(e, ctxt);
13251324
}
13261325
}
13271326
// fallback to non-array delegate
@@ -1612,7 +1611,7 @@ private Throwable throwOrReturnThrowable(Throwable t, DeserializationContext ctx
16121611
return t;
16131612
}
16141613

1615-
protected void wrapInstantiationProblem(Throwable t, DeserializationContext ctxt)
1614+
protected Object wrapInstantiationProblem(Throwable t, DeserializationContext ctxt)
16161615
throws IOException
16171616
{
16181617
while (t instanceof InvocationTargetException && t.getCause() != null) {
@@ -1631,7 +1630,6 @@ protected void wrapInstantiationProblem(Throwable t, DeserializationContext ctxt
16311630
throw (RuntimeException) t;
16321631
}
16331632
}
1634-
ctxt.reportInstantiationException(_beanType.getRawClass(), t);
1635-
// may return here, if exceptions are deferred...
1633+
return ctxt.handleInstantiationProblem(_beanType.getRawClass(), null, t);
16361634
}
16371635
}

src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,7 @@ protected final Object finishBuild(DeserializationContext ctxt, Object builder)
134134
try {
135135
return _buildMethod.getMember().invoke(builder);
136136
} catch (Exception e) {
137-
wrapInstantiationProblem(e, ctxt);
138-
return null;
137+
return wrapInstantiationProblem(e, ctxt);
139138
}
140139
}
141140

@@ -402,8 +401,7 @@ protected final Object _deserializeUsingPropertyBased(final JsonParser p,
402401
try {
403402
bean = creator.build(ctxt, buffer);
404403
} catch (Exception e) {
405-
wrapInstantiationProblem(e, ctxt);
406-
return null; // never gets here
404+
bean = wrapInstantiationProblem(e, ctxt);
407405
}
408406
if (unknown != null) {
409407
// polymorphic?
@@ -636,8 +634,7 @@ protected Object deserializeUsingPropertyBasedWithUnwrapped(JsonParser p,
636634
try {
637635
bean = creator.build(ctxt, buffer);
638636
} catch (Exception e) {
639-
wrapInstantiationProblem(e, ctxt);
640-
return null; // never gets here
637+
return wrapInstantiationProblem(e, ctxt);
641638
}
642639
return _unwrappedPropertyHandler.processUnwrapped(p, ctxt, bean, tokens);
643640
}

src/main/java/com/fasterxml/jackson/databind/deser/DeserializationProblemHandler.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public Object handleWeirdStringValue(DeserializationContext ctxt,
137137
{
138138
return NOT_HANDLED;
139139
}
140-
140+
141141
/**
142142
* Method called when a numeric value (integral or floating-point from input
143143
* can not be converted to a non-numeric value type due to specific problem
@@ -171,7 +171,41 @@ public Object handleWeirdNumberValue(DeserializationContext ctxt,
171171
{
172172
return NOT_HANDLED;
173173
}
174-
174+
175+
/**
176+
* Method called when instance creation for a type fails due to an exception.
177+
* Handler may choose to do one of following things:
178+
*<ul>
179+
* <li>Indicate it does not know what to do by returning {@link #NOT_HANDLED}
180+
* </li>
181+
* <li>Throw a {@link IOException} to indicate specific fail message (instead of
182+
* standard exception caller would throw
183+
* </li>
184+
* <li>Return actual instantiated value (of type <code>targetType</code>) to use as
185+
* replacement, and continue processing.
186+
* </li>
187+
* <li>Return <code>null</code> to use null as value but not to try further
188+
* processing (in cases where properties would otherwise be bound)
189+
* </li>
190+
* </ul>
191+
*
192+
* @param instClass Type that was to be instantiated
193+
* @param argument (optional) Additional argument that was passed to creator, if any
194+
* @param t Exception that caused instantiation failure
195+
*
196+
* @return Either {@link #NOT_HANDLED} to indicate that handler does not know
197+
* what to do (and exception may be thrown), or value to use as key (possibly
198+
* <code>null</code>
199+
*
200+
* @since 2.8
201+
*/
202+
public Object handleInstantiationProblem(DeserializationContext ctxt,
203+
Class<?> instClass, Object argument, Throwable t)
204+
throws IOException
205+
{
206+
return NOT_HANDLED;
207+
}
208+
175209
/**
176210
* Handler method called if resolution of type id from given String failed
177211
* to produce a subtype; usually because logical id is not mapped to actual

src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanAsArrayBuilderDeserializer.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,10 @@ protected final Object finishBuild(DeserializationContext ctxt, Object builder)
9292
try {
9393
return _buildMethod.getMember().invoke(builder);
9494
} catch (Exception e) {
95-
wrapInstantiationProblem(e, ctxt);
96-
return null;
95+
return wrapInstantiationProblem(e, ctxt);
9796
}
9897
}
99-
98+
10099
@Override
101100
public Object deserialize(JsonParser p, DeserializationContext ctxt)
102101
throws IOException
@@ -353,8 +352,7 @@ protected final Object _deserializeUsingPropertyBased(final JsonParser p,
353352
try {
354353
builder = creator.build(ctxt, buffer);
355354
} catch (Exception e) {
356-
wrapInstantiationProblem(e, ctxt);
357-
return null; // never gets here
355+
return wrapInstantiationProblem(e, ctxt);
358356
}
359357
}
360358
return builder;

src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanAsArrayDeserializer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,7 @@ protected final Object _deserializeUsingPropertyBased(final JsonParser p, final
350350
try {
351351
bean = creator.build(ctxt, buffer);
352352
} catch (Exception e) {
353-
wrapInstantiationProblem(e, ctxt);
354-
return null; // never gets here
353+
return wrapInstantiationProblem(e, ctxt);
355354
}
356355
}
357356
return bean;

src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializers.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,7 @@ public Calendar deserialize(JsonParser p, DeserializationContext ctxt) throws IO
227227
}
228228
return c;
229229
} catch (Exception e) {
230-
ctxt.reportInstantiationException(_calendarClass, e);
231-
return null;
230+
return (Calendar) ctxt.handleInstantiationProblem(_calendarClass, d, e);
232231
}
233232
}
234233
}

src/main/java/com/fasterxml/jackson/databind/deser/std/FactoryBasedEnumDeserializer.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,14 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx
126126
return _factory.call();
127127
} catch (Exception e) {
128128
Throwable t = ClassUtil.throwRootCauseIfIOE(e);
129-
ctxt.reportInstantiationException(_valueClass, t);
129+
return ctxt.handleInstantiationProblem(_valueClass, null, t);
130130
}
131131
}
132132
try {
133133
return _factory.callOnWith(_valueClass, value);
134134
} catch (Exception e) {
135135
Throwable t = ClassUtil.throwRootCauseIfIOE(e);
136-
ctxt.reportInstantiationException(_valueClass, t);
137-
return null;
136+
return ctxt.handleInstantiationProblem(_valueClass, value, t);
138137
}
139138
}
140139

src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOExcepti
133133
}
134134
}
135135
// 05-May-2016, tatu: Unlike most usage, this seems legit, so...
136-
@SuppressWarnings("deprecation")
137136
JsonMappingException e = ctxt.weirdStringException(text, _valueClass, msg);
138137
if (cause != null) {
139138
e.initCause(cause);
@@ -219,8 +218,8 @@ protected Object _deserialize(String value, DeserializationContext ctxt) throws
219218
try {
220219
return ctxt.findClass(value);
221220
} catch (Exception e) {
222-
ctxt.reportInstantiationException(_valueClass, ClassUtil.getRootCause(e));
223-
return null;
221+
return ctxt.handleInstantiationProblem(_valueClass, value,
222+
ClassUtil.getRootCause(e));
224223
}
225224
case STD_JAVA_TYPE:
226225
return ctxt.getTypeFactory().constructFromCanonical(value);

0 commit comments

Comments
 (0)