blob: a4dcf71bec3336353d5badd6c8638dd2000385f7 [file] [log] [blame]
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001package com.fasterxml.jackson.databind;
2
3import java.io.IOException;
Tatu Saloranta06c20b12012-01-29 21:36:52 -08004import java.text.DateFormat;
5import java.text.ParseException;
Tatu Salorantad068a402016-10-05 23:21:57 -07006import java.util.*;
Tatu Salorantaaf263c32013-10-24 16:18:50 -07007import java.util.concurrent.atomic.AtomicReference;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08008
Tatu Salorantaa5301ba2015-12-11 09:47:09 -08009import com.fasterxml.jackson.annotation.JsonFormat;
Tatu Salorantad71dffa2012-02-07 21:05:21 -080010import com.fasterxml.jackson.annotation.ObjectIdGenerator;
Pascal GĂ©linas184cae32014-02-05 17:35:56 -050011import com.fasterxml.jackson.annotation.ObjectIdResolver;
Tatu Saloranta6faae872016-10-22 19:43:50 -070012
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080013import com.fasterxml.jackson.core.*;
Tatu Saloranta6faae872016-10-22 19:43:50 -070014
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -070015import com.fasterxml.jackson.databind.cfg.ContextAttributes;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080016import com.fasterxml.jackson.databind.deser.*;
Tatu Saloranta9d1fb752016-06-07 22:47:04 -070017import com.fasterxml.jackson.databind.deser.impl.ObjectIdReader;
Tatu Saloranta34a8adf2012-02-08 22:07:36 -080018import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId;
Tatuc3a73d02012-01-31 12:45:49 -080019import com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer;
Tatu Salorantac1478ac2016-09-29 08:17:03 -070020import com.fasterxml.jackson.databind.exc.InputMismatchException;
21import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
Tatu Salorantadd348562012-07-18 17:25:02 -070022import com.fasterxml.jackson.databind.exc.InvalidFormatException;
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -070023import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080024import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
Tatub37ff332012-01-24 16:19:36 -080025import com.fasterxml.jackson.databind.introspect.Annotated;
Tatu Salorantabb06aa02016-09-08 22:38:23 -070026import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
Tatuc3a73d02012-01-31 12:45:49 -080027import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
Tatu Salorantad6230fd2016-05-30 21:11:19 -070028import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
Tatu Saloranta2f823442011-12-23 20:25:27 -080029import com.fasterxml.jackson.databind.node.JsonNodeFactory;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080030import com.fasterxml.jackson.databind.type.TypeFactory;
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -080031import com.fasterxml.jackson.databind.util.*;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080032
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080033/**
Tatu Saloranta97f84822012-01-29 21:38:40 -080034 * Context for the process of deserialization a single root-level value.
35 * Used to allow passing in configuration settings and reusable temporary
36 * objects (scrap arrays, containers).
Tatu Saloranta060ce112012-02-01 22:18:09 -080037 *<p>
Tatu Salorantac1478ac2016-09-29 08:17:03 -070038 * Instance life-cycle is such that a partially configured "blueprint" object
Tatu Saloranta060ce112012-02-01 22:18:09 -080039 * is registered with {@link ObjectMapper} (and {@link ObjectReader},
Tatu Salorantac1478ac2016-09-29 08:17:03 -070040 * and when actual instance is needed for deserialization,
41 * a fully configured instance will be created using a method in extended internal
42 * API of sub-class
Tatu Saloranta71e876b2012-02-05 19:15:48 -080043 * ({@link com.fasterxml.jackson.databind.deser.DefaultDeserializationContext#createInstance}).
Tatu Saloranta060ce112012-02-01 22:18:09 -080044 * Each instance is guaranteed to only be used from single-threaded context;
Tatu Salorantac1478ac2016-09-29 08:17:03 -070045 * instances may be reused if (and only if) no configuration has changed.
Tatu Saloranta060ce112012-02-01 22:18:09 -080046 *<p>
47 * Defined as abstract class so that implementations must define methods
48 * for reconfiguring blueprints and creating instances.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080049 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080050public abstract class DeserializationContext
Tatu Saloranta9439a312013-03-02 13:13:09 -080051 extends DatabindContext
Tatu Saloranta0e114112012-10-06 10:45:41 -070052 implements java.io.Serializable
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080053{
Cowtowncoder7fee92e2015-02-11 16:15:08 -080054 private static final long serialVersionUID = 1L; // 2.6
Tatu Saloranta0e114112012-10-06 10:45:41 -070055
Tatu Saloranta06c20b12012-01-29 21:36:52 -080056 /**
57 * Let's limit length of error messages, for cases where underlying data
58 * may be very large -- no point in spamming logs with megs of meaningless
59 * data.
60 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080061 private final static int MAX_ERROR_STR_LEN = 500;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080062
Tatu Saloranta060ce112012-02-01 22:18:09 -080063 /*
64 /**********************************************************
65 /* Configuration, immutable
66 /**********************************************************
67 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -080068
Tatu Saloranta71e876b2012-02-05 19:15:48 -080069 /**
70 * Object that handle details of {@link JsonDeserializer} caching.
71 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080072 protected final DeserializerCache _cache;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080073
Tatu Saloranta060ce112012-02-01 22:18:09 -080074 /*
75 /**********************************************************
76 /* Configuration, changeable via fluent factories
77 /**********************************************************
78 */
79
80 /**
81 * Read-only factory instance; exposed to let
82 * owners (<code>ObjectMapper</code>, <code>ObjectReader</code>)
83 * access it.
84 */
Tatu Salorantaaa512742012-02-22 22:51:33 -080085 protected final DeserializerFactory _factory;
86
87 /*
88 /**********************************************************
Tatu Saloranta060ce112012-02-01 22:18:09 -080089 /* Configuration that gets set for instances (not blueprints)
Tatu Saloranta71e876b2012-02-05 19:15:48 -080090 /* (partly denormalized for performance)
Tatu Saloranta060ce112012-02-01 22:18:09 -080091 /**********************************************************
92 */
93
Tatu Saloranta71e876b2012-02-05 19:15:48 -080094 /**
95 * Generic deserialization processing configuration
96 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080097 protected final DeserializationConfig _config;
Tatu Saloranta71e876b2012-02-05 19:15:48 -080098
99 /**
100 * Bitmap of {@link DeserializationFeature}s that are enabled
101 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800102 protected final int _featureFlags;
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800103
Tatu Saloranta71e876b2012-02-05 19:15:48 -0800104 /**
105 * Currently active view, if any.
106 */
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800107 protected final Class<?> _view;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800108
109 /**
110 * Currently active parser used for deserialization.
111 * May be different from the outermost parser
112 * when content is buffered.
113 */
Tatu Salorantaf5211582012-10-05 17:09:47 -0700114 protected transient JsonParser _parser;
Tatuc3a73d02012-01-31 12:45:49 -0800115
Tatu Saloranta71e876b2012-02-05 19:15:48 -0800116 /**
117 * Object used for resolving references to injectable
118 * values.
119 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800120 protected final InjectableValues _injectableValues;
121
Tatu Saloranta060ce112012-02-01 22:18:09 -0800122 /*
123 /**********************************************************
124 /* Per-operation reusable helper objects (not for blueprints)
125 /**********************************************************
126 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800127
Tatu Salorantaf5211582012-10-05 17:09:47 -0700128 protected transient ArrayBuilders _arrayBuilders;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800129
Tatu Salorantaf5211582012-10-05 17:09:47 -0700130 protected transient ObjectBuffer _objectBuffer;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800131
Tatu Salorantaf5211582012-10-05 17:09:47 -0700132 protected transient DateFormat _dateFormat;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700133
134 /**
135 * Lazily-constructed holder for per-call attributes.
136 *
137 * @since 2.3
138 */
139 protected transient ContextAttributes _attributes;
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800140
141 /**
142 * Type of {@link JsonDeserializer} (or, more specifically,
Cowtowncoder08efeba2015-05-05 12:34:11 -0700143 * {@link ContextualDeserializer}) that is being
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800144 * contextualized currently.
145 *
146 * @since 2.5
147 */
148 protected LinkedNode<JavaType> _currentType;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800149
150 /*
151 /**********************************************************
152 /* Life-cycle
153 /**********************************************************
154 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800155
156 protected DeserializationContext(DeserializerFactory df) {
157 this(df, null);
158 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800159
Tatu Saloranta060ce112012-02-01 22:18:09 -0800160 protected DeserializationContext(DeserializerFactory df,
161 DeserializerCache cache)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800162 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800163 if (df == null) {
164 throw new IllegalArgumentException("Can not pass null DeserializerFactory");
165 }
166 _factory = df;
167 _cache = (cache == null) ? new DeserializerCache() : cache;
168
169 _featureFlags = 0;
170 _config = null;
171 _injectableValues = null;
172 _view = null;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700173 _attributes = null;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800174 }
175
176 protected DeserializationContext(DeserializationContext src,
177 DeserializerFactory factory)
178 {
179 _cache = src._cache;
180 _factory = factory;
181
182 _config = src._config;
183 _featureFlags = src._featureFlags;
184 _view = src._view;
185 _parser = src._parser;
186 _injectableValues = src._injectableValues;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700187 _attributes = src._attributes;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800188 }
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700189
190 /**
191 * Constructor used for creating actual per-call instances.
192 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800193 protected DeserializationContext(DeserializationContext src,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700194 DeserializationConfig config, JsonParser p,
Tatu Saloranta060ce112012-02-01 22:18:09 -0800195 InjectableValues injectableValues)
196 {
197 _cache = src._cache;
198 _factory = src._factory;
199
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800200 _config = config;
Tatu Salorantae3ae58e2012-01-28 23:08:16 -0800201 _featureFlags = config.getDeserializationFeatures();
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800202 _view = config.getActiveView();
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700203 _parser = p;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800204 _injectableValues = injectableValues;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700205 _attributes = config.getAttributes();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800206 }
Tatu Saloranta9439a312013-03-02 13:13:09 -0800207
Tatu Saloranta23328aa2014-10-28 22:38:15 -0700208 /**
209 * Copy-constructor for use with <code>copy()</code> by {@link ObjectMapper#copy()}
210 */
211 protected DeserializationContext(DeserializationContext src) {
212 _cache = new DeserializerCache();
213 _factory = src._factory;
214
215 _config = src._config;
216 _featureFlags = src._featureFlags;
217 _view = src._view;
218 _injectableValues = null;
219 }
220
Tatu Saloranta9439a312013-03-02 13:13:09 -0800221 /*
222 /**********************************************************
223 /* DatabindContext implementation
224 /**********************************************************
225 */
226
227 @Override
228 public DeserializationConfig getConfig() { return _config; }
229
230 @Override
231 public final Class<?> getActiveView() { return _view; }
232
233 @Override
Tatu Salorantaa5301ba2015-12-11 09:47:09 -0800234 public final boolean canOverrideAccessModifiers() {
235 return _config.canOverrideAccessModifiers();
236 }
237
238 @Override
239 public final boolean isEnabled(MapperFeature feature) {
240 return _config.isEnabled(feature);
241 }
242
243 @Override
244 public final JsonFormat.Value getDefaultPropertyFormat(Class<?> baseType) {
245 return _config.getDefaultPropertyFormat(baseType);
246 }
Tatu Saloranta4fdbb692016-04-16 21:41:14 -0700247
Tatu Salorantaa5301ba2015-12-11 09:47:09 -0800248 @Override
Tatu Saloranta9439a312013-03-02 13:13:09 -0800249 public final AnnotationIntrospector getAnnotationIntrospector() {
250 return _config.getAnnotationIntrospector();
251 }
252
253 @Override
254 public final TypeFactory getTypeFactory() {
255 return _config.getTypeFactory();
256 }
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700257
Cowtowncoder41bbc962015-06-19 17:16:08 -0700258 /**
259 * Method for accessing default Locale to use: convenience method for
260 *<pre>
261 * getConfig().getLocale();
262 *</pre>
263 */
264 @Override
265 public Locale getLocale() {
266 return _config.getLocale();
267 }
268
269 /**
270 * Method for accessing default TimeZone to use: convenience method for
271 *<pre>
272 * getConfig().getTimeZone();
273 *</pre>
274 */
275 @Override
276 public TimeZone getTimeZone() {
277 return _config.getTimeZone();
278 }
279
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700280 /*
281 /**********************************************************
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800282 /* Access to per-call state, like generic attributes (2.3+)
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700283 /**********************************************************
284 */
285
286 @Override
287 public Object getAttribute(Object key) {
288 return _attributes.getAttribute(key);
289 }
290
291 @Override
292 public DeserializationContext setAttribute(Object key, Object value)
293 {
294 _attributes = _attributes.withPerCallAttribute(key, value);
295 return this;
296 }
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800297
298 /**
299 * Accessor to {@link JavaType} of currently contextualized
300 * {@link ContextualDeserializer}, if any.
301 * This is sometimes useful for generic {@link JsonDeserializer}s that
302 * do not get passed (or do not retain) type information when being
303 * constructed: happens for example for deserializers constructed
304 * from annotations.
305 *
306 * @since 2.5
307 *
308 * @return Type of {@link ContextualDeserializer} being contextualized,
309 * if process is on-going; null if not.
310 */
311 public JavaType getContextualType() {
312 return (_currentType == null) ? null : _currentType.value();
313 }
314
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800315 /*
316 /**********************************************************
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800317 /* Public API, config setting accessors
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800318 /**********************************************************
319 */
320
321 /**
Dmitry Katsuboe70c66f2012-09-03 16:00:30 +0200322 * Method for getting current {@link DeserializerFactory}.
323 */
324 public DeserializerFactory getFactory() {
325 return _factory;
326 }
Tatu Saloranta9439a312013-03-02 13:13:09 -0800327
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800328 /**
329 * Convenience method for checking whether specified on/off
330 * feature is enabled
331 */
Tatu9610aff2012-02-02 11:30:08 -0800332 public final boolean isEnabled(DeserializationFeature feat) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800333 /* 03-Dec-2010, tatu: minor shortcut; since this is called quite often,
334 * let's use a local copy of feature settings:
335 */
336 return (_featureFlags & feat.getMask()) != 0;
337 }
338
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800339 /**
Cowtowncoder23e52ab2015-05-19 17:53:26 -0700340 * Bulk access method for getting the bit mask of all {@link DeserializationFeature}s
341 * that are enabled.
342 *
343 * @since 2.6
344 */
345 public final int getDeserializationFeatures() {
346 return _featureFlags;
347 }
348
349 /**
350 * Bulk access method for checking that all features specified by
Tatu Saloranta0ac36ba2013-08-21 18:08:51 -0700351 * mask are enabled.
352 *
353 * @since 2.3
354 */
355 public final boolean hasDeserializationFeatures(int featureMask) {
Cowtowncoder23e52ab2015-05-19 17:53:26 -0700356 return (_featureFlags & featureMask) == featureMask;
357 }
358
359 /**
360 * Bulk access method for checking that at least one of features specified by
361 * mask is enabled.
362 *
363 * @since 2.6
364 */
365 public final boolean hasSomeOfFeatures(int featureMask) {
366 return (_featureFlags & featureMask) != 0;
Tatu Saloranta0ac36ba2013-08-21 18:08:51 -0700367 }
368
369 /**
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800370 * Method for accessing the currently active parser.
371 * May be different from the outermost parser
372 * when content is buffered.
373 *<p>
374 * Use of this method is discouraged: if code has direct access
375 * to the active parser, that should be used instead.
376 */
377 public final JsonParser getParser() { return _parser; }
378
379 public final Object findInjectableValue(Object valueId,
380 BeanProperty forProperty, Object beanInstance)
Tatu Saloranta68440372016-10-29 17:06:05 -0700381 throws JsonMappingException
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800382 {
383 if (_injectableValues == null) {
Tatu Saloranta68440372016-10-29 17:06:05 -0700384 reportBadDefinition(ClassUtil.classOf(valueId), String.format(
385"No 'injectableValues' configured, can not inject value with id [%s]", valueId));
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800386 }
387 return _injectableValues.findInjectableValue(valueId, this, forProperty, beanInstance);
388 }
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800389
Tatu Saloranta060ce112012-02-01 22:18:09 -0800390 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800391 * Convenience method for accessing the default Base64 encoding
392 * used for decoding base64 encoded binary content.
393 * Same as calling:
394 *<pre>
395 * getConfig().getBase64Variant();
396 *</pre>
397 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800398 public final Base64Variant getBase64Variant() {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800399 return _config.getBase64Variant();
400 }
401
Tatu Saloranta060ce112012-02-01 22:18:09 -0800402 /**
403 * Convenience method, functionally equivalent to:
404 *<pre>
405 * getConfig().getNodeFactory();
406 * </pre>
407 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800408 public final JsonNodeFactory getNodeFactory() {
409 return _config.getNodeFactory();
410 }
411
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800412 /*
413 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800414 /* Public API, pass-through to DeserializerCache
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800415 /**********************************************************
416 */
Tatuc3a73d02012-01-31 12:45:49 -0800417
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800418 /**
Tatu Saloranta060ce112012-02-01 22:18:09 -0800419 * Method for checking whether we could find a deserializer
420 * for given type.
Cowtowncodera2e27202014-11-25 17:07:52 -0800421 *
Tatu Salorantaaf263c32013-10-24 16:18:50 -0700422 * @param type
423 * @since 2.3
Tatu Saloranta060ce112012-02-01 22:18:09 -0800424 */
Tatu Salorantaaf263c32013-10-24 16:18:50 -0700425 public boolean hasValueDeserializerFor(JavaType type, AtomicReference<Throwable> cause) {
426 try {
427 return _cache.hasValueDeserializerFor(this, _factory, type);
428 } catch (JsonMappingException e) {
429 if (cause != null) {
430 cause.set(e);
431 }
432 } catch (RuntimeException e) {
433 if (cause == null) { // earlier behavior
434 throw e;
435 }
436 cause.set(e);
437 }
438 return false;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800439 }
440
Tatu Saloranta060ce112012-02-01 22:18:09 -0800441 /**
Tatuc3a73d02012-01-31 12:45:49 -0800442 * Method for finding a value deserializer, and creating a contextual
443 * version if necessary, for value reached via specified property.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800444 */
Tatuc3a73d02012-01-31 12:45:49 -0800445 @SuppressWarnings("unchecked")
446 public final JsonDeserializer<Object> findContextualValueDeserializer(JavaType type,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700447 BeanProperty prop) throws JsonMappingException
Tatuc3a73d02012-01-31 12:45:49 -0800448 {
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700449 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this, _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800450 if (deser != null) {
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800451 deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, prop, type);
Tatuc3a73d02012-01-31 12:45:49 -0800452 }
453 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800454 }
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700455
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800456 /**
Cowtowncodera2e27202014-11-25 17:07:52 -0800457 * Variant that will try to locate deserializer for current type, but without
458 * performing any contextualization (unlike {@link #findContextualValueDeserializer})
459 * or checking for need to create a {@link TypeDeserializer} (unlike
460 * {@link #findRootValueDeserializer(JavaType)}.
461 * This method is usually called from within {@link ResolvableDeserializer#resolve},
462 * and expectation is that caller then calls either
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800463 * {@link #handlePrimaryContextualization(JsonDeserializer, BeanProperty, JavaType)} or
464 * {@link #handleSecondaryContextualization(JsonDeserializer, BeanProperty, JavaType)} at a
Cowtowncodera2e27202014-11-25 17:07:52 -0800465 * later point, as necessary.
466 *
467 * @since 2.5
468 */
469 public final JsonDeserializer<Object> findNonContextualValueDeserializer(JavaType type)
470 throws JsonMappingException
471 {
472 return _cache.findValueDeserializer(this, _factory, type);
473 }
474
475 /**
Tatuc3a73d02012-01-31 12:45:49 -0800476 * Method for finding a deserializer for root-level value.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800477 */
Tatuc3a73d02012-01-31 12:45:49 -0800478 @SuppressWarnings("unchecked")
Tatu Saloranta9b9d0432012-01-30 09:20:26 -0800479 public final JsonDeserializer<Object> findRootValueDeserializer(JavaType type)
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700480 throws JsonMappingException
Tatuc3a73d02012-01-31 12:45:49 -0800481 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800482 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this,
483 _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800484 if (deser == null) { // can this occur?
485 return null;
486 }
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800487 deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, null, type);
Tatuc3a73d02012-01-31 12:45:49 -0800488 TypeDeserializer typeDeser = _factory.findTypeDeserializer(_config, type);
489 if (typeDeser != null) {
490 // important: contextualize to indicate this is for root value
491 typeDeser = typeDeser.forProperty(null);
492 return new TypeWrappedDeserializer(typeDeser, deser);
493 }
494 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800495 }
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800496
497 /**
498 * Convenience method, functionally same as:
499 *<pre>
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700500 * getDeserializerProvider().findKeyDeserializer(getConfig(), prop.getType(), prop);
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800501 *</pre>
502 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800503 public final KeyDeserializer findKeyDeserializer(JavaType keyType,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700504 BeanProperty prop) throws JsonMappingException {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800505 KeyDeserializer kd = _cache.findKeyDeserializer(this,
506 _factory, keyType);
Tatud0bb3152012-01-31 13:04:06 -0800507 // Second: contextualize?
508 if (kd instanceof ContextualKeyDeserializer) {
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700509 kd = ((ContextualKeyDeserializer) kd).createContextual(this, prop);
Tatud0bb3152012-01-31 13:04:06 -0800510 }
511 return kd;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800512 }
513
Tatub37ff332012-01-24 16:19:36 -0800514 /*
515 /**********************************************************
Tatu Saloranta34a8adf2012-02-08 22:07:36 -0800516 /* Public API, ObjectId handling
517 /**********************************************************
518 */
519
520 /**
521 * Method called to find and return entry corresponding to given
522 * Object Id: will add an entry if necessary, and never returns null
523 */
Pascal GĂ©linas184cae32014-02-05 17:35:56 -0500524 public abstract ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator, ObjectIdResolver resolver);
525
Pascal GĂ©linas096e02b2013-12-18 17:21:42 -0500526 /**
527 * Method called to ensure that every object id encounter during processing
528 * are resolved.
529 *
530 * @throws UnresolvedForwardReference
531 */
532 public abstract void checkUnresolvedObjectId()
533 throws UnresolvedForwardReference;
534
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800535 /*
536 /**********************************************************
537 /* Public API, type handling
538 /**********************************************************
539 */
540
541 /**
542 * Convenience method, functionally equivalent to:
543 *<pre>
544 * getConfig().constructType(cls);
545 * </pre>
546 */
547 public final JavaType constructType(Class<?> cls) {
Tatu Saloranta816bbed2016-10-05 21:13:12 -0700548 return (cls == null) ? null : _config.constructType(cls);
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800549 }
550
551 /**
Cowtowncodera5bd0a22015-06-25 15:27:07 -0700552 * Helper method that is to be used when resolving basic class name into
553 * Class instance, the reason being that it may be necessary to work around
554 * various ClassLoader limitations, as well as to handle primitive type
555 * signatures.
556 *
557 * @since 2.6
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800558 */
559 public Class<?> findClass(String className) throws ClassNotFoundException
560 {
561 // By default, delegate to ClassUtil: can be overridden with custom handling
Cowtowncodera5bd0a22015-06-25 15:27:07 -0700562 return getTypeFactory().findClass(className);
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800563 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800564
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800565 /*
566 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800567 /* Public API, helper object recycling
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800568 /**********************************************************
569 */
570
571 /**
572 * Method that can be used to get access to a reusable ObjectBuffer,
573 * useful for efficiently constructing Object arrays and Lists.
574 * Note that leased buffers should be returned once deserializer
575 * is done, to allow for reuse during same round of deserialization.
576 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800577 public final ObjectBuffer leaseObjectBuffer()
578 {
579 ObjectBuffer buf = _objectBuffer;
580 if (buf == null) {
581 buf = new ObjectBuffer();
582 } else {
583 _objectBuffer = null;
584 }
585 return buf;
586 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800587
588 /**
589 * Method to call to return object buffer previously leased with
590 * {@link #leaseObjectBuffer}.
591 *
592 * @param buf Returned object buffer
593 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800594 public final void returnObjectBuffer(ObjectBuffer buf)
595 {
596 /* Already have a reusable buffer? Let's retain bigger one
597 * (or if equal, favor newer one, shorter life-cycle)
598 */
599 if (_objectBuffer == null
600 || buf.initialCapacity() >= _objectBuffer.initialCapacity()) {
601 _objectBuffer = buf;
602 }
603 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800604
605 /**
606 * Method for accessing object useful for building arrays of
607 * primitive types (such as int[]).
608 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800609 public final ArrayBuilders getArrayBuilders()
610 {
611 if (_arrayBuilders == null) {
612 _arrayBuilders = new ArrayBuilders();
613 }
614 return _arrayBuilders;
615 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800616
617 /*
618 /**********************************************************
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700619 /* Extended API: handler instantiation
620 /**********************************************************
621 */
622
623 public abstract JsonDeserializer<Object> deserializerInstance(Annotated annotated,
624 Object deserDef)
625 throws JsonMappingException;
626
627 public abstract KeyDeserializer keyDeserializerInstance(Annotated annotated,
628 Object deserDef)
629 throws JsonMappingException;
630
631 /*
632 /**********************************************************
633 /* Extended API: resolving contextual deserializers; called
634 /* by structured deserializers for their value/component
635 /* deserializers
636 /**********************************************************
637 */
638
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700639 /**
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700640 * Method called for primary property deserializers (ones
Tatu Saloranta59fe29c2013-09-05 22:37:06 -0700641 * directly created to deserialize values of a POJO property),
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700642 * to handle details of resolving
643 * {@link ContextualDeserializer} with given property context.
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700644 *
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700645 * @param prop Property for which the given primary deserializer is used; never null.
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700646 *
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800647 * @since 2.5
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700648 */
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700649 public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> deser,
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800650 BeanProperty prop, JavaType type)
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700651 throws JsonMappingException
652 {
Cowtowncodera2e27202014-11-25 17:07:52 -0800653 if (deser instanceof ContextualDeserializer) {
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800654 _currentType = new LinkedNode<JavaType>(type, _currentType);
655 try {
656 deser = ((ContextualDeserializer) deser).createContextual(this, prop);
657 } finally {
658 _currentType = _currentType.next();
659 }
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700660 }
661 return deser;
662 }
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700663
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700664 /**
665 * Method called for secondary property deserializers (ones
666 * NOT directly created to deal with an annotatable POJO property,
667 * but instead created as a component -- such as value deserializers
668 * for structured types, or deserializers for root values)
669 * to handle details of resolving
670 * {@link ContextualDeserializer} with given property context.
Tatu Saloranta59fe29c2013-09-05 22:37:06 -0700671 * Given that these deserializers are not directly related to given property
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700672 * (or, in case of root value property, to any property), annotations
673 * accessible may or may not be relevant.
674 *
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700675 * @param prop Property for which deserializer is used, if any; null
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700676 * when deserializing root values
677 *
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800678 * @since 2.5
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700679 */
680 public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?> deser,
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800681 BeanProperty prop, JavaType type)
682 throws JsonMappingException
683 {
684 if (deser instanceof ContextualDeserializer) {
685 _currentType = new LinkedNode<JavaType>(type, _currentType);
686 try {
687 deser = ((ContextualDeserializer) deser).createContextual(this, prop);
688 } finally {
689 _currentType = _currentType.next();
690 }
691 }
692 return deser;
693 }
694
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700695 /*
696 /**********************************************************
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800697 /* Parsing methods that may use reusable/-cyclable objects
698 /**********************************************************
699 */
700
701 /**
702 * Convenience method for parsing a Date from given String, using
703 * currently configured date format (accessed using
704 * {@link DeserializationConfig#getDateFormat()}).
705 *<p>
706 * Implementation will handle thread-safety issues related to
707 * date formats such that first time this method is called,
708 * date format is cloned, and cloned instance will be retained
709 * for use during this deserialization round.
710 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700711 public Date parseDate(String dateStr) throws IllegalArgumentException
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800712 {
713 try {
Tatu Salorantaef00ac62013-11-03 09:56:39 -0800714 DateFormat df = getDateFormat();
715 return df.parse(dateStr);
Tatu Salorantaaa512742012-02-22 22:51:33 -0800716 } catch (ParseException e) {
Tatu Saloranta8e9d4b22015-05-01 21:26:32 -0700717 throw new IllegalArgumentException(String.format(
718 "Failed to parse Date value '%s': %s", dateStr, e.getMessage()));
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800719 }
720 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800721
722 /**
723 * Convenience method for constructing Calendar instance set
724 * to specified time, to be modified and used by caller.
725 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700726 public Calendar constructCalendar(Date d) {
727 // 08-Jan-2008, tatu: not optimal, but should work for the most part; let's revise as needed.
Tatu Salorantaaa512742012-02-22 22:51:33 -0800728 Calendar c = Calendar.getInstance(getTimeZone());
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800729 c.setTime(d);
730 return c;
731 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800732
733 /*
734 /**********************************************************
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700735 /* Convenience methods for reading parsed values
736 /**********************************************************
737 */
738
739 /**
740 * Convenience method that may be used by composite or container deserializers,
741 * for reading one-off values contained (for sequences, it is more efficient
742 * to actually fetch deserializer once for the whole collection).
743 *<p>
744 * NOTE: when deserializing values of properties contained in composite types,
745 * rather use {@link #readPropertyValue(JsonParser, BeanProperty, Class)};
746 * this method does not allow use of contextual annotations.
747 *
748 * @since 2.4
749 */
750 public <T> T readValue(JsonParser p, Class<T> type) throws IOException {
751 return readValue(p, getTypeFactory().constructType(type));
752 }
753
754 /**
755 * @since 2.4
756 */
757 @SuppressWarnings("unchecked")
758 public <T> T readValue(JsonParser p, JavaType type) throws IOException {
759 JsonDeserializer<Object> deser = findRootValueDeserializer(type);
760 if (deser == null) {
Tatu Salorantac1478ac2016-09-29 08:17:03 -0700761 reportBadDefinition(type,
762 "Could not find JsonDeserializer for type "+type);
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700763 }
764 return (T) deser.deserialize(p, this);
765 }
766
767 /**
768 * Convenience method that may be used by composite or container deserializers,
769 * for reading one-off values for the composite type, taking into account
770 * annotations that the property (passed to this method -- usually property that
771 * has custom serializer that called this method) has.
772 *
773 * @since 2.4
774 */
775 public <T> T readPropertyValue(JsonParser p, BeanProperty prop, Class<T> type) throws IOException {
776 return readPropertyValue(p, prop, getTypeFactory().constructType(type));
777 }
778
779 /**
780 * @since 2.4
781 */
782 @SuppressWarnings("unchecked")
783 public <T> T readPropertyValue(JsonParser p, BeanProperty prop, JavaType type) throws IOException {
784 JsonDeserializer<Object> deser = findContextualValueDeserializer(type, prop);
785 if (deser == null) {
Tatu Saloranta5ae6e4b2015-10-05 21:49:01 -0700786 String propName = (prop == null) ? "NULL" : ("'"+prop.getName()+"'");
Tatu Salorantac1478ac2016-09-29 08:17:03 -0700787 return reportBadDefinition(type, String.format(
Tatu Saloranta851092c2016-05-21 20:08:40 -0700788 "Could not find JsonDeserializer for type %s (via property %s)",
Tatu Salorantac1478ac2016-09-29 08:17:03 -0700789 type, propName));
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700790 }
791 return (T) deser.deserialize(p, this);
792 }
Tatu Saloranta5ae6e4b2015-10-05 21:49:01 -0700793
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700794 /*
795 /**********************************************************
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700796 /* Methods for problem handling
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800797 /**********************************************************
798 */
799
800 /**
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700801 * Method that deserializers should call if they encounter an unrecognized
802 * property (and once that is not explicitly designed as ignorable), to
803 * inform possibly configured {@link DeserializationProblemHandler}s and
804 * let it handle the problem.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800805 *
806 * @return True if there was a configured problem handler that was able to handle the
Tatu Saloranta0e3b3832012-01-22 22:08:20 -0800807 * problem
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800808 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700809 public boolean handleUnknownProperty(JsonParser p, JsonDeserializer<?> deser,
Tatu Saloranta060ce112012-02-01 22:18:09 -0800810 Object instanceOrClass, String propName)
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700811 throws IOException
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800812 {
813 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700814 while (h != null) {
815 // Can bail out if it's handled
816 if (h.value().handleUnknownProperty(this, p, deser, instanceOrClass, propName)) {
817 return true;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800818 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700819 h = h.next();
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800820 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700821 // Nope, not handled. Potentially that's a problem...
822 if (!isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
823 p.skipChildren();
824 return true;
825 }
826 // Do we know properties that are expected instead?
827 Collection<Object> propIds = (deser == null) ? null : deser.getKnownPropertyNames();
828 throw UnrecognizedPropertyException.from(_parser,
829 instanceOrClass, propName, propIds);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800830 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800831
832 /**
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700833 * Method that deserializers should call if they encounter a String value
834 * that can not be converted to expected key of a {@link java.util.Map}
835 * valued property.
836 * Default implementation will try to call {@link DeserializationProblemHandler#handleWeirdNumberValue}
837 * on configured handlers, if any, to allow for recovery; if recovery does not
838 * succeed, will throw {@link InvalidFormatException} with given message.
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700839 *
840 * @param keyClass Expected type for key
841 * @param keyValue String value from which to deserialize key
842 * @param msg Error message template caller wants to use if exception is to be thrown
843 * @param msgArgs Optional arguments to use for message, if any
844 *
845 * @return Key value to use
846 *
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700847 * @throws IOException To indicate unrecoverable problem, usually based on <code>msg</code>
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700848 *
849 * @since 2.8
850 */
851 public Object handleWeirdKey(Class<?> keyClass, String keyValue,
852 String msg, Object... msgArgs)
853 throws IOException
854 {
855 // but if not handled, just throw exception
Tatu Saloranta79124862016-10-19 22:13:29 -0700856 msg = _format(msg, msgArgs);
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700857 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700858 while (h != null) {
859 // Can bail out if it's handled
860 Object key = h.value().handleWeirdKey(this, keyClass, keyValue, msg);
Tatu Saloranta2d318f62016-05-10 21:58:00 -0700861 if (key != DeserializationProblemHandler.NOT_HANDLED) {
Tatu Salorantad01e3ab2016-05-19 09:31:38 -0700862 // Sanity check for broken handlers, otherwise nasty to debug:
863 if ((key == null) || keyClass.isInstance(key)) {
864 return key;
865 }
866 throw weirdStringException(keyValue, keyClass, String.format(
867 "DeserializationProblemHandler.handleWeirdStringValue() for type %s returned value of type %s",
868 keyClass, key.getClass()));
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700869 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700870 h = h.next();
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700871 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700872 throw weirdKeyException(keyClass, keyValue, msg);
873 }
874
875 /**
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -0700876 * Method that deserializers should call if they encounter a String value
877 * that can not be converted to target property type, in cases where some
878 * String values could be acceptable (either with different settings,
879 * or different value).
880 * Default implementation will try to call {@link DeserializationProblemHandler#handleWeirdStringValue}
881 * on configured handlers, if any, to allow for recovery; if recovery does not
882 * succeed, will throw {@link InvalidFormatException} with given message.
883 *
884 * @param targetClass Type of property into which incoming number should be converted
885 * @param value String value from which to deserialize property value
886 * @param msg Error message template caller wants to use if exception is to be thrown
887 * @param msgArgs Optional arguments to use for message, if any
888 *
889 * @return Property value to use
890 *
891 * @throws IOException To indicate unrecoverable problem, usually based on <code>msg</code>
892 *
893 * @since 2.8
894 */
895 public Object handleWeirdStringValue(Class<?> targetClass, String value,
896 String msg, Object... msgArgs)
897 throws IOException
898 {
899 // but if not handled, just throw exception
Tatu Saloranta79124862016-10-19 22:13:29 -0700900 msg = _format(msg, msgArgs);
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -0700901 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
902 while (h != null) {
903 // Can bail out if it's handled
Tatu Salorantad01e3ab2016-05-19 09:31:38 -0700904 Object instance = h.value().handleWeirdStringValue(this, targetClass, value, msg);
905 if (instance != DeserializationProblemHandler.NOT_HANDLED) {
906 // Sanity check for broken handlers, otherwise nasty to debug:
907 if ((instance == null) || targetClass.isInstance(instance)) {
908 return instance;
909 }
910 throw weirdStringException(value, targetClass, String.format(
911 "DeserializationProblemHandler.handleWeirdStringValue() for type %s returned value of type %s",
912 targetClass, instance.getClass()));
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -0700913 }
914 h = h.next();
915 }
916 throw weirdStringException(value, targetClass, msg);
917 }
918
919 /**
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700920 * Method that deserializers should call if they encounter a numeric value
921 * that can not be converted to target property type, in cases where some
922 * numeric values could be acceptable (either with different settings,
923 * or different numeric value).
924 * Default implementation will try to call {@link DeserializationProblemHandler#handleWeirdNumberValue}
925 * on configured handlers, if any, to allow for recovery; if recovery does not
926 * succeed, will throw {@link InvalidFormatException} with given message.
927 *
928 * @param targetClass Type of property into which incoming number should be converted
929 * @param value Number value from which to deserialize property value
930 * @param msg Error message template caller wants to use if exception is to be thrown
931 * @param msgArgs Optional arguments to use for message, if any
932 *
933 * @return Property value to use
934 *
935 * @throws IOException To indicate unrecoverable problem, usually based on <code>msg</code>
936 *
937 * @since 2.8
938 */
939 public Object handleWeirdNumberValue(Class<?> targetClass, Number value,
940 String msg, Object... msgArgs)
941 throws IOException
942 {
Tatu Saloranta79124862016-10-19 22:13:29 -0700943 msg = _format(msg, msgArgs);
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700944 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
945 while (h != null) {
946 // Can bail out if it's handled
947 Object key = h.value().handleWeirdNumberValue(this, targetClass, value, msg);
948 if (key != DeserializationProblemHandler.NOT_HANDLED) {
Tatu Salorantad01e3ab2016-05-19 09:31:38 -0700949 // Sanity check for broken handlers, otherwise nasty to debug:
950 if ((key == null) || targetClass.isInstance(key)) {
951 return key;
952 }
953 throw weirdNumberException(value, targetClass, String.format(
954 "DeserializationProblemHandler.handleWeirdNumberValue() for type %s returned value of type %s",
955 targetClass, key.getClass()));
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700956 }
957 h = h.next();
958 }
959 throw weirdNumberException(value, targetClass, msg);
960 }
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -0700961
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700962 /**
Tatu Saloranta68245442016-05-21 18:08:41 -0700963 * Method that deserializers should call if they fail to instantiate value
964 * due to lack of viable instantiator (usually creator, that is, constructor
965 * or static factory method). Method should be called at point where value
966 * has not been decoded, so that handler has a chance to handle decoding
967 * using alternate mechanism, and handle underlying content (possibly by
968 * just skipping it) to keep input state valid
Tatu Saloranta609a0f82016-05-18 20:17:10 -0700969 *
Tatu Saloranta68245442016-05-21 18:08:41 -0700970 * @param instClass Type that was to be instantiated
Tatu Salorantaed416862016-10-16 13:42:12 -0700971 * @param valueInst (optional) Value instantiator to be used, if any; null if type does not
972 * use one for instantiation (custom deserialiers don't; standard POJO deserializer does)
Tatu Saloranta68245442016-05-21 18:08:41 -0700973 * @param p Parser that points to the JSON value to decode
Tatu Saloranta609a0f82016-05-18 20:17:10 -0700974 *
Tatu Saloranta68245442016-05-21 18:08:41 -0700975 * @return Object that should be constructed, if any; has to be of type <code>instClass</code>
Tatu Saloranta609a0f82016-05-18 20:17:10 -0700976 *
Tatu Salorantaed416862016-10-16 13:42:12 -0700977 * @since 2.9 (2.8 had alternate that did not take <code>ValueInstantiator</code>)
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700978 */
Tatu Salorantaed416862016-10-16 13:42:12 -0700979 @SuppressWarnings("resource")
980 public Object handleMissingInstantiator(Class<?> instClass, ValueInstantiator valueInst,
981 JsonParser p, String msg, Object... msgArgs)
Tatu Saloranta68245442016-05-21 18:08:41 -0700982 throws IOException
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700983 {
Tatu Salorantaed416862016-10-16 13:42:12 -0700984 if (p == null) {
985 p = getParser();
986 }
Tatu Saloranta79124862016-10-19 22:13:29 -0700987 msg = _format(msg, msgArgs);
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700988 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
989 while (h != null) {
990 // Can bail out if it's handled
Tatu Saloranta68245442016-05-21 18:08:41 -0700991 Object instance = h.value().handleMissingInstantiator(this,
Tatu Salorantaed416862016-10-16 13:42:12 -0700992 instClass, valueInst, p, msg);
Tatu Saloranta68245442016-05-21 18:08:41 -0700993 if (instance != DeserializationProblemHandler.NOT_HANDLED) {
994 // Sanity check for broken handlers, otherwise nasty to debug:
995 if ((instance == null) || instClass.isInstance(instance)) {
996 return instance;
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700997 }
Tatu Saloranta816bbed2016-10-05 21:13:12 -0700998 reportBadDefinition(constructType(instClass), String.format(
999"DeserializationProblemHandler.handleMissingInstantiator() for type %s returned value of type %s",
Tatu Saloranta68245442016-05-21 18:08:41 -07001000 instClass, instance.getClass()));
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -07001001 }
1002 h = h.next();
1003 }
Tatu Salorantaed416862016-10-16 13:42:12 -07001004
1005 // 16-Oct-2016, tatu: This is either a definition problem (if no applicable creator
1006 // exists), or input mismatch problem (otherwise) since none of existing cretors
1007 // match with token.
1008 if ((valueInst != null) && !valueInst.canInstantiate()) {
1009 msg = String.format("Can not construct instance of %s (no Creators, like default construct, exist): %s",
1010 instClass.getName(), msg);
1011 return reportBadDefinition(constructType(instClass), msg);
1012 }
1013 msg = String.format("Can not construct instance of %s (although at least one Creator exists): %s",
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001014 instClass.getName(), msg);
1015 return reportInputMismatch(instClass, msg);
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001016 }
1017
Tatu Saloranta609a0f82016-05-18 20:17:10 -07001018 /**
1019 * Method that deserializers should call if they fail to instantiate value
1020 * due to an exception that was thrown by constructor (or other mechanism used
1021 * to create instances).
1022 * Default implementation will try to call {@link DeserializationProblemHandler#handleInstantiationProblem}
1023 * on configured handlers, if any, to allow for recovery; if recovery does not
1024 * succeed, will throw exception constructed with {@link #instantiationException}.
1025 *
1026 * @param instClass Type that was to be instantiated
1027 * @param argument (optional) Argument that was passed to constructor or equivalent
1028 * instantiator; often a {@link java.lang.String}.
1029 * @param t Exception that caused failure
1030 *
1031 * @return Object that should be constructed, if any; has to be of type <code>instClass</code>
1032 *
1033 * @since 2.8
1034 */
1035 public Object handleInstantiationProblem(Class<?> instClass, Object argument,
1036 Throwable t)
1037 throws IOException
1038 {
1039 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
1040 while (h != null) {
1041 // Can bail out if it's handled
Tatu Salorantad01e3ab2016-05-19 09:31:38 -07001042 Object instance = h.value().handleInstantiationProblem(this, instClass, argument, t);
1043 if (instance != DeserializationProblemHandler.NOT_HANDLED) {
1044 // Sanity check for broken handlers, otherwise nasty to debug:
1045 if ((instance == null) || instClass.isInstance(instance)) {
1046 return instance;
1047 }
Tatu Saloranta816bbed2016-10-05 21:13:12 -07001048 reportBadDefinition(constructType(instClass), String.format(
1049"DeserializationProblemHandler.handleInstantiationProblem() for type %s returned value of type %s",
Tatu Salorantad01e3ab2016-05-19 09:31:38 -07001050 instClass, instance.getClass()));
Tatu Saloranta609a0f82016-05-18 20:17:10 -07001051 }
1052 h = h.next();
1053 }
1054 // 18-May-2016, tatu: Only wrap if not already a valid type to throw
1055 if (t instanceof IOException) {
1056 throw (IOException) t;
1057 }
1058 throw instantiationException(instClass, t);
1059 }
1060
Tatu Saloranta68245442016-05-21 18:08:41 -07001061 /**
Tatu Saloranta851092c2016-05-21 20:08:40 -07001062 * Method that deserializers should call if the first token of the value to
1063 * deserialize is of unexpected type (that is, type of token that deserializer
1064 * can not handle). This could occur, for example, if a Number deserializer
1065 * encounter {@link JsonToken#START_ARRAY} instead of
1066 * {@link JsonToken#VALUE_NUMBER_INT} or {@link JsonToken#VALUE_NUMBER_FLOAT}.
1067 *
1068 * @param instClass Type that was to be instantiated
1069 * @param p Parser that points to the JSON value to decode
1070 *
1071 * @return Object that should be constructed, if any; has to be of type <code>instClass</code>
1072 *
1073 * @since 2.8
1074 */
1075 public Object handleUnexpectedToken(Class<?> instClass, JsonParser p)
1076 throws IOException
1077 {
1078 return handleUnexpectedToken(instClass, p.getCurrentToken(), p, null);
1079 }
1080
1081 /**
1082 * Method that deserializers should call if the first token of the value to
1083 * deserialize is of unexpected type (that is, type of token that deserializer
1084 * can not handle). This could occur, for example, if a Number deserializer
1085 * encounter {@link JsonToken#START_ARRAY} instead of
1086 * {@link JsonToken#VALUE_NUMBER_INT} or {@link JsonToken#VALUE_NUMBER_FLOAT}.
1087 *
1088 * @param instClass Type that was to be instantiated
Tatu Saloranta2a877182016-10-15 18:18:22 -07001089 * @param t Token encountered that does match expected
Tatu Saloranta851092c2016-05-21 20:08:40 -07001090 * @param p Parser that points to the JSON value to decode
1091 *
1092 * @return Object that should be constructed, if any; has to be of type <code>instClass</code>
1093 *
1094 * @since 2.8
1095 */
1096 public Object handleUnexpectedToken(Class<?> instClass, JsonToken t,
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001097 JsonParser p, String msg, Object... msgArgs)
Tatu Saloranta851092c2016-05-21 20:08:40 -07001098 throws IOException
1099 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001100 msg = _format(msg, msgArgs);
Tatu Saloranta851092c2016-05-21 20:08:40 -07001101 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
1102 while (h != null) {
1103 Object instance = h.value().handleUnexpectedToken(this,
1104 instClass, t, p, msg);
1105 if (instance != DeserializationProblemHandler.NOT_HANDLED) {
1106 if ((instance == null) || instClass.isInstance(instance)) {
1107 return instance;
1108 }
Tatu Saloranta2a877182016-10-15 18:18:22 -07001109 reportBadDefinition(constructType(instClass), String.format(
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001110 "DeserializationProblemHandler.handleUnexpectedToken() for type %s returned value of type %s",
Tatu Saloranta2a877182016-10-15 18:18:22 -07001111 instance.getClass()));
Tatu Saloranta851092c2016-05-21 20:08:40 -07001112 }
1113 h = h.next();
1114 }
Tatu Saloranta851092c2016-05-21 20:08:40 -07001115 if (msg == null) {
Tatu Saloranta73359ae2016-06-06 08:44:54 -07001116 if (t == null) {
1117 msg = String.format("Unexpected end-of-input when binding data into %s",
1118 _calcName(instClass));
1119 } else {
1120 msg = String.format("Can not deserialize instance of %s out of %s token",
1121 _calcName(instClass), t);
1122 }
Tatu Saloranta851092c2016-05-21 20:08:40 -07001123 }
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001124 reportInputMismatch(instClass, msg);
Tatu Salorantaacc533a2016-05-22 21:47:18 -07001125 return null; // never gets here
Tatu Saloranta851092c2016-05-21 20:08:40 -07001126 }
1127
1128 /**
Tatu Saloranta68245442016-05-21 18:08:41 -07001129 * Method that deserializers should call if they encounter a type id
1130 * (for polymorphic deserialization) that can not be resolved to an
1131 * actual type; usually since there is no mapping defined.
1132 * Default implementation will try to call {@link DeserializationProblemHandler#handleUnknownTypeId}
1133 * on configured handlers, if any, to allow for recovery; if recovery does not
1134 * succeed, will throw exception constructed with {@link #unknownTypeIdException}.
1135 *
1136 * @param baseType Base type from which resolution starts
1137 * @param id Type id that could not be converted
1138 * @param extraDesc Additional problem description to add to default exception message,
1139 * if resolution fails.
1140 *
1141 * @return {@link JavaType} that id resolves to
1142 *
1143 * @throws IOException To indicate unrecoverable problem, if resolution can not
1144 * be made to work
1145 *
1146 * @since 2.8
1147 */
1148 public JavaType handleUnknownTypeId(JavaType baseType, String id,
Tatu Salorantad6230fd2016-05-30 21:11:19 -07001149 TypeIdResolver idResolver, String extraDesc) throws IOException
Tatu Saloranta68245442016-05-21 18:08:41 -07001150 {
1151 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
1152 while (h != null) {
1153 // Can bail out if it's handled
Tatu Salorantad6230fd2016-05-30 21:11:19 -07001154 JavaType type = h.value().handleUnknownTypeId(this, baseType, id, idResolver, extraDesc);
Tatu Saloranta68245442016-05-21 18:08:41 -07001155 if (type != null) {
1156 if (type.hasRawClass(Void.class)) {
1157 return null;
1158 }
1159 // But ensure there's type compatibility
1160 if (type.isTypeOrSubTypeOf(baseType.getRawClass())) {
1161 return type;
1162 }
1163 throw unknownTypeIdException(baseType, id,
1164 "problem handler tried to resolve into non-subtype: "+type);
1165 }
1166 h = h.next();
1167 }
Tatu Saloranta811ec172016-05-24 23:39:04 -07001168 // 24-May-2016, tatu: Actually we may still not want to fail quite yet
1169 if (!isEnabled(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE)) {
1170 return null;
1171 }
Tatu Saloranta68245442016-05-21 18:08:41 -07001172 throw unknownTypeIdException(baseType, id, extraDesc);
1173 }
1174
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001175 /*
1176 /**********************************************************
Tatu Saloranta68245442016-05-21 18:08:41 -07001177 /* Methods for problem reporting, in cases where recovery
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001178 /* is not considered possible: input problem
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001179 /**********************************************************
1180 */
1181
1182 /**
Tatu Saloranta68245442016-05-21 18:08:41 -07001183 * Method for deserializers to call
1184 * when the token encountered was of type different than what <b>should</b>
1185 * be seen at that position, usually within a sequence of expected tokens.
1186 * Note that this method will throw a {@link JsonMappingException} and no
1187 * recovery is attempted (via {@link DeserializationProblemHandler}, as
1188 * problem is considered to be difficult to recover from, in general.
1189 *
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001190 * @since 2.9
Tatu Saloranta68245442016-05-21 18:08:41 -07001191 */
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001192 public void reportWrongTokenException(JsonDeserializer<?> deser,
1193 JsonToken expToken, String msg, Object... msgArgs)
1194 throws JsonMappingException
1195 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001196 msg = _format(msg, msgArgs);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001197 throw wrongTokenException(getParser(), deser.handledType(), expToken, msg);
1198 }
1199
1200 /**
1201 * Method for deserializers to call
1202 * when the token encountered was of type different than what <b>should</b>
1203 * be seen at that position, usually within a sequence of expected tokens.
1204 * Note that this method will throw a {@link JsonMappingException} and no
1205 * recovery is attempted (via {@link DeserializationProblemHandler}, as
1206 * problem is considered to be difficult to recover from, in general.
1207 *
1208 * @since 2.9
1209 */
1210 public void reportWrongTokenException(JavaType targetType,
1211 JsonToken expToken, String msg, Object... msgArgs)
1212 throws JsonMappingException
1213 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001214 msg = _format(msg, msgArgs);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001215 throw wrongTokenException(getParser(), targetType, expToken, msg);
1216 }
1217
1218 /**
1219 * Method for deserializers to call
1220 * when the token encountered was of type different than what <b>should</b>
1221 * be seen at that position, usually within a sequence of expected tokens.
1222 * Note that this method will throw a {@link JsonMappingException} and no
1223 * recovery is attempted (via {@link DeserializationProblemHandler}, as
1224 * problem is considered to be difficult to recover from, in general.
1225 *
1226 * @since 2.9
1227 */
1228 public void reportWrongTokenException(Class<?> targetType,
1229 JsonToken expToken, String msg, Object... msgArgs)
1230 throws JsonMappingException
1231 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001232 msg = _format(msg, msgArgs);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001233 throw wrongTokenException(getParser(), targetType, expToken, msg);
1234 }
Tatu Saloranta9d1fb752016-06-07 22:47:04 -07001235
1236 /**
1237 * @since 2.8
1238 */
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001239 public <T> T reportUnresolvedObjectId(ObjectIdReader oidReader, Object bean)
Tatu Saloranta9d1fb752016-06-07 22:47:04 -07001240 throws JsonMappingException
1241 {
1242 String msg = String.format("No Object Id found for an instance of %s, to assign to property '%s'",
1243 bean.getClass().getName(), oidReader.propertyName);
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001244 return reportInputMismatch(oidReader.idProperty, msg);
Tatu Saloranta9d1fb752016-06-07 22:47:04 -07001245 }
1246
Tatu Salorantabb06aa02016-09-08 22:38:23 -07001247 /**
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001248 * Helper method used to indicate a problem with input in cases where more
1249 * specific <code>reportXxx()</code> method was not available.
1250 *
1251 * @since 2.9
1252 */
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001253 public <T> T reportInputMismatch(BeanProperty prop,
1254 String msg, Object... msgArgs) throws JsonMappingException
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001255 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001256 msg = _format(msg, msgArgs);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001257 throw InputMismatchException.from(getParser(), prop.getType(), msg);
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001258 }
1259
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001260 /**
1261 * Helper method used to indicate a problem with input in cases where more
1262 * specific <code>reportXxx()</code> method was not available.
1263 *
1264 * @since 2.9
1265 */
1266 public <T> T reportInputMismatch(JsonDeserializer<?> src,
1267 String msg, Object... msgArgs) throws JsonMappingException
1268 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001269 msg = _format(msg, msgArgs);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001270 throw InputMismatchException.from(getParser(), src.handledType(), msg);
1271 }
1272
1273 /**
1274 * Helper method used to indicate a problem with input in cases where more
1275 * specific <code>reportXxx()</code> method was not available.
1276 *
1277 * @since 2.9
1278 */
1279 public <T> T reportInputMismatch(Class<?> targetType,
1280 String msg, Object... msgArgs) throws JsonMappingException
1281 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001282 msg = _format(msg, msgArgs);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001283 throw InputMismatchException.from(getParser(), targetType, msg);
1284 }
1285
1286 /**
1287 * Helper method used to indicate a problem with input in cases where more
1288 * specific <code>reportXxx()</code> method was not available.
1289 *
1290 * @since 2.9
1291 */
1292 public <T> T reportInputMismatch(JavaType targetType,
1293 String msg, Object... msgArgs) throws JsonMappingException
1294 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001295 msg = _format(msg, msgArgs);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001296 throw InputMismatchException.from(getParser(), targetType, msg);
1297 }
Tatu Salorantab8f60292016-10-25 22:50:06 -07001298
1299 @Deprecated // since 2.9
1300 public void reportWrongTokenException(JsonParser p,
1301 JsonToken expToken, String msg, Object... msgArgs)
1302 throws JsonMappingException
1303 {
1304 msg = _format(msg, msgArgs);
1305 throw wrongTokenException(p, expToken, msg);
1306 }
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001307
Tatu Salorantab8f60292016-10-25 22:50:06 -07001308 /**
1309 * Helper method for reporting a problem with unhandled unknown property.
1310 *
1311 * @param instanceOrClass Either value being populated (if one has been
1312 * instantiated), or Class that indicates type that would be (or
1313 * have been) instantiated
1314 * @param deser Deserializer that had the problem, if called by deserializer
1315 * (or on behalf of one)
1316 *
1317 * @deprecated Since 2.8 call {@link #handleUnknownProperty} instead
1318 */
1319 @Deprecated
1320 public void reportUnknownProperty(Object instanceOrClass, String fieldName,
1321 JsonDeserializer<?> deser)
1322 throws JsonMappingException
1323 {
1324 if (isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
1325 // Do we know properties that are expected instead?
1326 Collection<Object> propIds = (deser == null) ? null : deser.getKnownPropertyNames();
1327 throw UnrecognizedPropertyException.from(_parser,
1328 instanceOrClass, fieldName, propIds);
1329 }
1330 }
1331
1332 /**
1333 * @since 2.8
1334 *
1335 * @deprecated Since 2.9: not clear this ever occurs
1336 */
1337 @Deprecated // since 2.9
1338 public void reportMissingContent(String msg, Object... msgArgs) throws JsonMappingException {
1339 throw InputMismatchException.from(getParser(), (JavaType) null, "No content to map due to end-of-input");
1340 }
1341
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001342 /*
1343 /**********************************************************
1344 /* Methods for problem reporting, in cases where recovery
1345 /* is not considered possible: POJO definition problems
1346 /**********************************************************
1347 */
1348
1349 /**
Tatu Salorantabb06aa02016-09-08 22:38:23 -07001350 * Helper method called to indicate problem in POJO (serialization) definitions or settings
1351 * regarding specific Java type, unrelated to actual JSON content to map.
1352 * Default behavior is to construct and throw a {@link JsonMappingException}.
1353 *
1354 * @since 2.9
1355 */
1356 public <T> T reportBadTypeDefinition(BeanDescription bean,
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001357 String msg, Object... msgArgs) throws JsonMappingException {
1358 msg = _format(msg, msgArgs);
Tatu Salorantabb06aa02016-09-08 22:38:23 -07001359 String beanDesc = (bean == null) ? "N/A" : _desc(bean.getType().getGenericSignature());
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001360 msg = String.format("Invalid type definition for type %s: %s", beanDesc, msg);
1361 throw InvalidDefinitionException.from(_parser, msg, bean, null);
Tatu Salorantabb06aa02016-09-08 22:38:23 -07001362 }
1363
1364 /**
1365 * Helper method called to indicate problem in POJO (serialization) definitions or settings
1366 * regarding specific property (of a type), unrelated to actual JSON content to map.
1367 * Default behavior is to construct and throw a {@link JsonMappingException}.
1368 *
1369 * @since 2.9
1370 */
1371 public <T> T reportBadPropertyDefinition(BeanDescription bean, BeanPropertyDefinition prop,
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001372 String msg, Object... msgArgs) throws JsonMappingException {
1373 msg = _format(msg, msgArgs);
Tatu Salorantabb06aa02016-09-08 22:38:23 -07001374 String propName = (prop == null) ? "N/A" : _quotedString(prop.getName());
1375 String beanDesc = (bean == null) ? "N/A" : _desc(bean.getType().getGenericSignature());
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001376 msg = String.format("Invalid definition for property %s (of type %s): %s",
1377 propName, beanDesc, msg);
1378 throw InvalidDefinitionException.from(_parser, msg, bean, prop);
Tatu Salorantabb06aa02016-09-08 22:38:23 -07001379 }
1380
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001381 @Override
1382 public <T> T reportBadDefinition(JavaType type, String msg) throws JsonMappingException {
1383 throw InvalidDefinitionException.from(_parser, msg, type);
Tatu Saloranta851092c2016-05-21 20:08:40 -07001384 }
1385
Tatu Salorantab8f60292016-10-25 22:50:06 -07001386 /**
1387 * Method that deserializer may call if it is called to do an update ("merge")
1388 * but deserializer operates on a non-mergeable type. Although this should
1389 * usually be caught earlier, sometimes it may only be caught during operation
1390 * and if so this is the method to call.
1391 * Note that if {@link MapperFeature#IGNORE_MERGE_FOR_UNMERGEABLE} is enabled,
1392 * this method will simply return null; otherwise {@link InvalidDefinitionException}
1393 * will be thrown.
1394 *
1395 * @since 2.9
1396 */
1397 public <T> T reportBadMerge(JsonDeserializer<?> deser) throws JsonMappingException {
1398 if (isEnabled(MapperFeature.IGNORE_MERGE_FOR_UNMERGEABLE)) {
1399 return null;
1400 }
1401
1402 Class<?> raw = deser.handledType();
1403 JavaType type = constructType(raw);
1404 String msg = String.format("Invalid configuration: values of type %s can not be merged",
1405 type);
1406 throw InvalidDefinitionException.from(getParser(), msg, type);
1407 }
1408
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001409 /*
1410 /**********************************************************
1411 /* Methods for constructing semantic exceptions; usually not
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001412 /* to be called directly, call `handleXxx()` instead
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001413 /**********************************************************
1414 */
1415
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001416 /**
Tatu Saloranta68245442016-05-21 18:08:41 -07001417 * Helper method for constructing {@link JsonMappingException} to indicate
Tatu Saloranta98dd0912016-05-15 23:13:44 -07001418 * that the token encountered was of type different than what <b>should</b>
1419 * be seen at that position, usually within a sequence of expected tokens.
1420 * Note that most of the time this method should NOT be directly called;
1421 * instead, {@link #reportWrongTokenException} should be called and will
1422 * call this method as necessary.
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001423 *
1424 * @since 2.9
Tatu Saloranta98dd0912016-05-15 23:13:44 -07001425 */
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001426 public JsonMappingException wrongTokenException(JsonParser p, JavaType targetType,
Tatu Saloranta79124862016-10-19 22:13:29 -07001427 JsonToken expToken, String extra)
Tatu Saloranta98dd0912016-05-15 23:13:44 -07001428 {
1429 String msg = String.format("Unexpected token (%s), expected %s",
1430 p.getCurrentToken(), expToken);
Tatu Saloranta79124862016-10-19 22:13:29 -07001431 msg = _colonConcat(msg, extra);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001432 return InputMismatchException.from(p, targetType, msg);
1433 }
1434
1435 public JsonMappingException wrongTokenException(JsonParser p, Class<?> targetType,
Tatu Saloranta79124862016-10-19 22:13:29 -07001436 JsonToken expToken, String extra)
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001437 {
1438 String msg = String.format("Unexpected token (%s), expected %s",
1439 p.getCurrentToken(), expToken);
Tatu Saloranta79124862016-10-19 22:13:29 -07001440 msg = _colonConcat(msg, extra);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001441 return InputMismatchException.from(p, targetType, msg);
1442 }
1443
1444 @Deprecated // since 2.9
1445 public JsonMappingException wrongTokenException(JsonParser p, JsonToken expToken,
1446 String msg)
1447 {
1448 return wrongTokenException(p, (JavaType) null, expToken, msg);
Tatu Saloranta98dd0912016-05-15 23:13:44 -07001449 }
1450
1451 /**
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001452 * Helper method for constructing exception to indicate that given JSON
1453 * Object field name was not in format to be able to deserialize specified
1454 * key type.
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001455 * Note that most of the time this method should NOT be called; instead,
1456 * {@link #handleWeirdKey} should be called which will call this method
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001457 * if necessary.
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001458 */
1459 public JsonMappingException weirdKeyException(Class<?> keyClass, String keyValue,
1460 String msg) {
1461 return InvalidFormatException.from(_parser,
1462 String.format("Can not deserialize Map key of type %s from String %s: %s",
1463 keyClass.getName(), _quotedString(keyValue), msg),
1464 keyValue, keyClass);
1465 }
1466
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001467 /**
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001468 * Helper method for constructing exception to indicate that input JSON
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001469 * String was not suitable for deserializing into given target type.
1470 * Note that most of the time this method should NOT be called; instead,
1471 * {@link #handleWeirdStringValue} should be called which will call this method
1472 * if necessary.
1473 *
1474 * @param value String value from input being deserialized
1475 * @param instClass Type that String should be deserialized into
1476 * @param msg Message that describes specific problem
1477 *
1478 * @since 2.1
1479 */
1480 public JsonMappingException weirdStringException(String value, Class<?> instClass,
1481 String msg) {
1482 return InvalidFormatException.from(_parser,
1483 String.format("Can not deserialize value of type %s from String %s: %s",
1484 instClass.getName(), _quotedString(value), msg),
1485 value, instClass);
1486 }
1487
1488 /**
1489 * Helper method for constructing exception to indicate that input JSON
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001490 * Number was not suitable for deserializing into given target type.
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001491 * Note that most of the time this method should NOT be called; instead,
1492 * {@link #handleWeirdNumberValue} should be called which will call this method
1493 * if necessary.
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001494 */
1495 public JsonMappingException weirdNumberException(Number value, Class<?> instClass,
1496 String msg) {
1497 return InvalidFormatException.from(_parser,
1498 String.format("Can not deserialize value of type %s from number %s: %s",
1499 instClass.getName(), String.valueOf(value), msg),
1500 value, instClass);
1501 }
Tatu Salorantab1041d02016-05-19 08:22:50 -07001502
1503 /**
1504 * Helper method for constructing instantiation exception for specified type,
1505 * to indicate problem with physically constructing instance of
1506 * specified class (missing constructor, exception from constructor)
1507 *<p>
1508 * Note that most of the time this method should NOT be called; instead,
1509 * {@link #handleInstantiationProblem} should be called which will call this method
1510 * if necessary.
1511 */
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001512 public JsonMappingException instantiationException(Class<?> instClass, Throwable cause) {
1513 // Most likely problem with Creator definition, right?
1514 JavaType type = constructType(instClass);
1515 String msg = String.format("Can not construct instance of %s, problem: %s",
1516 instClass.getName(), cause.getMessage());
1517 InvalidDefinitionException e = InvalidDefinitionException.from(_parser, msg, type);
1518 e.initCause(cause);
1519 return e;
Tatu Salorantab1041d02016-05-19 08:22:50 -07001520 }
1521
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001522 /**
Tatu Saloranta68245442016-05-21 18:08:41 -07001523 * Helper method for constructing instantiation exception for specified type,
1524 * to indicate that instantiation failed due to missing instantiator
1525 * (creator; constructor or factory method).
1526 *<p>
1527 * Note that most of the time this method should NOT be called; instead,
1528 * {@link #handleMissingInstantiator} should be called which will call this method
1529 * if necessary.
1530 */
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001531 public JsonMappingException instantiationException(Class<?> instClass, String msg0) {
1532 // Most likely problem with Creator definition, right?
1533 JavaType type = constructType(instClass);
1534 String msg = String.format("Can not construct instance of %s: %s", instClass.getName(), msg0);
1535 return InvalidDefinitionException.from(_parser, msg, type);
Tatu Saloranta68245442016-05-21 18:08:41 -07001536 }
1537
1538 /**
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001539 * Helper method for constructing exception to indicate that given type id
1540 * could not be resolved to a valid subtype of specified base type, during
1541 * polymorphic deserialization.
Tatu Salorantab1041d02016-05-19 08:22:50 -07001542 *<p>
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001543 * Note that most of the time this method should NOT be called; instead,
1544 * {@link #handleUnknownTypeId} should be called which will call this method
1545 * if necessary.
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001546 */
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001547 public JsonMappingException unknownTypeIdException(JavaType baseType, String typeId,
1548 String extraDesc) {
1549 String msg = String.format("Could not resolve type id '%s' into a subtype of %s",
1550 typeId, baseType);
Tatu Saloranta79124862016-10-19 22:13:29 -07001551 msg = _colonConcat(msg, extraDesc);
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001552 return InvalidTypeIdException.from(_parser, msg, baseType, typeId);
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001553 }
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001554
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001555 /*
1556 /**********************************************************
Tatu Saloranta851092c2016-05-21 20:08:40 -07001557 /* Deprecated exception factory methods
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001558 /**********************************************************
1559 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001560
Tatu Saloranta7a4193f2016-05-05 12:55:05 -07001561 /**
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001562 * @since 2.5
Tatu Saloranta2ffca932016-05-05 12:23:14 -07001563 *
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -07001564 * @deprecated Since 2.8 use {@link #handleUnknownTypeId} instead
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001565 */
Tatu Saloranta2ffca932016-05-05 12:23:14 -07001566 @Deprecated
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001567 public JsonMappingException unknownTypeException(JavaType type, String id,
1568 String extraDesc) {
Tatu Saloranta8c3eb032016-04-20 22:52:38 -07001569 String msg = String.format("Could not resolve type id '%s' into a subtype of %s",
1570 id, type);
Tatu Saloranta79124862016-10-19 22:13:29 -07001571 msg = _colonConcat(msg, extraDesc);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001572 return InputMismatchException.from(_parser, type, msg);
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001573 }
1574
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001575 /**
1576 * Helper method for constructing exception to indicate that end-of-input was
1577 * reached while still expecting more tokens to deserialize value of specified type.
1578 *
1579 * @deprecated Since 2.8; currently no way to catch EOF at databind level
1580 */
1581 @Deprecated
1582 public JsonMappingException endOfInputException(Class<?> instClass) {
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001583 return InputMismatchException.from(_parser, instClass,
1584 "Unexpected end-of-input when trying to deserialize a "+instClass.getName());
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001585 }
1586
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001587 /*
1588 /**********************************************************
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001589 /* Deprecated methods for constructing, throwing non-specific
1590 /* JsonMappingExceptions: as of 2.9, should use more specific
1591 /* ones.
1592 /**********************************************************
1593 */
1594
1595 /**
1596 * Fallback method that may be called if no other <code>reportXxx</code>
1597 * is applicable -- but only in that case.
1598 *
1599 * @since 2.8
1600 *
1601 * @deprecate Since 2.9: use a more specific method, or {@link #reportBadDefinition(JavaType, String)},
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001602 * or {@link #reportInputMismatch} instead
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001603 */
1604 @Deprecated // since 2.9
1605 public void reportMappingException(String msg, Object... msgArgs)
1606 throws JsonMappingException
1607 {
Tatu Salorantae27ec2d2016-10-24 22:44:16 -07001608 throw JsonMappingException.from(getParser(), _format(msg, msgArgs));
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001609 }
1610
1611 /**
1612 * Helper method for constructing generic mapping exception with specified
1613 * message and current location information.
1614 * Note that application code should almost always call
1615 * one of <code>handleXxx</code> methods, or {@link #reportMappingException(String, Object...)}
1616 * instead.
1617 *
1618 * @since 2.6
1619 *
1620 * @deprecated Since 2.9 use more specific error reporting methods instead
1621 */
1622 @Deprecated
1623 public JsonMappingException mappingException(String message) {
1624 return JsonMappingException.from(getParser(), message);
1625 }
1626
1627 /**
1628 * Helper method for constructing generic mapping exception with specified
1629 * message and current location information
1630 * Note that application code should almost always call
1631 * one of <code>handleXxx</code> methods, or {@link #reportMappingException(String, Object...)}
1632 * instead.
1633 *
1634 * @since 2.6
1635 *
1636 * @deprecated Since 2.9 use more specific error reporting methods instead
1637 */
1638 @Deprecated
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001639 public JsonMappingException mappingException(String msg, Object... msgArgs) {
1640 return JsonMappingException.from(getParser(), _format(msg, msgArgs));
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001641 }
1642
1643 /**
1644 * Helper method for constructing generic mapping exception for specified type
1645 *
1646 * @deprecated Since 2.8 use {@link #handleUnexpectedToken(Class, JsonParser)} instead
1647 */
1648 @Deprecated
1649 public JsonMappingException mappingException(Class<?> targetClass) {
1650 return mappingException(targetClass, _parser.getCurrentToken());
1651 }
1652
1653 /**
1654 * @deprecated Since 2.8 use {@link #handleUnexpectedToken(Class, JsonParser)} instead
1655 */
1656 @Deprecated
1657 public JsonMappingException mappingException(Class<?> targetClass, JsonToken token) {
1658 String tokenDesc = (token == null) ? "<end of input>" : String.format("%s token", token);
1659 return JsonMappingException.from(_parser,
1660 String.format("Can not deserialize instance of %s out of %s",
1661 _calcName(targetClass), tokenDesc));
1662 }
1663
1664 /*
1665 /**********************************************************
Tatu Saloranta851092c2016-05-21 20:08:40 -07001666 /* Other internal methods
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001667 /**********************************************************
1668 */
1669
1670 protected DateFormat getDateFormat()
1671 {
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -08001672 if (_dateFormat != null) {
1673 return _dateFormat;
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001674 }
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -08001675 /* 24-Feb-2012, tatu: At this point, all timezone configuration
Cowtowncoder8d0d6e42015-01-22 15:36:13 -08001676 * should have occurred, with respect to default dateformat
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -08001677 * and timezone configuration. But we still better clone
1678 * an instance as formatters may be stateful.
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -08001679 */
1680 DateFormat df = _config.getDateFormat();
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -08001681 _dateFormat = df = (DateFormat) df.clone();
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -08001682 return df;
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001683 }
1684
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -08001685 protected String _calcName(Class<?> cls) {
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001686 if (cls.isArray()) {
1687 return _calcName(cls.getComponentType())+"[]";
1688 }
1689 return cls.getName();
1690 }
Tatu Saloranta7a3b0b12016-02-09 16:52:28 -08001691
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -08001692 protected String _valueDesc() {
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001693 try {
1694 return _desc(_parser.getText());
1695 } catch (Exception e) {
1696 return "[N/A]";
1697 }
1698 }
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -08001699
1700 protected String _desc(String desc) {
Tatu Saloranta20a67f72015-11-21 14:17:45 -08001701 if (desc == null) {
1702 return "[N/A]";
1703 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001704 // !!! should we quote it? (in case there are control chars, linefeeds)
1705 if (desc.length() > MAX_ERROR_STR_LEN) {
1706 desc = desc.substring(0, MAX_ERROR_STR_LEN) + "]...[" + desc.substring(desc.length() - MAX_ERROR_STR_LEN);
1707 }
1708 return desc;
1709 }
Tatu Saloranta20a67f72015-11-21 14:17:45 -08001710
1711 // @since 2.7
1712 protected String _quotedString(String desc) {
1713 if (desc == null) {
1714 return "[N/A]";
1715 }
1716 // !!! should we quote it? (in case there are control chars, linefeeds)
1717 if (desc.length() > MAX_ERROR_STR_LEN) {
1718 return String.format("\"%s]...[%s\"",
1719 desc.substring(0, MAX_ERROR_STR_LEN),
1720 desc.substring(desc.length() - MAX_ERROR_STR_LEN));
1721 }
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001722 return String.format("\"%s\"", desc);
Tatu Saloranta20a67f72015-11-21 14:17:45 -08001723 }
Tatu Saloranta79124862016-10-19 22:13:29 -07001724
1725 // @since 2.9
1726 protected String _colonConcat(String msgBase, String extra) {
1727 if (extra == null) {
1728 return msgBase;
1729 }
1730 return msgBase + ": " + extra;
1731 }
1732
1733 // @since 2.9
1734 protected String _format(String msg, Object... msgArgs) {
1735 if (msgArgs.length > 0) {
1736 return String.format(msg, msgArgs);
1737 }
1738 return msg;
1739 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001740}