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