blob: d616a949da2a91e194002afa989288e4bb49c3e7 [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 Salorantae4f23bb2011-12-23 00:31:35 -08006import 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 Salorantae4f23bb2011-12-23 00:31:35 -080012import com.fasterxml.jackson.core.*;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -070013import com.fasterxml.jackson.databind.cfg.ContextAttributes;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080014import com.fasterxml.jackson.databind.deser.*;
Tatu Saloranta34a8adf2012-02-08 22:07:36 -080015import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId;
Tatuc3a73d02012-01-31 12:45:49 -080016import com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer;
Tatu Salorantadd348562012-07-18 17:25:02 -070017import com.fasterxml.jackson.databind.exc.InvalidFormatException;
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -070018import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080019import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
Tatub37ff332012-01-24 16:19:36 -080020import com.fasterxml.jackson.databind.introspect.Annotated;
Tatuc3a73d02012-01-31 12:45:49 -080021import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
Tatu Saloranta2f823442011-12-23 20:25:27 -080022import com.fasterxml.jackson.databind.node.JsonNodeFactory;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080023import com.fasterxml.jackson.databind.type.TypeFactory;
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -080024import com.fasterxml.jackson.databind.util.*;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080025
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080026/**
Tatu Saloranta97f84822012-01-29 21:38:40 -080027 * Context for the process of deserialization a single root-level value.
28 * Used to allow passing in configuration settings and reusable temporary
29 * objects (scrap arrays, containers).
Tatu Saloranta060ce112012-02-01 22:18:09 -080030 *<p>
31 * Instance life-cycle is such that an partially configured "blueprint" object
32 * is registered with {@link ObjectMapper} (and {@link ObjectReader},
33 * and when an actual instance is needed for deserialization,
34 * a fully configured instance will
Tatu Saloranta71e876b2012-02-05 19:15:48 -080035 * be created using a method in excented API of sub-class
36 * ({@link com.fasterxml.jackson.databind.deser.DefaultDeserializationContext#createInstance}).
Tatu Saloranta060ce112012-02-01 22:18:09 -080037 * Each instance is guaranteed to only be used from single-threaded context;
38 * instances may be reused iff no configuration has changed.
39 *<p>
40 * Defined as abstract class so that implementations must define methods
41 * for reconfiguring blueprints and creating instances.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080042 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080043public abstract class DeserializationContext
Tatu Saloranta9439a312013-03-02 13:13:09 -080044 extends DatabindContext
Tatu Saloranta0e114112012-10-06 10:45:41 -070045 implements java.io.Serializable
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080046{
Cowtowncoder7fee92e2015-02-11 16:15:08 -080047 private static final long serialVersionUID = 1L; // 2.6
Tatu Saloranta0e114112012-10-06 10:45:41 -070048
Tatu Saloranta06c20b12012-01-29 21:36:52 -080049 /**
50 * Let's limit length of error messages, for cases where underlying data
51 * may be very large -- no point in spamming logs with megs of meaningless
52 * data.
53 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080054 private final static int MAX_ERROR_STR_LEN = 500;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080055
Tatu Saloranta060ce112012-02-01 22:18:09 -080056 /*
57 /**********************************************************
58 /* Configuration, immutable
59 /**********************************************************
60 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -080061
Tatu Saloranta71e876b2012-02-05 19:15:48 -080062 /**
63 * Object that handle details of {@link JsonDeserializer} caching.
64 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080065 protected final DeserializerCache _cache;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080066
Tatu Saloranta060ce112012-02-01 22:18:09 -080067 /*
68 /**********************************************************
69 /* Configuration, changeable via fluent factories
70 /**********************************************************
71 */
72
73 /**
74 * Read-only factory instance; exposed to let
75 * owners (<code>ObjectMapper</code>, <code>ObjectReader</code>)
76 * access it.
77 */
Tatu Salorantaaa512742012-02-22 22:51:33 -080078 protected final DeserializerFactory _factory;
79
80 /*
81 /**********************************************************
Tatu Saloranta060ce112012-02-01 22:18:09 -080082 /* Configuration that gets set for instances (not blueprints)
Tatu Saloranta71e876b2012-02-05 19:15:48 -080083 /* (partly denormalized for performance)
Tatu Saloranta060ce112012-02-01 22:18:09 -080084 /**********************************************************
85 */
86
Tatu Saloranta71e876b2012-02-05 19:15:48 -080087 /**
88 * Generic deserialization processing configuration
89 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080090 protected final DeserializationConfig _config;
Tatu Saloranta71e876b2012-02-05 19:15:48 -080091
92 /**
93 * Bitmap of {@link DeserializationFeature}s that are enabled
94 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080095 protected final int _featureFlags;
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -080096
Tatu Saloranta71e876b2012-02-05 19:15:48 -080097 /**
98 * Currently active view, if any.
99 */
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800100 protected final Class<?> _view;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800101
102 /**
103 * Currently active parser used for deserialization.
104 * May be different from the outermost parser
105 * when content is buffered.
106 */
Tatu Salorantaf5211582012-10-05 17:09:47 -0700107 protected transient JsonParser _parser;
Tatuc3a73d02012-01-31 12:45:49 -0800108
Tatu Saloranta71e876b2012-02-05 19:15:48 -0800109 /**
110 * Object used for resolving references to injectable
111 * values.
112 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800113 protected final InjectableValues _injectableValues;
114
Tatu Saloranta060ce112012-02-01 22:18:09 -0800115 /*
116 /**********************************************************
117 /* Per-operation reusable helper objects (not for blueprints)
118 /**********************************************************
119 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800120
Tatu Salorantaf5211582012-10-05 17:09:47 -0700121 protected transient ArrayBuilders _arrayBuilders;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800122
Tatu Salorantaf5211582012-10-05 17:09:47 -0700123 protected transient ObjectBuffer _objectBuffer;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800124
Tatu Salorantaf5211582012-10-05 17:09:47 -0700125 protected transient DateFormat _dateFormat;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700126
127 /**
128 * Lazily-constructed holder for per-call attributes.
129 *
130 * @since 2.3
131 */
132 protected transient ContextAttributes _attributes;
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800133
134 /**
135 * Type of {@link JsonDeserializer} (or, more specifically,
Cowtowncoder08efeba2015-05-05 12:34:11 -0700136 * {@link ContextualDeserializer}) that is being
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800137 * contextualized currently.
138 *
139 * @since 2.5
140 */
141 protected LinkedNode<JavaType> _currentType;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800142
143 /*
144 /**********************************************************
145 /* Life-cycle
146 /**********************************************************
147 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800148
149 protected DeserializationContext(DeserializerFactory df) {
150 this(df, null);
151 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800152
Tatu Saloranta060ce112012-02-01 22:18:09 -0800153 protected DeserializationContext(DeserializerFactory df,
154 DeserializerCache cache)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800155 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800156 if (df == null) {
157 throw new IllegalArgumentException("Can not pass null DeserializerFactory");
158 }
159 _factory = df;
160 _cache = (cache == null) ? new DeserializerCache() : cache;
161
162 _featureFlags = 0;
163 _config = null;
164 _injectableValues = null;
165 _view = null;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700166 _attributes = null;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800167 }
168
169 protected DeserializationContext(DeserializationContext src,
170 DeserializerFactory factory)
171 {
172 _cache = src._cache;
173 _factory = factory;
174
175 _config = src._config;
176 _featureFlags = src._featureFlags;
177 _view = src._view;
178 _parser = src._parser;
179 _injectableValues = src._injectableValues;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700180 _attributes = src._attributes;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800181 }
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700182
183 /**
184 * Constructor used for creating actual per-call instances.
185 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800186 protected DeserializationContext(DeserializationContext src,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700187 DeserializationConfig config, JsonParser p,
Tatu Saloranta060ce112012-02-01 22:18:09 -0800188 InjectableValues injectableValues)
189 {
190 _cache = src._cache;
191 _factory = src._factory;
192
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800193 _config = config;
Tatu Salorantae3ae58e2012-01-28 23:08:16 -0800194 _featureFlags = config.getDeserializationFeatures();
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800195 _view = config.getActiveView();
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700196 _parser = p;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800197 _injectableValues = injectableValues;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700198 _attributes = config.getAttributes();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800199 }
Tatu Saloranta9439a312013-03-02 13:13:09 -0800200
Tatu Saloranta23328aa2014-10-28 22:38:15 -0700201 /**
202 * Copy-constructor for use with <code>copy()</code> by {@link ObjectMapper#copy()}
203 */
204 protected DeserializationContext(DeserializationContext src) {
205 _cache = new DeserializerCache();
206 _factory = src._factory;
207
208 _config = src._config;
209 _featureFlags = src._featureFlags;
210 _view = src._view;
211 _injectableValues = null;
212 }
213
Tatu Saloranta9439a312013-03-02 13:13:09 -0800214 /*
215 /**********************************************************
216 /* DatabindContext implementation
217 /**********************************************************
218 */
219
220 @Override
221 public DeserializationConfig getConfig() { return _config; }
222
223 @Override
224 public final Class<?> getActiveView() { return _view; }
225
226 @Override
Tatu Salorantaa5301ba2015-12-11 09:47:09 -0800227 public final boolean canOverrideAccessModifiers() {
228 return _config.canOverrideAccessModifiers();
229 }
230
231 @Override
232 public final boolean isEnabled(MapperFeature feature) {
233 return _config.isEnabled(feature);
234 }
235
236 @Override
237 public final JsonFormat.Value getDefaultPropertyFormat(Class<?> baseType) {
238 return _config.getDefaultPropertyFormat(baseType);
239 }
Tatu Saloranta4fdbb692016-04-16 21:41:14 -0700240
Tatu Salorantaa5301ba2015-12-11 09:47:09 -0800241 @Override
Tatu Saloranta9439a312013-03-02 13:13:09 -0800242 public final AnnotationIntrospector getAnnotationIntrospector() {
243 return _config.getAnnotationIntrospector();
244 }
245
246 @Override
247 public final TypeFactory getTypeFactory() {
248 return _config.getTypeFactory();
249 }
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700250
Cowtowncoder41bbc962015-06-19 17:16:08 -0700251 /**
252 * Method for accessing default Locale to use: convenience method for
253 *<pre>
254 * getConfig().getLocale();
255 *</pre>
256 */
257 @Override
258 public Locale getLocale() {
259 return _config.getLocale();
260 }
261
262 /**
263 * Method for accessing default TimeZone to use: convenience method for
264 *<pre>
265 * getConfig().getTimeZone();
266 *</pre>
267 */
268 @Override
269 public TimeZone getTimeZone() {
270 return _config.getTimeZone();
271 }
272
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700273 /*
274 /**********************************************************
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800275 /* Access to per-call state, like generic attributes (2.3+)
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700276 /**********************************************************
277 */
278
279 @Override
280 public Object getAttribute(Object key) {
281 return _attributes.getAttribute(key);
282 }
283
284 @Override
285 public DeserializationContext setAttribute(Object key, Object value)
286 {
287 _attributes = _attributes.withPerCallAttribute(key, value);
288 return this;
289 }
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800290
291 /**
292 * Accessor to {@link JavaType} of currently contextualized
293 * {@link ContextualDeserializer}, if any.
294 * This is sometimes useful for generic {@link JsonDeserializer}s that
295 * do not get passed (or do not retain) type information when being
296 * constructed: happens for example for deserializers constructed
297 * from annotations.
298 *
299 * @since 2.5
300 *
301 * @return Type of {@link ContextualDeserializer} being contextualized,
302 * if process is on-going; null if not.
303 */
304 public JavaType getContextualType() {
305 return (_currentType == null) ? null : _currentType.value();
306 }
307
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800308 /*
309 /**********************************************************
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800310 /* Public API, config setting accessors
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800311 /**********************************************************
312 */
313
314 /**
Dmitry Katsuboe70c66f2012-09-03 16:00:30 +0200315 * Method for getting current {@link DeserializerFactory}.
316 */
317 public DeserializerFactory getFactory() {
318 return _factory;
319 }
Tatu Saloranta9439a312013-03-02 13:13:09 -0800320
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800321 /**
322 * Convenience method for checking whether specified on/off
323 * feature is enabled
324 */
Tatu9610aff2012-02-02 11:30:08 -0800325 public final boolean isEnabled(DeserializationFeature feat) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800326 /* 03-Dec-2010, tatu: minor shortcut; since this is called quite often,
327 * let's use a local copy of feature settings:
328 */
329 return (_featureFlags & feat.getMask()) != 0;
330 }
331
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800332 /**
Cowtowncoder23e52ab2015-05-19 17:53:26 -0700333 * Bulk access method for getting the bit mask of all {@link DeserializationFeature}s
334 * that are enabled.
335 *
336 * @since 2.6
337 */
338 public final int getDeserializationFeatures() {
339 return _featureFlags;
340 }
341
342 /**
343 * Bulk access method for checking that all features specified by
Tatu Saloranta0ac36ba2013-08-21 18:08:51 -0700344 * mask are enabled.
345 *
346 * @since 2.3
347 */
348 public final boolean hasDeserializationFeatures(int featureMask) {
Cowtowncoder23e52ab2015-05-19 17:53:26 -0700349 return (_featureFlags & featureMask) == featureMask;
350 }
351
352 /**
353 * Bulk access method for checking that at least one of features specified by
354 * mask is enabled.
355 *
356 * @since 2.6
357 */
358 public final boolean hasSomeOfFeatures(int featureMask) {
359 return (_featureFlags & featureMask) != 0;
Tatu Saloranta0ac36ba2013-08-21 18:08:51 -0700360 }
361
362 /**
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800363 * Method for accessing the currently active parser.
364 * May be different from the outermost parser
365 * when content is buffered.
366 *<p>
367 * Use of this method is discouraged: if code has direct access
368 * to the active parser, that should be used instead.
369 */
370 public final JsonParser getParser() { return _parser; }
371
372 public final Object findInjectableValue(Object valueId,
373 BeanProperty forProperty, Object beanInstance)
374 {
375 if (_injectableValues == null) {
376 throw new IllegalStateException("No 'injectableValues' configured, can not inject value with id ["+valueId+"]");
377 }
378 return _injectableValues.findInjectableValue(valueId, this, forProperty, beanInstance);
379 }
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800380
Tatu Saloranta060ce112012-02-01 22:18:09 -0800381 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800382 * Convenience method for accessing the default Base64 encoding
383 * used for decoding base64 encoded binary content.
384 * Same as calling:
385 *<pre>
386 * getConfig().getBase64Variant();
387 *</pre>
388 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800389 public final Base64Variant getBase64Variant() {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800390 return _config.getBase64Variant();
391 }
392
Tatu Saloranta060ce112012-02-01 22:18:09 -0800393 /**
394 * Convenience method, functionally equivalent to:
395 *<pre>
396 * getConfig().getNodeFactory();
397 * </pre>
398 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800399 public final JsonNodeFactory getNodeFactory() {
400 return _config.getNodeFactory();
401 }
402
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800403 /*
404 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800405 /* Public API, pass-through to DeserializerCache
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800406 /**********************************************************
407 */
Tatuc3a73d02012-01-31 12:45:49 -0800408
Tatu Salorantaaf263c32013-10-24 16:18:50 -0700409 @Deprecated // since 2.3, use overloaded variant
410 public boolean hasValueDeserializerFor(JavaType type) {
411 return hasValueDeserializerFor(type, null);
412 }
413
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800414 /**
Tatu Saloranta060ce112012-02-01 22:18:09 -0800415 * Method for checking whether we could find a deserializer
416 * for given type.
Cowtowncodera2e27202014-11-25 17:07:52 -0800417 *
Tatu Salorantaaf263c32013-10-24 16:18:50 -0700418 * @param type
419 * @since 2.3
Tatu Saloranta060ce112012-02-01 22:18:09 -0800420 */
Tatu Salorantaaf263c32013-10-24 16:18:50 -0700421 public boolean hasValueDeserializerFor(JavaType type, AtomicReference<Throwable> cause) {
422 try {
423 return _cache.hasValueDeserializerFor(this, _factory, type);
424 } catch (JsonMappingException e) {
425 if (cause != null) {
426 cause.set(e);
427 }
428 } catch (RuntimeException e) {
429 if (cause == null) { // earlier behavior
430 throw e;
431 }
432 cause.set(e);
433 }
434 return false;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800435 }
436
Tatu Saloranta060ce112012-02-01 22:18:09 -0800437 /**
Tatuc3a73d02012-01-31 12:45:49 -0800438 * Method for finding a value deserializer, and creating a contextual
439 * version if necessary, for value reached via specified property.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800440 */
Tatuc3a73d02012-01-31 12:45:49 -0800441 @SuppressWarnings("unchecked")
442 public final JsonDeserializer<Object> findContextualValueDeserializer(JavaType type,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700443 BeanProperty prop) throws JsonMappingException
Tatuc3a73d02012-01-31 12:45:49 -0800444 {
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700445 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this, _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800446 if (deser != null) {
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800447 deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, prop, type);
Tatuc3a73d02012-01-31 12:45:49 -0800448 }
449 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800450 }
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700451
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800452 /**
Cowtowncodera2e27202014-11-25 17:07:52 -0800453 * Variant that will try to locate deserializer for current type, but without
454 * performing any contextualization (unlike {@link #findContextualValueDeserializer})
455 * or checking for need to create a {@link TypeDeserializer} (unlike
456 * {@link #findRootValueDeserializer(JavaType)}.
457 * This method is usually called from within {@link ResolvableDeserializer#resolve},
458 * and expectation is that caller then calls either
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800459 * {@link #handlePrimaryContextualization(JsonDeserializer, BeanProperty, JavaType)} or
460 * {@link #handleSecondaryContextualization(JsonDeserializer, BeanProperty, JavaType)} at a
Cowtowncodera2e27202014-11-25 17:07:52 -0800461 * later point, as necessary.
462 *
463 * @since 2.5
464 */
465 public final JsonDeserializer<Object> findNonContextualValueDeserializer(JavaType type)
466 throws JsonMappingException
467 {
468 return _cache.findValueDeserializer(this, _factory, type);
469 }
470
471 /**
Tatuc3a73d02012-01-31 12:45:49 -0800472 * Method for finding a deserializer for root-level value.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800473 */
Tatuc3a73d02012-01-31 12:45:49 -0800474 @SuppressWarnings("unchecked")
Tatu Saloranta9b9d0432012-01-30 09:20:26 -0800475 public final JsonDeserializer<Object> findRootValueDeserializer(JavaType type)
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700476 throws JsonMappingException
Tatuc3a73d02012-01-31 12:45:49 -0800477 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800478 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this,
479 _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800480 if (deser == null) { // can this occur?
481 return null;
482 }
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800483 deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, null, type);
Tatuc3a73d02012-01-31 12:45:49 -0800484 TypeDeserializer typeDeser = _factory.findTypeDeserializer(_config, type);
485 if (typeDeser != null) {
486 // important: contextualize to indicate this is for root value
487 typeDeser = typeDeser.forProperty(null);
488 return new TypeWrappedDeserializer(typeDeser, deser);
489 }
490 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800491 }
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800492
493 /**
494 * Convenience method, functionally same as:
495 *<pre>
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700496 * getDeserializerProvider().findKeyDeserializer(getConfig(), prop.getType(), prop);
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800497 *</pre>
498 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800499 public final KeyDeserializer findKeyDeserializer(JavaType keyType,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700500 BeanProperty prop) throws JsonMappingException {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800501 KeyDeserializer kd = _cache.findKeyDeserializer(this,
502 _factory, keyType);
Tatud0bb3152012-01-31 13:04:06 -0800503 // Second: contextualize?
504 if (kd instanceof ContextualKeyDeserializer) {
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700505 kd = ((ContextualKeyDeserializer) kd).createContextual(this, prop);
Tatud0bb3152012-01-31 13:04:06 -0800506 }
507 return kd;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800508 }
509
Tatub37ff332012-01-24 16:19:36 -0800510 /*
511 /**********************************************************
Tatu Saloranta34a8adf2012-02-08 22:07:36 -0800512 /* Public API, ObjectId handling
513 /**********************************************************
514 */
515
516 /**
517 * Method called to find and return entry corresponding to given
518 * Object Id: will add an entry if necessary, and never returns null
519 */
Pascal GĂ©linas184cae32014-02-05 17:35:56 -0500520 public abstract ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator, ObjectIdResolver resolver);
521
Tatu Saloranta301ea2d2014-03-16 22:26:12 -0700522 @Deprecated // since 2.4
Pascal GĂ©linas184cae32014-02-05 17:35:56 -0500523 public abstract ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator);
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800524
Pascal GĂ©linas096e02b2013-12-18 17:21:42 -0500525 /**
526 * Method called to ensure that every object id encounter during processing
527 * are resolved.
528 *
529 * @throws UnresolvedForwardReference
530 */
531 public abstract void checkUnresolvedObjectId()
532 throws UnresolvedForwardReference;
533
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800534 /*
535 /**********************************************************
536 /* Public API, type handling
537 /**********************************************************
538 */
539
540 /**
541 * Convenience method, functionally equivalent to:
542 *<pre>
543 * getConfig().constructType(cls);
544 * </pre>
545 */
546 public final JavaType constructType(Class<?> cls) {
547 return _config.constructType(cls);
548 }
549
550 /**
Cowtowncodera5bd0a22015-06-25 15:27:07 -0700551 * Helper method that is to be used when resolving basic class name into
552 * Class instance, the reason being that it may be necessary to work around
553 * various ClassLoader limitations, as well as to handle primitive type
554 * signatures.
555 *
556 * @since 2.6
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800557 */
558 public Class<?> findClass(String className) throws ClassNotFoundException
559 {
560 // By default, delegate to ClassUtil: can be overridden with custom handling
Cowtowncodera5bd0a22015-06-25 15:27:07 -0700561 return getTypeFactory().findClass(className);
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800562 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800563
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800564 /*
565 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800566 /* Public API, helper object recycling
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800567 /**********************************************************
568 */
569
570 /**
571 * Method that can be used to get access to a reusable ObjectBuffer,
572 * useful for efficiently constructing Object arrays and Lists.
573 * Note that leased buffers should be returned once deserializer
574 * is done, to allow for reuse during same round of deserialization.
575 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800576 public final ObjectBuffer leaseObjectBuffer()
577 {
578 ObjectBuffer buf = _objectBuffer;
579 if (buf == null) {
580 buf = new ObjectBuffer();
581 } else {
582 _objectBuffer = null;
583 }
584 return buf;
585 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800586
587 /**
588 * Method to call to return object buffer previously leased with
589 * {@link #leaseObjectBuffer}.
590 *
591 * @param buf Returned object buffer
592 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800593 public final void returnObjectBuffer(ObjectBuffer buf)
594 {
595 /* Already have a reusable buffer? Let's retain bigger one
596 * (or if equal, favor newer one, shorter life-cycle)
597 */
598 if (_objectBuffer == null
599 || buf.initialCapacity() >= _objectBuffer.initialCapacity()) {
600 _objectBuffer = buf;
601 }
602 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800603
604 /**
605 * Method for accessing object useful for building arrays of
606 * primitive types (such as int[]).
607 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800608 public final ArrayBuilders getArrayBuilders()
609 {
610 if (_arrayBuilders == null) {
611 _arrayBuilders = new ArrayBuilders();
612 }
613 return _arrayBuilders;
614 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800615
616 /*
617 /**********************************************************
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700618 /* Extended API: handler instantiation
619 /**********************************************************
620 */
621
622 public abstract JsonDeserializer<Object> deserializerInstance(Annotated annotated,
623 Object deserDef)
624 throws JsonMappingException;
625
626 public abstract KeyDeserializer keyDeserializerInstance(Annotated annotated,
627 Object deserDef)
628 throws JsonMappingException;
629
630 /*
631 /**********************************************************
632 /* Extended API: resolving contextual deserializers; called
633 /* by structured deserializers for their value/component
634 /* deserializers
635 /**********************************************************
636 */
637
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700638 /**
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700639 * Method called for primary property deserializers (ones
Tatu Saloranta59fe29c2013-09-05 22:37:06 -0700640 * directly created to deserialize values of a POJO property),
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700641 * to handle details of resolving
642 * {@link ContextualDeserializer} with given property context.
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700643 *
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700644 * @param prop Property for which the given primary deserializer is used; never null.
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700645 *
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800646 * @since 2.5
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700647 */
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700648 public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> deser,
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800649 BeanProperty prop, JavaType type)
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700650 throws JsonMappingException
651 {
Cowtowncodera2e27202014-11-25 17:07:52 -0800652 if (deser instanceof ContextualDeserializer) {
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800653 _currentType = new LinkedNode<JavaType>(type, _currentType);
654 try {
655 deser = ((ContextualDeserializer) deser).createContextual(this, prop);
656 } finally {
657 _currentType = _currentType.next();
658 }
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700659 }
660 return deser;
661 }
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700662
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700663 /**
664 * Method called for secondary property deserializers (ones
665 * NOT directly created to deal with an annotatable POJO property,
666 * but instead created as a component -- such as value deserializers
667 * for structured types, or deserializers for root values)
668 * to handle details of resolving
669 * {@link ContextualDeserializer} with given property context.
Tatu Saloranta59fe29c2013-09-05 22:37:06 -0700670 * Given that these deserializers are not directly related to given property
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700671 * (or, in case of root value property, to any property), annotations
672 * accessible may or may not be relevant.
673 *
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700674 * @param prop Property for which deserializer is used, if any; null
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700675 * when deserializing root values
676 *
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800677 * @since 2.5
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700678 */
679 public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?> deser,
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800680 BeanProperty prop, JavaType type)
681 throws JsonMappingException
682 {
683 if (deser instanceof ContextualDeserializer) {
684 _currentType = new LinkedNode<JavaType>(type, _currentType);
685 try {
686 deser = ((ContextualDeserializer) deser).createContextual(this, prop);
687 } finally {
688 _currentType = _currentType.next();
689 }
690 }
691 return deser;
692 }
693
Cowtowncoder36864212015-03-16 14:23:22 -0700694 @Deprecated // since 2.5; remove from 2.7
695 public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> deser, BeanProperty prop) throws JsonMappingException {
696 return handlePrimaryContextualization(deser, prop, TypeFactory.unknownType());
697 }
698
699 @Deprecated // since 2.5; remove from 2.7
700 public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?> deser, BeanProperty prop) throws JsonMappingException {
701 if (deser instanceof ContextualDeserializer) {
702 deser = ((ContextualDeserializer) deser).createContextual(this, prop);
703 }
704 return deser;
705 }
706
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700707 /*
708 /**********************************************************
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800709 /* Parsing methods that may use reusable/-cyclable objects
710 /**********************************************************
711 */
712
713 /**
714 * Convenience method for parsing a Date from given String, using
715 * currently configured date format (accessed using
716 * {@link DeserializationConfig#getDateFormat()}).
717 *<p>
718 * Implementation will handle thread-safety issues related to
719 * date formats such that first time this method is called,
720 * date format is cloned, and cloned instance will be retained
721 * for use during this deserialization round.
722 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700723 public Date parseDate(String dateStr) throws IllegalArgumentException
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800724 {
725 try {
Tatu Salorantaef00ac62013-11-03 09:56:39 -0800726 DateFormat df = getDateFormat();
727 return df.parse(dateStr);
Tatu Salorantaaa512742012-02-22 22:51:33 -0800728 } catch (ParseException e) {
Tatu Saloranta8e9d4b22015-05-01 21:26:32 -0700729 throw new IllegalArgumentException(String.format(
730 "Failed to parse Date value '%s': %s", dateStr, e.getMessage()));
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800731 }
732 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800733
734 /**
735 * Convenience method for constructing Calendar instance set
736 * to specified time, to be modified and used by caller.
737 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700738 public Calendar constructCalendar(Date d) {
739 // 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 -0800740 Calendar c = Calendar.getInstance(getTimeZone());
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800741 c.setTime(d);
742 return c;
743 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800744
745 /*
746 /**********************************************************
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700747 /* Convenience methods for reading parsed values
748 /**********************************************************
749 */
750
751 /**
752 * Convenience method that may be used by composite or container deserializers,
753 * for reading one-off values contained (for sequences, it is more efficient
754 * to actually fetch deserializer once for the whole collection).
755 *<p>
756 * NOTE: when deserializing values of properties contained in composite types,
757 * rather use {@link #readPropertyValue(JsonParser, BeanProperty, Class)};
758 * this method does not allow use of contextual annotations.
759 *
760 * @since 2.4
761 */
762 public <T> T readValue(JsonParser p, Class<T> type) throws IOException {
763 return readValue(p, getTypeFactory().constructType(type));
764 }
765
766 /**
767 * @since 2.4
768 */
769 @SuppressWarnings("unchecked")
770 public <T> T readValue(JsonParser p, JavaType type) throws IOException {
771 JsonDeserializer<Object> deser = findRootValueDeserializer(type);
772 if (deser == null) {
Tatu Saloranta5ae6e4b2015-10-05 21:49:01 -0700773 throw mappingException("Could not find JsonDeserializer for type %s", type);
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700774 }
775 return (T) deser.deserialize(p, this);
776 }
777
778 /**
779 * Convenience method that may be used by composite or container deserializers,
780 * for reading one-off values for the composite type, taking into account
781 * annotations that the property (passed to this method -- usually property that
782 * has custom serializer that called this method) has.
783 *
784 * @since 2.4
785 */
786 public <T> T readPropertyValue(JsonParser p, BeanProperty prop, Class<T> type) throws IOException {
787 return readPropertyValue(p, prop, getTypeFactory().constructType(type));
788 }
789
790 /**
791 * @since 2.4
792 */
793 @SuppressWarnings("unchecked")
794 public <T> T readPropertyValue(JsonParser p, BeanProperty prop, JavaType type) throws IOException {
795 JsonDeserializer<Object> deser = findContextualValueDeserializer(type, prop);
796 if (deser == null) {
Tatu Saloranta5ae6e4b2015-10-05 21:49:01 -0700797 String propName = (prop == null) ? "NULL" : ("'"+prop.getName()+"'");
798 throw mappingException("Could not find JsonDeserializer for type %s (via property %s)",
799 type, propName);
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700800 }
801 return (T) deser.deserialize(p, this);
802 }
Tatu Saloranta5ae6e4b2015-10-05 21:49:01 -0700803
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700804 /*
805 /**********************************************************
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700806 /* Methods for problem handling
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800807 /**********************************************************
808 */
809
810 /**
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700811 * Method that deserializers should call if they encounter an unrecognized
812 * property (and once that is not explicitly designed as ignorable), to
813 * inform possibly configured {@link DeserializationProblemHandler}s and
814 * let it handle the problem.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800815 *
816 * @return True if there was a configured problem handler that was able to handle the
Tatu Saloranta0e3b3832012-01-22 22:08:20 -0800817 * problem
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800818 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700819 public boolean handleUnknownProperty(JsonParser p, JsonDeserializer<?> deser,
Tatu Saloranta060ce112012-02-01 22:18:09 -0800820 Object instanceOrClass, String propName)
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700821 throws IOException
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800822 {
823 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700824 while (h != null) {
825 // Can bail out if it's handled
826 if (h.value().handleUnknownProperty(this, p, deser, instanceOrClass, propName)) {
827 return true;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800828 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700829 h = h.next();
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800830 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700831 // Nope, not handled. Potentially that's a problem...
832 if (!isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
833 p.skipChildren();
834 return true;
835 }
836 // Do we know properties that are expected instead?
837 Collection<Object> propIds = (deser == null) ? null : deser.getKnownPropertyNames();
838 throw UnrecognizedPropertyException.from(_parser,
839 instanceOrClass, propName, propIds);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800840 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800841
842 /**
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700843 * Method that deserializers should call if they encounter a String value
844 * that can not be converted to expected key of a {@link java.util.Map}
845 * valued property.
846 * Default implementation will try to call {@link DeserializationProblemHandler#handleWeirdNumberValue}
847 * on configured handlers, if any, to allow for recovery; if recovery does not
848 * succeed, will throw {@link InvalidFormatException} with given message.
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700849 *
850 * @param keyClass Expected type for key
851 * @param keyValue String value from which to deserialize key
852 * @param msg Error message template caller wants to use if exception is to be thrown
853 * @param msgArgs Optional arguments to use for message, if any
854 *
855 * @return Key value to use
856 *
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700857 * @throws IOException To indicate unrecoverable problem, usually based on <code>msg</code>
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700858 *
859 * @since 2.8
860 */
861 public Object handleWeirdKey(Class<?> keyClass, String keyValue,
862 String msg, Object... msgArgs)
863 throws IOException
864 {
865 // but if not handled, just throw exception
866 if (msgArgs.length > 0) {
867 msg = String.format(msg, msgArgs);
868 }
869 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700870 while (h != null) {
871 // Can bail out if it's handled
872 Object key = h.value().handleWeirdKey(this, keyClass, keyValue, msg);
Tatu Saloranta2d318f62016-05-10 21:58:00 -0700873 if (key != DeserializationProblemHandler.NOT_HANDLED) {
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700874 return key;
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700875 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700876 h = h.next();
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700877 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700878 throw weirdKeyException(keyClass, keyValue, msg);
879 }
880
881 /**
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -0700882 * Method that deserializers should call if they encounter a String value
883 * that can not be converted to target property type, in cases where some
884 * String values could be acceptable (either with different settings,
885 * or different value).
886 * Default implementation will try to call {@link DeserializationProblemHandler#handleWeirdStringValue}
887 * on configured handlers, if any, to allow for recovery; if recovery does not
888 * succeed, will throw {@link InvalidFormatException} with given message.
889 *
890 * @param targetClass Type of property into which incoming number should be converted
891 * @param value String value from which to deserialize property value
892 * @param msg Error message template caller wants to use if exception is to be thrown
893 * @param msgArgs Optional arguments to use for message, if any
894 *
895 * @return Property value to use
896 *
897 * @throws IOException To indicate unrecoverable problem, usually based on <code>msg</code>
898 *
899 * @since 2.8
900 */
901 public Object handleWeirdStringValue(Class<?> targetClass, String value,
902 String msg, Object... msgArgs)
903 throws IOException
904 {
905 // but if not handled, just throw exception
906 if (msgArgs.length > 0) {
907 msg = String.format(msg, msgArgs);
908 }
909 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
910 while (h != null) {
911 // Can bail out if it's handled
912 Object key = h.value().handleWeirdStringValue(this, targetClass, value, msg);
913 if (key != DeserializationProblemHandler.NOT_HANDLED) {
914 return key;
915 }
916 h = h.next();
917 }
918 throw weirdStringException(value, targetClass, msg);
919 }
920
921 /**
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700922 * Method that deserializers should call if they encounter a numeric value
923 * that can not be converted to target property type, in cases where some
924 * numeric values could be acceptable (either with different settings,
925 * or different numeric value).
926 * Default implementation will try to call {@link DeserializationProblemHandler#handleWeirdNumberValue}
927 * on configured handlers, if any, to allow for recovery; if recovery does not
928 * succeed, will throw {@link InvalidFormatException} with given message.
929 *
930 * @param targetClass Type of property into which incoming number should be converted
931 * @param value Number value from which to deserialize property value
932 * @param msg Error message template caller wants to use if exception is to be thrown
933 * @param msgArgs Optional arguments to use for message, if any
934 *
935 * @return Property value to use
936 *
937 * @throws IOException To indicate unrecoverable problem, usually based on <code>msg</code>
938 *
939 * @since 2.8
940 */
941 public Object handleWeirdNumberValue(Class<?> targetClass, Number value,
942 String msg, Object... msgArgs)
943 throws IOException
944 {
945 // but if not handled, just throw exception
946 if (msgArgs.length > 0) {
947 msg = String.format(msg, msgArgs);
948 }
949 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
950 while (h != null) {
951 // Can bail out if it's handled
952 Object key = h.value().handleWeirdNumberValue(this, targetClass, value, msg);
953 if (key != DeserializationProblemHandler.NOT_HANDLED) {
954 return key;
955 }
956 h = h.next();
957 }
958 throw weirdNumberException(value, targetClass, msg);
959 }
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -0700960
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700961 /**
Tatu Saloranta609a0f82016-05-18 20:17:10 -0700962 * Method that deserializers should call if they encounter a type id
963 * (for polymorphic deserialization) that can not be resolved to an
964 * actual type; usually since there is no mapping defined.
965 * Default implementation will try to call {@link DeserializationProblemHandler#handleUnknownTypeId}
966 * on configured handlers, if any, to allow for recovery; if recovery does not
967 * succeed, will throw exception constructed with {@link #unknownTypeIdException}.
968 *
969 * @param baseType Base type from which resolution starts
970 * @param id Type id that could not be converted
971 * @param extraDesc Additional problem description to add to default exception message,
972 * if resolution fails.
973 *
974 * @return {@link JavaType} that id resolves to
975 *
976 * @throws IOException To indicate unrecoverable problem, if resolution can not
977 * be made to work
978 *
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700979 * @since 2.8
980 */
981 public JavaType handleUnknownTypeId(JavaType baseType, String id,
982 String extraDesc) throws IOException
983 {
984 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
985 while (h != null) {
986 // Can bail out if it's handled
987 JavaType type = h.value().handleUnknownTypeId(this, baseType, id, extraDesc);
988 if (type != null) {
989 if (type.hasRawClass(Void.class)) {
990 return null;
991 }
Tatu Salorantaf2c40cb2016-05-10 20:21:32 -0700992 // But ensure there's type compatibility
993 if (type.isTypeOrSubTypeOf(baseType.getRawClass())) {
994 return type;
995 }
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -0700996 throw unknownTypeIdException(baseType, id,
Tatu Salorantaf2c40cb2016-05-10 20:21:32 -0700997 "problem handler tried to resolve into non-subtype: "+type);
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700998 }
999 h = h.next();
1000 }
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001001 throw unknownTypeIdException(baseType, id, extraDesc);
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001002 }
1003
Tatu Saloranta609a0f82016-05-18 20:17:10 -07001004 /**
1005 * Method that deserializers should call if they fail to instantiate value
1006 * due to an exception that was thrown by constructor (or other mechanism used
1007 * to create instances).
1008 * Default implementation will try to call {@link DeserializationProblemHandler#handleInstantiationProblem}
1009 * on configured handlers, if any, to allow for recovery; if recovery does not
1010 * succeed, will throw exception constructed with {@link #instantiationException}.
1011 *
1012 * @param instClass Type that was to be instantiated
1013 * @param argument (optional) Argument that was passed to constructor or equivalent
1014 * instantiator; often a {@link java.lang.String}.
1015 * @param t Exception that caused failure
1016 *
1017 * @return Object that should be constructed, if any; has to be of type <code>instClass</code>
1018 *
1019 * @since 2.8
1020 */
1021 public Object handleInstantiationProblem(Class<?> instClass, Object argument,
1022 Throwable t)
1023 throws IOException
1024 {
1025 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
1026 while (h != null) {
1027 // Can bail out if it's handled
1028 Object key = h.value().handleInstantiationProblem(this, instClass, argument, t);
1029 if (key != DeserializationProblemHandler.NOT_HANDLED) {
1030 return key;
1031 }
1032 h = h.next();
1033 }
1034 // 18-May-2016, tatu: Only wrap if not already a valid type to throw
1035 if (t instanceof IOException) {
1036 throw (IOException) t;
1037 }
1038 throw instantiationException(instClass, t);
1039 }
1040
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001041 /*
1042 /**********************************************************
1043 /* Methods for problem reporting
1044 /**********************************************************
1045 */
1046
1047 /**
1048 * Helper method for reporting a problem with unhandled unknown property.
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -08001049 *
1050 * @param instanceOrClass Either value being populated (if one has been
1051 * instantiated), or Class that indicates type that would be (or
1052 * have been) instantiated
Tatu Saloranta05fce932012-03-19 17:14:05 -07001053 * @param deser Deserializer that had the problem, if called by deserializer
1054 * (or on behalf of one)
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -07001055 *
1056 * @deprecated Since 2.8 call {@link #handleUnknownProperty} instead
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -08001057 */
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -07001058 @Deprecated
Tatu Saloranta05fce932012-03-19 17:14:05 -07001059 public void reportUnknownProperty(Object instanceOrClass, String fieldName,
1060 JsonDeserializer<?> deser)
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -08001061 throws JsonMappingException
1062 {
Tatu Saloranta05fce932012-03-19 17:14:05 -07001063 if (!isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
1064 return;
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -08001065 }
Tatu Saloranta05fce932012-03-19 17:14:05 -07001066 // Do we know properties that are expected instead?
1067 Collection<Object> propIds = (deser == null) ? null : deser.getKnownPropertyNames();
1068 throw UnrecognizedPropertyException.from(_parser,
1069 instanceOrClass, fieldName, propIds);
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -08001070 }
Tatu Saloranta8c3eb032016-04-20 22:52:38 -07001071
1072 /**
1073 * @since 2.8
1074 */
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001075 public void reportInstantiationException(Class<?> instClass,
Tatu Saloranta8c3eb032016-04-20 22:52:38 -07001076 String msg, Object... msgArgs)
1077 throws JsonMappingException
1078 {
1079 if (msgArgs.length > 0) {
1080 msg = String.format(msg, msgArgs);
1081 }
1082 throw instantiationException(instClass, msg);
1083 }
1084
1085 /**
1086 * @since 2.8
1087 */
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001088 public JsonMappingException reportWrongTokenException(JsonParser p,
Tatu Saloranta8c3eb032016-04-20 22:52:38 -07001089 JsonToken expToken, String msg, Object... msgArgs)
1090 throws JsonMappingException
1091 {
1092 if (msgArgs.length > 0) {
1093 msg = String.format(msg, msgArgs);
1094 }
1095 throw wrongTokenException(p, expToken, msg);
1096 }
1097
1098 /**
1099 * @since 2.8
1100 */
Tatu Saloranta48437a72016-05-09 22:36:15 -07001101 public void reportMappingException(String msg, Object... msgArgs)
1102 throws JsonMappingException
1103 {
1104 if (msgArgs.length > 0) {
1105 msg = String.format(msg, msgArgs);
1106 }
1107 throw mappingException(msg);
1108 }
1109
1110 /**
1111 * @since 2.8
1112 */
1113 public void reportMappingException(Class<?> targetClass, JsonToken t) throws JsonMappingException {
1114 throw mappingException(targetClass, t);
1115 }
1116
1117 /**
1118 * @since 2.8
1119 */
1120 public void reportMappingException(Class<?> targetClass) throws JsonMappingException {
1121 throw mappingException(targetClass);
1122 }
1123
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -08001124 /*
1125 /**********************************************************
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001126 /* Methods for constructing exceptions, "untyped"
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -08001127 /**********************************************************
1128 */
1129
1130 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001131 * Helper method for constructing generic mapping exception for specified type
Tatu Salorantabd3c3122016-05-10 19:33:23 -07001132 *
1133 * @deprecated Since 2.8 use {@link #reportMappingException(Class)} instead
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001134 */
Tatu Salorantabd3c3122016-05-10 19:33:23 -07001135 @Deprecated
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001136 public JsonMappingException mappingException(Class<?> targetClass) {
1137 return mappingException(targetClass, _parser.getCurrentToken());
1138 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001139
Tatu Saloranta48437a72016-05-09 22:36:15 -07001140 /**
Tatu Salorantabd3c3122016-05-10 19:33:23 -07001141 * @deprecated Since 2.8 use {@link #reportMappingException(Class, JsonToken)} instead
Tatu Saloranta48437a72016-05-09 22:36:15 -07001142 */
1143 @Deprecated
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -08001144 public JsonMappingException mappingException(Class<?> targetClass, JsonToken token) {
Tatu Saloranta8e9d4b22015-05-01 21:26:32 -07001145 return JsonMappingException.from(_parser,
1146 String.format("Can not deserialize instance of %s out of %s token",
1147 _calcName(targetClass), token));
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001148 }
Tatu Saloranta48437a72016-05-09 22:36:15 -07001149
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001150 /**
Tatu Saloranta48437a72016-05-09 22:36:15 -07001151 * @deprecated Since 2.8 use {@link #reportMappingException(String, Object...)} instead
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001152 */
Tatu Saloranta48437a72016-05-09 22:36:15 -07001153 @Deprecated
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -08001154 public JsonMappingException mappingException(String message) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001155 return JsonMappingException.from(getParser(), message);
1156 }
Cowtowncoder5dfc92c2015-07-08 17:21:20 -07001157
1158 /**
1159 * Helper method for constructing generic mapping exception with specified
1160 * message and current location information
1161 *
1162 * @since 2.6
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001163 *
1164 * @deprecated Since 2.8 use {@link #reportMappingException(String, Object...)} instead
Cowtowncoder5dfc92c2015-07-08 17:21:20 -07001165 */
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001166 @Deprecated
Cowtowncoder5dfc92c2015-07-08 17:21:20 -07001167 public JsonMappingException mappingException(String msgTemplate, Object... args) {
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001168 if (args != null && args.length > 0) {
1169 msgTemplate = String.format(msgTemplate, args);
1170 }
1171 return JsonMappingException.from(getParser(), msgTemplate);
Cowtowncoder5dfc92c2015-07-08 17:21:20 -07001172 }
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001173
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001174 /*
1175 /**********************************************************
1176 /* Methods for constructing semantic exceptions; usually not
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001177 /* to be called directly, call `handleXxx()` instead
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001178 /**********************************************************
1179 */
1180
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001181 /**
Tatu Saloranta98dd0912016-05-15 23:13:44 -07001182 * Helper method for constructing {@link JsonMappingException} to indicated
1183 * that the token encountered was of type different than what <b>should</b>
1184 * be seen at that position, usually within a sequence of expected tokens.
1185 * Note that most of the time this method should NOT be directly called;
1186 * instead, {@link #reportWrongTokenException} should be called and will
1187 * call this method as necessary.
1188 */
1189 public JsonMappingException wrongTokenException(JsonParser p, JsonToken expToken,
1190 String msg0)
1191 {
1192 String msg = String.format("Unexpected token (%s), expected %s",
1193 p.getCurrentToken(), expToken);
1194 if (msg0 != null) {
1195 msg = msg + ": "+msg0;
1196 }
1197 return JsonMappingException.from(p, msg);
1198 }
1199
1200 /**
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001201 * Helper method for constructing exception to indicate that given JSON
1202 * Object field name was not in format to be able to deserialize specified
1203 * key type.
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001204 * Note that most of the time this method should NOT be called; instead,
1205 * {@link #handleWeirdKey} should be called which will call this method
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001206 * if necessary.
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001207 */
1208 public JsonMappingException weirdKeyException(Class<?> keyClass, String keyValue,
1209 String msg) {
1210 return InvalidFormatException.from(_parser,
1211 String.format("Can not deserialize Map key of type %s from String %s: %s",
1212 keyClass.getName(), _quotedString(keyValue), msg),
1213 keyValue, keyClass);
1214 }
1215
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001216 /**
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001217 * Helper method for constructing exception to indicate that input JSON
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001218 * String was not suitable for deserializing into given target type.
1219 * Note that most of the time this method should NOT be called; instead,
1220 * {@link #handleWeirdStringValue} should be called which will call this method
1221 * if necessary.
1222 *
1223 * @param value String value from input being deserialized
1224 * @param instClass Type that String should be deserialized into
1225 * @param msg Message that describes specific problem
1226 *
1227 * @since 2.1
1228 */
1229 public JsonMappingException weirdStringException(String value, Class<?> instClass,
1230 String msg) {
1231 return InvalidFormatException.from(_parser,
1232 String.format("Can not deserialize value of type %s from String %s: %s",
1233 instClass.getName(), _quotedString(value), msg),
1234 value, instClass);
1235 }
1236
1237 /**
1238 * Helper method for constructing exception to indicate that input JSON
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001239 * Number was not suitable for deserializing into given target type.
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001240 * Note that most of the time this method should NOT be called; instead,
1241 * {@link #handleWeirdNumberValue} should be called which will call this method
1242 * if necessary.
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001243 */
1244 public JsonMappingException weirdNumberException(Number value, Class<?> instClass,
1245 String msg) {
1246 return InvalidFormatException.from(_parser,
1247 String.format("Can not deserialize value of type %s from number %s: %s",
1248 instClass.getName(), String.valueOf(value), msg),
1249 value, instClass);
1250 }
Tatu Salorantab1041d02016-05-19 08:22:50 -07001251
1252 /**
1253 * Helper method for constructing instantiation exception for specified type,
1254 * to indicate problem with physically constructing instance of
1255 * specified class (missing constructor, exception from constructor)
1256 *<p>
1257 * Note that most of the time this method should NOT be called; instead,
1258 * {@link #handleInstantiationProblem} should be called which will call this method
1259 * if necessary.
1260 */
1261 public JsonMappingException instantiationException(Class<?> instClass, Throwable t) {
1262 return JsonMappingException.from(_parser,
1263 String.format("Can not construct instance of %s, problem: %s",
1264 instClass.getName(), t.getMessage()), t);
1265 }
1266
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001267 /**
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001268 * Helper method for constructing exception to indicate that given type id
1269 * could not be resolved to a valid subtype of specified base type, during
1270 * polymorphic deserialization.
Tatu Salorantab1041d02016-05-19 08:22:50 -07001271 *<p>
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001272 * Note that most of the time this method should NOT be called; instead,
1273 * {@link #handleUnknownTypeId} should be called which will call this method
1274 * if necessary.
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001275 */
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001276 public JsonMappingException unknownTypeIdException(JavaType baseType, String typeId,
1277 String extraDesc) {
1278 String msg = String.format("Could not resolve type id '%s' into a subtype of %s",
1279 typeId, baseType);
1280 if (extraDesc != null) {
1281 msg = msg + ": "+extraDesc;
1282 }
1283 return InvalidTypeIdException.from(_parser, msg, baseType, typeId);
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001284 }
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001285
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001286 /*
1287 /**********************************************************
Tatu Salorantab1041d02016-05-19 08:22:50 -07001288 /* Methods for constructing semantic exceptions
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001289 /**********************************************************
1290 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001291
Tatu Saloranta7a4193f2016-05-05 12:55:05 -07001292 /**
Tatu Salorantab1041d02016-05-19 08:22:50 -07001293 * @deprecated Since 2.8 use {@link #reportInstantiationException} instead
1294 */
Tatu Saloranta7a4193f2016-05-05 12:55:05 -07001295 @Deprecated
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -08001296 public JsonMappingException instantiationException(Class<?> instClass, String msg) {
Tatu Saloranta8e9d4b22015-05-01 21:26:32 -07001297 return JsonMappingException.from(_parser,
Tatu Saloranta4b9bfd02016-05-09 20:47:06 -07001298 String.format("Can not construct instance of %s: %s",
1299 instClass.getName(), msg));
Tatu Salorantadd348562012-07-18 17:25:02 -07001300 }
1301
1302 /**
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001303 * @since 2.5
Tatu Saloranta2ffca932016-05-05 12:23:14 -07001304 *
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -07001305 * @deprecated Since 2.8 use {@link #handleUnknownTypeId} instead
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001306 */
Tatu Saloranta2ffca932016-05-05 12:23:14 -07001307 @Deprecated
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001308 public JsonMappingException unknownTypeException(JavaType type, String id,
1309 String extraDesc) {
Tatu Saloranta8c3eb032016-04-20 22:52:38 -07001310 String msg = String.format("Could not resolve type id '%s' into a subtype of %s",
1311 id, type);
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001312 if (extraDesc != null) {
1313 msg = msg + ": "+extraDesc;
1314 }
1315 return JsonMappingException.from(_parser, msg);
1316 }
1317
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001318 /**
1319 * Helper method for constructing exception to indicate that end-of-input was
1320 * reached while still expecting more tokens to deserialize value of specified type.
1321 *
1322 * @deprecated Since 2.8; currently no way to catch EOF at databind level
1323 */
1324 @Deprecated
1325 public JsonMappingException endOfInputException(Class<?> instClass) {
1326 return JsonMappingException.from(_parser, "Unexpected end-of-input when trying to deserialize a "
1327 +instClass.getName());
1328 }
1329
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001330 /*
1331 /**********************************************************
1332 /* Overridable internal methods
1333 /**********************************************************
1334 */
1335
1336 protected DateFormat getDateFormat()
1337 {
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -08001338 if (_dateFormat != null) {
1339 return _dateFormat;
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001340 }
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -08001341 /* 24-Feb-2012, tatu: At this point, all timezone configuration
Cowtowncoder8d0d6e42015-01-22 15:36:13 -08001342 * should have occurred, with respect to default dateformat
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -08001343 * and timezone configuration. But we still better clone
1344 * an instance as formatters may be stateful.
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -08001345 */
1346 DateFormat df = _config.getDateFormat();
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -08001347 _dateFormat = df = (DateFormat) df.clone();
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -08001348 return df;
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001349 }
1350
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -08001351 protected String determineClassName(Object instance) {
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001352 return ClassUtil.getClassDescription(instance);
1353 }
1354
1355 /*
1356 /**********************************************************
1357 /* Other internal methods
1358 /**********************************************************
1359 */
1360
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -08001361 protected String _calcName(Class<?> cls) {
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001362 if (cls.isArray()) {
1363 return _calcName(cls.getComponentType())+"[]";
1364 }
1365 return cls.getName();
1366 }
Tatu Saloranta7a3b0b12016-02-09 16:52:28 -08001367
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -08001368 protected String _valueDesc() {
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001369 try {
1370 return _desc(_parser.getText());
1371 } catch (Exception e) {
1372 return "[N/A]";
1373 }
1374 }
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -08001375
1376 protected String _desc(String desc) {
Tatu Saloranta20a67f72015-11-21 14:17:45 -08001377 if (desc == null) {
1378 return "[N/A]";
1379 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001380 // !!! should we quote it? (in case there are control chars, linefeeds)
1381 if (desc.length() > MAX_ERROR_STR_LEN) {
1382 desc = desc.substring(0, MAX_ERROR_STR_LEN) + "]...[" + desc.substring(desc.length() - MAX_ERROR_STR_LEN);
1383 }
1384 return desc;
1385 }
Tatu Saloranta20a67f72015-11-21 14:17:45 -08001386
1387 // @since 2.7
1388 protected String _quotedString(String desc) {
1389 if (desc == null) {
1390 return "[N/A]";
1391 }
1392 // !!! should we quote it? (in case there are control chars, linefeeds)
1393 if (desc.length() > MAX_ERROR_STR_LEN) {
1394 return String.format("\"%s]...[%s\"",
1395 desc.substring(0, MAX_ERROR_STR_LEN),
1396 desc.substring(desc.length() - MAX_ERROR_STR_LEN));
1397 }
1398 return "\"" + desc + "\"";
1399 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001400}