1 package com.fasterxml.jackson.databind.deser;
2 
3 import java.io.IOException;
4 
5 import com.fasterxml.jackson.core.JsonParser;
6 import com.fasterxml.jackson.core.JsonToken;
7 import com.fasterxml.jackson.databind.DeserializationConfig;
8 import com.fasterxml.jackson.databind.DeserializationContext;
9 import com.fasterxml.jackson.databind.JavaType;
10 import com.fasterxml.jackson.databind.JsonDeserializer;
11 import com.fasterxml.jackson.databind.ObjectMapper;
12 import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
13 
14 /**
15  * This is the class that can be registered (via
16  * {@link DeserializationConfig} object owner by
17  * {@link ObjectMapper}) to get called when a potentially
18  * recoverable problem is encountered during deserialization
19  * process. Handlers can try to resolve the problem, throw
20  * an exception or just skip the content.
21  *<p>
22  * Default implementations for all methods implemented minimal
23  * "do nothing" functionality, which is roughly equivalent to
24  * not having a registered listener at all. This allows for
25  * only implemented handler methods one is interested in, without
26  * handling other cases.
27  *<p>
28  * NOTE: it is typically <b>NOT</b> acceptable to simply do nothing,
29  * because this will result in unprocessed tokens being left in
30  * token stream (read via {@link JsonParser}, in case a structured
31  * (JSON Object or JSON Array) value is being pointed to by parser.
32  */
33 public abstract class DeserializationProblemHandler
34 {
35     /**
36      * Marker value returned by some handler methods to indicate that
37      * they could not handle problem and produce replacement value.
38      *
39      * @since 2.7
40      */
41     public final static Object NOT_HANDLED = new Object();
42 
43     /**
44      * Method called when a JSON Object property with an unrecognized
45      * name is encountered.
46      * Content (supposedly) matching the property are accessible via
47      * parser that can be obtained from passed deserialization context.
48      * Handler can also choose to skip the content; if so, it MUST return
49      * true to indicate it did handle property successfully.
50      * Skipping is usually done like so:
51      *<pre>
52      *  parser.skipChildren();
53      *</pre>
54      *<p>
55      * Note: {@link com.fasterxml.jackson.databind.DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES})
56      * takes effect only <b>after</b> handler is called, and only
57      * if handler did <b>not</b> handle the problem.
58      *
59      * @param beanOrClass Either bean instance being deserialized (if one
60      *   has been instantiated so far); or Class that indicates type that
61      *   will be instantiated (if no instantiation done yet: for example
62      *   when bean uses non-default constructors)
63      * @param p Parser to use for handling problematic content
64      *
65      * @return True if the problem is resolved (and content available used or skipped);
66      *  false if the handler did not anything and the problem is unresolved. Note that in
67      *  latter case caller will either throw an exception or explicitly skip the content,
68      *  depending on configuration.
69      */
handleUnknownProperty(DeserializationContext ctxt, JsonParser p, JsonDeserializer<?> deserializer, Object beanOrClass, String propertyName)70     public boolean handleUnknownProperty(DeserializationContext ctxt, JsonParser p,
71             JsonDeserializer<?> deserializer, Object beanOrClass, String propertyName)
72         throws IOException
73     {
74         return false;
75     }
76 
77     /**
78      * Method called when a property name from input cannot be converted to a
79      * non-Java-String key type (passed as <code>rawKeyType</code>) due to format problem.
80      * Handler may choose to do one of 3 things:
81      *<ul>
82      * <li>Indicate it does not know what to do by returning {@link #NOT_HANDLED}
83      *  </li>
84      * <li>Throw a {@link IOException} to indicate specific fail message (instead of
85      *    standard exception caller would throw
86      *  </li>
87      * <li>Return actual key value to use as replacement, and continue processing.
88      *  </li>
89      * </ul>
90      *
91      * @param failureMsg Message that will be used by caller (by calling
92      *    {@link DeserializationContext#weirdKeyException(Class, String, String)})
93      *    to indicate type of failure unless handler produces key to use
94      *
95      * @return Either {@link #NOT_HANDLED} to indicate that handler does not know
96      *    what to do (and exception may be thrown), or value to use as key (possibly
97      *    <code>null</code>
98      *
99      * @since 2.8
100      */
handleWeirdKey(DeserializationContext ctxt, Class<?> rawKeyType, String keyValue, String failureMsg)101     public Object handleWeirdKey(DeserializationContext ctxt,
102             Class<?> rawKeyType, String keyValue,
103             String failureMsg)
104         throws IOException
105     {
106         return NOT_HANDLED;
107     }
108 
109     /**
110      * Method called when a String value
111      * cannot be converted to a non-String value type due to specific problem
112      * (as opposed to String values never being usable).
113      * Handler may choose to do one of 3 things:
114      *<ul>
115      * <li>Indicate it does not know what to do by returning {@link #NOT_HANDLED}
116      *  </li>
117      * <li>Throw a {@link IOException} to indicate specific fail message (instead of
118      *    standard exception caller would throw
119      *  </li>
120      * <li>Return actual converted value (of type <code>targetType</code>) to use as
121      *    replacement, and continue processing.
122      *  </li>
123      * </ul>
124      *
125      * @param failureMsg Message that will be used by caller (by calling
126      *    {@link DeserializationContext#weirdNumberException})
127      *    to indicate type of failure unless handler produces key to use
128      *
129      * @return Either {@link #NOT_HANDLED} to indicate that handler does not know
130      *    what to do (and exception may be thrown), or value to use as (possibly
131      *    <code>null</code>)
132      *
133      * @since 2.8
134      */
handleWeirdStringValue(DeserializationContext ctxt, Class<?> targetType, String valueToConvert, String failureMsg)135     public Object handleWeirdStringValue(DeserializationContext ctxt,
136             Class<?> targetType, String valueToConvert,
137             String failureMsg)
138         throws IOException
139     {
140         return NOT_HANDLED;
141     }
142 
143     /**
144      * Method called when a numeric value (integral or floating-point from input
145      * cannot be converted to a non-numeric value type due to specific problem
146      * (as opposed to numeric values never being usable).
147      * Handler may choose to do one of 3 things:
148      *<ul>
149      * <li>Indicate it does not know what to do by returning {@link #NOT_HANDLED}
150      *  </li>
151      * <li>Throw a {@link IOException} to indicate specific fail message (instead of
152      *    standard exception caller would throw
153      *  </li>
154      * <li>Return actual converted value (of type <code>targetType</code>) to use as
155      *    replacement, and continue processing.
156      *  </li>
157      * </ul>
158      *
159      * @param failureMsg Message that will be used by caller (by calling
160      *    {@link DeserializationContext#weirdNumberException})
161      *    to indicate type of failure unless handler produces key to use
162      *
163      * @return Either {@link #NOT_HANDLED} to indicate that handler does not know
164      *    what to do (and exception may be thrown), or value to use as (possibly
165      *    <code>null</code>)
166      *
167      * @since 2.8
168      */
handleWeirdNumberValue(DeserializationContext ctxt, Class<?> targetType, Number valueToConvert, String failureMsg)169     public Object handleWeirdNumberValue(DeserializationContext ctxt,
170             Class<?> targetType, Number valueToConvert, String failureMsg)
171         throws IOException
172     {
173         return NOT_HANDLED;
174     }
175 
176     /**
177      * Method called when an embedded (native) value ({@link JsonToken#VALUE_EMBEDDED_OBJECT})
178      * cannot be converted directly into expected value type (usually POJO).
179      * Handler may choose to do one of 3 things:
180      *<ul>
181      * <li>Indicate it does not know what to do by returning {@link #NOT_HANDLED}
182      *  </li>
183      * <li>Throw a {@link IOException} to indicate specific fail message (instead of
184      *    standard exception caller would throw
185      *  </li>
186      * <li>Return actual converted value (of type <code>targetType</code>) to use as
187      *    replacement, and continue processing.
188      *  </li>
189      * </ul>
190      *
191      * @return Either {@link #NOT_HANDLED} to indicate that handler does not know
192      *    what to do (and exception may be thrown), or value to use (possibly
193      *    <code>null</code>)
194      *
195      * @since 2.9
196      */
handleWeirdNativeValue(DeserializationContext ctxt, JavaType targetType, Object valueToConvert, JsonParser p)197     public Object handleWeirdNativeValue(DeserializationContext ctxt,
198             JavaType targetType, Object valueToConvert, JsonParser p)
199         throws IOException
200     {
201         return NOT_HANDLED;
202     }
203 
204     /**
205      * Deprecated variant of
206      * {@link #handleUnexpectedToken(DeserializationContext, JavaType, JsonToken, JsonParser, String)}
207      *
208      * @since 2.8
209      *
210      * @deprecated Since 2.10
211      */
212     @Deprecated
handleUnexpectedToken(DeserializationContext ctxt, Class<?> targetType, JsonToken t, JsonParser p, String failureMsg)213     public Object handleUnexpectedToken(DeserializationContext ctxt,
214             Class<?> targetType, JsonToken t, JsonParser p,
215             String failureMsg)
216         throws IOException
217     {
218         return NOT_HANDLED;
219     }
220 
221     /**
222      * Method that deserializers should call if the first token of the value to
223      * deserialize is of unexpected type (that is, type of token that deserializer
224      * cannot handle). This could occur, for example, if a Number deserializer
225      * encounter {@link JsonToken#START_ARRAY} instead of
226      * {@link JsonToken#VALUE_NUMBER_INT} or {@link JsonToken#VALUE_NUMBER_FLOAT}.
227      *<ul>
228      * <li>Indicate it does not know what to do by returning {@link #NOT_HANDLED}
229      *  </li>
230      * <li>Throw a {@link IOException} to indicate specific fail message (instead of
231      *    standard exception caller would throw
232      *  </li>
233      * <li>Handle content to match (by consuming or skipping it), and return actual
234      *    instantiated value (of type <code>targetType</code>) to use as replacement;
235      *    value may be `null` as well as expected target type.
236      *  </li>
237      * </ul>
238      *
239      * @param failureMsg Message that will be used by caller
240      *    to indicate type of failure unless handler produces value to use
241      *
242      * @return Either {@link #NOT_HANDLED} to indicate that handler does not know
243      *    what to do (and exception may be thrown), or value to use (possibly
244      *    <code>null</code>
245      *
246      * @since 2.10
247      */
handleUnexpectedToken(DeserializationContext ctxt, JavaType targetType, JsonToken t, JsonParser p, String failureMsg)248     public Object handleUnexpectedToken(DeserializationContext ctxt,
249             JavaType targetType, JsonToken t, JsonParser p,
250             String failureMsg)
251         throws IOException
252     {
253         // Calling class-version handler for backward compatibility, as of 2.10
254         return handleUnexpectedToken(ctxt, targetType.getRawClass(), t, p, failureMsg);
255     }
256 
257     /**
258      * Method called when instance creation for a type fails due to an exception.
259      * Handler may choose to do one of following things:
260      *<ul>
261      * <li>Indicate it does not know what to do by returning {@link #NOT_HANDLED}
262      *  </li>
263      * <li>Throw a {@link IOException} to indicate specific fail message (instead of
264      *    standard exception caller would throw
265      *  </li>
266      * <li>Return actual instantiated value (of type <code>targetType</code>) to use as
267      *    replacement, and continue processing.
268      *  </li>
269      * <li>Return <code>null</code> to use null as value but not to try further
270      *   processing (in cases where properties would otherwise be bound)
271      *  </li>
272      * </ul>
273      *
274      * @param instClass Type that was to be instantiated
275      * @param argument (optional) Additional argument that was passed to creator, if any
276      * @param t Exception that caused instantiation failure
277      *
278      * @return Either {@link #NOT_HANDLED} to indicate that handler does not know
279      *    what to do (and exception may be thrown), or value to use (possibly
280      *    <code>null</code>
281      *
282      * @since 2.8
283      */
handleInstantiationProblem(DeserializationContext ctxt, Class<?> instClass, Object argument, Throwable t)284     public Object handleInstantiationProblem(DeserializationContext ctxt,
285             Class<?> instClass, Object argument, Throwable t)
286         throws IOException
287     {
288         return NOT_HANDLED;
289     }
290 
291     /**
292      * Method called when instance creation for a type fails due to lack of an
293      * instantiator. Method is called before actual deserialization from input
294      * is attempted, so handler may do one of following things:
295      *<ul>
296      * <li>Indicate it does not know what to do by returning {@link #NOT_HANDLED}
297      *  </li>
298      * <li>Throw a {@link IOException} to indicate specific fail message (instead of
299      *    standard exception caller would throw
300      *  </li>
301      * <li>Handle content to match (by consuming or skipping it), and return actual
302      *    instantiated value (of type <code>targetType</code>) to use as replacement;
303      *    value may be `null` as well as expected target type.
304      *  </li>
305      * </ul>
306      *
307      * @param instClass Type that was to be instantiated
308      * @param p Parser to use for accessing content that needs handling, to either
309      *   use it or skip it (latter with {@link JsonParser#skipChildren()}.
310      *
311      * @return Either {@link #NOT_HANDLED} to indicate that handler does not know
312      *    what to do (and exception may be thrown), or value to use (possibly
313      *    <code>null</code>
314      *
315      * @since 2.9
316      */
handleMissingInstantiator(DeserializationContext ctxt, Class<?> instClass, ValueInstantiator valueInsta, JsonParser p, String msg)317     public Object handleMissingInstantiator(DeserializationContext ctxt,
318             Class<?> instClass, ValueInstantiator valueInsta, JsonParser p,
319             String msg)
320         throws IOException
321     {
322         // 16-Oct-2016, tatu: Need to delegate to deprecated method from 2.8;
323         //   remove redirect from later versions (post-2.9)
324         return handleMissingInstantiator(ctxt, instClass, p, msg);
325     }
326 
327     /**
328      * Handler method called if resolution of type id from given String failed
329      * to produce a subtype; usually because logical id is not mapped to actual
330      * implementation class.
331      * Handler may choose to do one of following things:
332      *<ul>
333      * <li>Indicate it does not know what to do by returning `null`
334      *  </li>
335      * <li>Indicate that nothing should be deserialized, by return `Void.class`
336      *  </li>
337      * <li>Throw a {@link IOException} to indicate specific fail message (instead of
338      *    standard exception caller would throw
339      *  </li>
340      * <li>Return actual resolved type to use for type id.
341      *  </li>
342      * </ul>
343      *
344      * @param ctxt Deserialization context to use for accessing information or
345      *    constructing exception to throw
346      * @param baseType Base type to use for resolving subtype id
347      * @param subTypeId Subtype id that failed to resolve
348      * @param failureMsg Informational message that would be thrown as part of
349      *    exception, if resolution still fails
350      *
351      * @return Actual type to use, if resolved; `null` if handler does not know what
352      *     to do; or `Void.class` to indicate that nothing should be deserialized for
353      *     type with the id (which caller may choose to do... or not)
354      *
355      * @since 2.8
356      */
handleUnknownTypeId(DeserializationContext ctxt, JavaType baseType, String subTypeId, TypeIdResolver idResolver, String failureMsg)357     public JavaType handleUnknownTypeId(DeserializationContext ctxt,
358             JavaType baseType, String subTypeId, TypeIdResolver idResolver,
359             String failureMsg)
360         throws IOException
361     {
362         return null;
363     }
364 
365     /**
366      * Handler method called if an expected type id for a polymorphic value is
367      * not found and no "default type" is specified or allowed.
368      * Handler may choose to do one of following things:
369      *<ul>
370      * <li>Indicate it does not know what to do by returning `null`
371      *  </li>
372      * <li>Indicate that nothing should be deserialized, by return `Void.class`
373      *  </li>
374      * <li>Throw a {@link IOException} to indicate specific fail message (instead of
375      *    standard exception caller would throw
376      *  </li>
377      * <li>Return actual resolved type to use for this particular case.
378      *  </li>
379      * </ul>
380      *
381      * @param ctxt Deserialization context to use for accessing information or
382      *    constructing exception to throw
383      * @param baseType Base type to use for resolving subtype id
384      * @param failureMsg Informational message that would be thrown as part of
385      *    exception, if resolution still fails
386      *
387      * @return Actual type to use, if resolved; `null` if handler does not know what
388      *     to do; or `Void.class` to indicate that nothing should be deserialized for
389      *     type with the id (which caller may choose to do... or not)
390      *
391      * @since 2.9
392      */
handleMissingTypeId(DeserializationContext ctxt, JavaType baseType, TypeIdResolver idResolver, String failureMsg)393     public JavaType handleMissingTypeId(DeserializationContext ctxt,
394             JavaType baseType, TypeIdResolver idResolver,
395             String failureMsg)
396         throws IOException
397     {
398         return null;
399     }
400 
401     /*
402     /**********************************************************
403     /* Deprecated
404     /**********************************************************
405      */
406 
407     /**
408      * @since 2.8
409      * @deprecated Since 2.9: use variant that takes {@link ValueInstantiator}
410      */
411     @Deprecated
handleMissingInstantiator(DeserializationContext ctxt, Class<?> instClass, JsonParser p, String msg)412     public Object handleMissingInstantiator(DeserializationContext ctxt,
413             Class<?> instClass, JsonParser p, String msg)
414         throws IOException
415     {
416         return NOT_HANDLED;
417     }
418 }
419