blob: 27d73dc197eaecc3e3dfd704c17c875eab5afaef [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 Salorantaa0bd1592016-11-25 18:49:52 -080020import com.fasterxml.jackson.databind.exc.MismatchedInputException;
Tatu Salorantac1478ac2016-09-29 08:17:03 -070021import 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 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;
Tatu Saloranta43fbd712016-11-09 21:43:27 -0800160 if (cache == null) {
161 cache = new DeserializerCache();
162 }
163 _cache = cache;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800164 _featureFlags = 0;
165 _config = null;
166 _injectableValues = null;
167 _view = null;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700168 _attributes = null;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800169 }
170
171 protected DeserializationContext(DeserializationContext src,
172 DeserializerFactory factory)
173 {
174 _cache = src._cache;
175 _factory = factory;
176
177 _config = src._config;
178 _featureFlags = src._featureFlags;
179 _view = src._view;
180 _parser = src._parser;
181 _injectableValues = src._injectableValues;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700182 _attributes = src._attributes;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800183 }
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700184
185 /**
186 * Constructor used for creating actual per-call instances.
187 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800188 protected DeserializationContext(DeserializationContext src,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700189 DeserializationConfig config, JsonParser p,
Tatu Saloranta060ce112012-02-01 22:18:09 -0800190 InjectableValues injectableValues)
191 {
192 _cache = src._cache;
193 _factory = src._factory;
194
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800195 _config = config;
Tatu Salorantae3ae58e2012-01-28 23:08:16 -0800196 _featureFlags = config.getDeserializationFeatures();
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800197 _view = config.getActiveView();
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700198 _parser = p;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800199 _injectableValues = injectableValues;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700200 _attributes = config.getAttributes();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800201 }
Tatu Saloranta9439a312013-03-02 13:13:09 -0800202
Tatu Saloranta23328aa2014-10-28 22:38:15 -0700203 /**
204 * Copy-constructor for use with <code>copy()</code> by {@link ObjectMapper#copy()}
205 */
206 protected DeserializationContext(DeserializationContext src) {
207 _cache = new DeserializerCache();
208 _factory = src._factory;
209
210 _config = src._config;
211 _featureFlags = src._featureFlags;
212 _view = src._view;
213 _injectableValues = null;
214 }
215
Tatu Saloranta9439a312013-03-02 13:13:09 -0800216 /*
217 /**********************************************************
218 /* DatabindContext implementation
219 /**********************************************************
220 */
221
222 @Override
223 public DeserializationConfig getConfig() { return _config; }
224
225 @Override
226 public final Class<?> getActiveView() { return _view; }
227
228 @Override
Tatu Salorantaa5301ba2015-12-11 09:47:09 -0800229 public final boolean canOverrideAccessModifiers() {
230 return _config.canOverrideAccessModifiers();
231 }
232
233 @Override
234 public final boolean isEnabled(MapperFeature feature) {
235 return _config.isEnabled(feature);
236 }
237
238 @Override
239 public final JsonFormat.Value getDefaultPropertyFormat(Class<?> baseType) {
240 return _config.getDefaultPropertyFormat(baseType);
241 }
Tatu Saloranta4fdbb692016-04-16 21:41:14 -0700242
Tatu Salorantaa5301ba2015-12-11 09:47:09 -0800243 @Override
Tatu Saloranta9439a312013-03-02 13:13:09 -0800244 public final AnnotationIntrospector getAnnotationIntrospector() {
245 return _config.getAnnotationIntrospector();
246 }
247
248 @Override
249 public final TypeFactory getTypeFactory() {
250 return _config.getTypeFactory();
251 }
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700252
Cowtowncoder41bbc962015-06-19 17:16:08 -0700253 /**
254 * Method for accessing default Locale to use: convenience method for
255 *<pre>
256 * getConfig().getLocale();
257 *</pre>
258 */
259 @Override
260 public Locale getLocale() {
261 return _config.getLocale();
262 }
263
264 /**
265 * Method for accessing default TimeZone to use: convenience method for
266 *<pre>
267 * getConfig().getTimeZone();
268 *</pre>
269 */
270 @Override
271 public TimeZone getTimeZone() {
272 return _config.getTimeZone();
273 }
274
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700275 /*
276 /**********************************************************
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800277 /* Access to per-call state, like generic attributes (2.3+)
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700278 /**********************************************************
279 */
280
281 @Override
282 public Object getAttribute(Object key) {
283 return _attributes.getAttribute(key);
284 }
285
286 @Override
287 public DeserializationContext setAttribute(Object key, Object value)
288 {
289 _attributes = _attributes.withPerCallAttribute(key, value);
290 return this;
291 }
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800292
293 /**
294 * Accessor to {@link JavaType} of currently contextualized
295 * {@link ContextualDeserializer}, if any.
296 * This is sometimes useful for generic {@link JsonDeserializer}s that
297 * do not get passed (or do not retain) type information when being
298 * constructed: happens for example for deserializers constructed
299 * from annotations.
300 *
301 * @since 2.5
302 *
303 * @return Type of {@link ContextualDeserializer} being contextualized,
304 * if process is on-going; null if not.
305 */
306 public JavaType getContextualType() {
307 return (_currentType == null) ? null : _currentType.value();
308 }
309
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800310 /*
311 /**********************************************************
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800312 /* Public API, config setting accessors
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800313 /**********************************************************
314 */
315
316 /**
Dmitry Katsuboe70c66f2012-09-03 16:00:30 +0200317 * Method for getting current {@link DeserializerFactory}.
318 */
319 public DeserializerFactory getFactory() {
320 return _factory;
321 }
Tatu Saloranta9439a312013-03-02 13:13:09 -0800322
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800323 /**
324 * Convenience method for checking whether specified on/off
325 * feature is enabled
326 */
Tatu9610aff2012-02-02 11:30:08 -0800327 public final boolean isEnabled(DeserializationFeature feat) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800328 /* 03-Dec-2010, tatu: minor shortcut; since this is called quite often,
329 * let's use a local copy of feature settings:
330 */
331 return (_featureFlags & feat.getMask()) != 0;
332 }
333
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800334 /**
Cowtowncoder23e52ab2015-05-19 17:53:26 -0700335 * Bulk access method for getting the bit mask of all {@link DeserializationFeature}s
336 * that are enabled.
337 *
338 * @since 2.6
339 */
340 public final int getDeserializationFeatures() {
341 return _featureFlags;
342 }
343
344 /**
345 * Bulk access method for checking that all features specified by
Tatu Saloranta0ac36ba2013-08-21 18:08:51 -0700346 * mask are enabled.
347 *
348 * @since 2.3
349 */
350 public final boolean hasDeserializationFeatures(int featureMask) {
Cowtowncoder23e52ab2015-05-19 17:53:26 -0700351 return (_featureFlags & featureMask) == featureMask;
352 }
353
354 /**
355 * Bulk access method for checking that at least one of features specified by
356 * mask is enabled.
357 *
358 * @since 2.6
359 */
360 public final boolean hasSomeOfFeatures(int featureMask) {
361 return (_featureFlags & featureMask) != 0;
Tatu Saloranta0ac36ba2013-08-21 18:08:51 -0700362 }
363
364 /**
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800365 * Method for accessing the currently active parser.
366 * May be different from the outermost parser
367 * when content is buffered.
368 *<p>
369 * Use of this method is discouraged: if code has direct access
370 * to the active parser, that should be used instead.
371 */
372 public final JsonParser getParser() { return _parser; }
373
374 public final Object findInjectableValue(Object valueId,
375 BeanProperty forProperty, Object beanInstance)
Tatu Saloranta68440372016-10-29 17:06:05 -0700376 throws JsonMappingException
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800377 {
378 if (_injectableValues == null) {
Tatu Saloranta68440372016-10-29 17:06:05 -0700379 reportBadDefinition(ClassUtil.classOf(valueId), String.format(
380"No 'injectableValues' configured, can not inject value with id [%s]", valueId));
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800381 }
382 return _injectableValues.findInjectableValue(valueId, this, forProperty, beanInstance);
383 }
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800384
Tatu Saloranta060ce112012-02-01 22:18:09 -0800385 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800386 * Convenience method for accessing the default Base64 encoding
387 * used for decoding base64 encoded binary content.
388 * Same as calling:
389 *<pre>
390 * getConfig().getBase64Variant();
391 *</pre>
392 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800393 public final Base64Variant getBase64Variant() {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800394 return _config.getBase64Variant();
395 }
396
Tatu Saloranta060ce112012-02-01 22:18:09 -0800397 /**
398 * Convenience method, functionally equivalent to:
399 *<pre>
400 * getConfig().getNodeFactory();
401 * </pre>
402 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800403 public final JsonNodeFactory getNodeFactory() {
404 return _config.getNodeFactory();
405 }
406
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800407 /*
408 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800409 /* Public API, pass-through to DeserializerCache
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800410 /**********************************************************
411 */
Tatuc3a73d02012-01-31 12:45:49 -0800412
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800413 /**
Tatu Saloranta060ce112012-02-01 22:18:09 -0800414 * Method for checking whether we could find a deserializer
415 * for given type.
Cowtowncodera2e27202014-11-25 17:07:52 -0800416 *
Tatu Salorantaaf263c32013-10-24 16:18:50 -0700417 * @param type
418 * @since 2.3
Tatu Saloranta060ce112012-02-01 22:18:09 -0800419 */
Tatu Salorantaaf263c32013-10-24 16:18:50 -0700420 public boolean hasValueDeserializerFor(JavaType type, AtomicReference<Throwable> cause) {
421 try {
422 return _cache.hasValueDeserializerFor(this, _factory, type);
423 } catch (JsonMappingException e) {
424 if (cause != null) {
425 cause.set(e);
426 }
427 } catch (RuntimeException e) {
428 if (cause == null) { // earlier behavior
429 throw e;
430 }
431 cause.set(e);
432 }
433 return false;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800434 }
435
Tatu Saloranta060ce112012-02-01 22:18:09 -0800436 /**
Tatuc3a73d02012-01-31 12:45:49 -0800437 * Method for finding a value deserializer, and creating a contextual
438 * version if necessary, for value reached via specified property.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800439 */
Tatuc3a73d02012-01-31 12:45:49 -0800440 @SuppressWarnings("unchecked")
441 public final JsonDeserializer<Object> findContextualValueDeserializer(JavaType type,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700442 BeanProperty prop) throws JsonMappingException
Tatuc3a73d02012-01-31 12:45:49 -0800443 {
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700444 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this, _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800445 if (deser != null) {
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800446 deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, prop, type);
Tatuc3a73d02012-01-31 12:45:49 -0800447 }
448 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800449 }
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700450
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800451 /**
Cowtowncodera2e27202014-11-25 17:07:52 -0800452 * Variant that will try to locate deserializer for current type, but without
453 * performing any contextualization (unlike {@link #findContextualValueDeserializer})
454 * or checking for need to create a {@link TypeDeserializer} (unlike
455 * {@link #findRootValueDeserializer(JavaType)}.
456 * This method is usually called from within {@link ResolvableDeserializer#resolve},
457 * and expectation is that caller then calls either
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800458 * {@link #handlePrimaryContextualization(JsonDeserializer, BeanProperty, JavaType)} or
459 * {@link #handleSecondaryContextualization(JsonDeserializer, BeanProperty, JavaType)} at a
Cowtowncodera2e27202014-11-25 17:07:52 -0800460 * later point, as necessary.
461 *
462 * @since 2.5
463 */
464 public final JsonDeserializer<Object> findNonContextualValueDeserializer(JavaType type)
465 throws JsonMappingException
466 {
467 return _cache.findValueDeserializer(this, _factory, type);
468 }
469
470 /**
Tatuc3a73d02012-01-31 12:45:49 -0800471 * Method for finding a deserializer for root-level value.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800472 */
Tatuc3a73d02012-01-31 12:45:49 -0800473 @SuppressWarnings("unchecked")
Tatu Saloranta9b9d0432012-01-30 09:20:26 -0800474 public final JsonDeserializer<Object> findRootValueDeserializer(JavaType type)
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700475 throws JsonMappingException
Tatuc3a73d02012-01-31 12:45:49 -0800476 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800477 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this,
478 _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800479 if (deser == null) { // can this occur?
480 return null;
481 }
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800482 deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, null, type);
Tatuc3a73d02012-01-31 12:45:49 -0800483 TypeDeserializer typeDeser = _factory.findTypeDeserializer(_config, type);
484 if (typeDeser != null) {
485 // important: contextualize to indicate this is for root value
486 typeDeser = typeDeser.forProperty(null);
487 return new TypeWrappedDeserializer(typeDeser, deser);
488 }
489 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800490 }
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800491
492 /**
493 * Convenience method, functionally same as:
494 *<pre>
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700495 * getDeserializerProvider().findKeyDeserializer(getConfig(), prop.getType(), prop);
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800496 *</pre>
497 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800498 public final KeyDeserializer findKeyDeserializer(JavaType keyType,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700499 BeanProperty prop) throws JsonMappingException {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800500 KeyDeserializer kd = _cache.findKeyDeserializer(this,
501 _factory, keyType);
Tatud0bb3152012-01-31 13:04:06 -0800502 // Second: contextualize?
503 if (kd instanceof ContextualKeyDeserializer) {
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700504 kd = ((ContextualKeyDeserializer) kd).createContextual(this, prop);
Tatud0bb3152012-01-31 13:04:06 -0800505 }
506 return kd;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800507 }
508
Tatub37ff332012-01-24 16:19:36 -0800509 /*
510 /**********************************************************
Tatu Saloranta34a8adf2012-02-08 22:07:36 -0800511 /* Public API, ObjectId handling
512 /**********************************************************
513 */
514
515 /**
516 * Method called to find and return entry corresponding to given
517 * Object Id: will add an entry if necessary, and never returns null
518 */
Pascal GĂ©linas184cae32014-02-05 17:35:56 -0500519 public abstract ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator, ObjectIdResolver resolver);
520
Pascal GĂ©linas096e02b2013-12-18 17:21:42 -0500521 /**
522 * Method called to ensure that every object id encounter during processing
523 * are resolved.
524 *
525 * @throws UnresolvedForwardReference
526 */
527 public abstract void checkUnresolvedObjectId()
528 throws UnresolvedForwardReference;
529
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800530 /*
531 /**********************************************************
532 /* Public API, type handling
533 /**********************************************************
534 */
535
536 /**
537 * Convenience method, functionally equivalent to:
538 *<pre>
539 * getConfig().constructType(cls);
540 * </pre>
541 */
542 public final JavaType constructType(Class<?> cls) {
Tatu Saloranta816bbed2016-10-05 21:13:12 -0700543 return (cls == null) ? null : _config.constructType(cls);
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800544 }
545
546 /**
Cowtowncodera5bd0a22015-06-25 15:27:07 -0700547 * Helper method that is to be used when resolving basic class name into
548 * Class instance, the reason being that it may be necessary to work around
549 * various ClassLoader limitations, as well as to handle primitive type
550 * signatures.
551 *
552 * @since 2.6
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800553 */
554 public Class<?> findClass(String className) throws ClassNotFoundException
555 {
556 // By default, delegate to ClassUtil: can be overridden with custom handling
Cowtowncodera5bd0a22015-06-25 15:27:07 -0700557 return getTypeFactory().findClass(className);
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800558 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800559
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800560 /*
561 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800562 /* Public API, helper object recycling
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800563 /**********************************************************
564 */
565
566 /**
567 * Method that can be used to get access to a reusable ObjectBuffer,
568 * useful for efficiently constructing Object arrays and Lists.
569 * Note that leased buffers should be returned once deserializer
570 * is done, to allow for reuse during same round of deserialization.
571 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800572 public final ObjectBuffer leaseObjectBuffer()
573 {
574 ObjectBuffer buf = _objectBuffer;
575 if (buf == null) {
576 buf = new ObjectBuffer();
577 } else {
578 _objectBuffer = null;
579 }
580 return buf;
581 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800582
583 /**
584 * Method to call to return object buffer previously leased with
585 * {@link #leaseObjectBuffer}.
586 *
587 * @param buf Returned object buffer
588 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800589 public final void returnObjectBuffer(ObjectBuffer buf)
590 {
591 /* Already have a reusable buffer? Let's retain bigger one
592 * (or if equal, favor newer one, shorter life-cycle)
593 */
594 if (_objectBuffer == null
595 || buf.initialCapacity() >= _objectBuffer.initialCapacity()) {
596 _objectBuffer = buf;
597 }
598 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800599
600 /**
601 * Method for accessing object useful for building arrays of
602 * primitive types (such as int[]).
603 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800604 public final ArrayBuilders getArrayBuilders()
605 {
606 if (_arrayBuilders == null) {
607 _arrayBuilders = new ArrayBuilders();
608 }
609 return _arrayBuilders;
610 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800611
612 /*
613 /**********************************************************
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700614 /* Extended API: handler instantiation
615 /**********************************************************
616 */
617
618 public abstract JsonDeserializer<Object> deserializerInstance(Annotated annotated,
619 Object deserDef)
620 throws JsonMappingException;
621
622 public abstract KeyDeserializer keyDeserializerInstance(Annotated annotated,
623 Object deserDef)
624 throws JsonMappingException;
625
626 /*
627 /**********************************************************
628 /* Extended API: resolving contextual deserializers; called
629 /* by structured deserializers for their value/component
630 /* deserializers
631 /**********************************************************
632 */
633
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700634 /**
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700635 * Method called for primary property deserializers (ones
Tatu Saloranta59fe29c2013-09-05 22:37:06 -0700636 * directly created to deserialize values of a POJO property),
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700637 * to handle details of resolving
638 * {@link ContextualDeserializer} with given property context.
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700639 *
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700640 * @param prop Property for which the given primary deserializer is used; never null.
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700641 *
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800642 * @since 2.5
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700643 */
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700644 public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> deser,
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800645 BeanProperty prop, JavaType type)
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700646 throws JsonMappingException
647 {
Cowtowncodera2e27202014-11-25 17:07:52 -0800648 if (deser instanceof ContextualDeserializer) {
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800649 _currentType = new LinkedNode<JavaType>(type, _currentType);
650 try {
651 deser = ((ContextualDeserializer) deser).createContextual(this, prop);
652 } finally {
653 _currentType = _currentType.next();
654 }
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700655 }
656 return deser;
657 }
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700658
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700659 /**
660 * Method called for secondary property deserializers (ones
661 * NOT directly created to deal with an annotatable POJO property,
662 * but instead created as a component -- such as value deserializers
663 * for structured types, or deserializers for root values)
664 * to handle details of resolving
665 * {@link ContextualDeserializer} with given property context.
Tatu Saloranta59fe29c2013-09-05 22:37:06 -0700666 * Given that these deserializers are not directly related to given property
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700667 * (or, in case of root value property, to any property), annotations
668 * accessible may or may not be relevant.
669 *
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700670 * @param prop Property for which deserializer is used, if any; null
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700671 * when deserializing root values
672 *
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800673 * @since 2.5
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700674 */
675 public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?> deser,
Tatu Salorantac4b6c612014-12-26 22:07:54 -0800676 BeanProperty prop, JavaType type)
677 throws JsonMappingException
678 {
679 if (deser instanceof ContextualDeserializer) {
680 _currentType = new LinkedNode<JavaType>(type, _currentType);
681 try {
682 deser = ((ContextualDeserializer) deser).createContextual(this, prop);
683 } finally {
684 _currentType = _currentType.next();
685 }
686 }
687 return deser;
688 }
689
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700690 /*
691 /**********************************************************
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800692 /* Parsing methods that may use reusable/-cyclable objects
693 /**********************************************************
694 */
695
696 /**
697 * Convenience method for parsing a Date from given String, using
698 * currently configured date format (accessed using
699 * {@link DeserializationConfig#getDateFormat()}).
700 *<p>
701 * Implementation will handle thread-safety issues related to
702 * date formats such that first time this method is called,
703 * date format is cloned, and cloned instance will be retained
704 * for use during this deserialization round.
705 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700706 public Date parseDate(String dateStr) throws IllegalArgumentException
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800707 {
708 try {
Tatu Salorantaef00ac62013-11-03 09:56:39 -0800709 DateFormat df = getDateFormat();
710 return df.parse(dateStr);
Tatu Salorantaaa512742012-02-22 22:51:33 -0800711 } catch (ParseException e) {
Tatu Saloranta8e9d4b22015-05-01 21:26:32 -0700712 throw new IllegalArgumentException(String.format(
713 "Failed to parse Date value '%s': %s", dateStr, e.getMessage()));
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800714 }
715 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800716
717 /**
718 * Convenience method for constructing Calendar instance set
719 * to specified time, to be modified and used by caller.
720 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700721 public Calendar constructCalendar(Date d) {
722 // 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 -0800723 Calendar c = Calendar.getInstance(getTimeZone());
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800724 c.setTime(d);
725 return c;
726 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800727
728 /*
729 /**********************************************************
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700730 /* Convenience methods for reading parsed values
731 /**********************************************************
732 */
733
734 /**
735 * Convenience method that may be used by composite or container deserializers,
736 * for reading one-off values contained (for sequences, it is more efficient
737 * to actually fetch deserializer once for the whole collection).
738 *<p>
739 * NOTE: when deserializing values of properties contained in composite types,
740 * rather use {@link #readPropertyValue(JsonParser, BeanProperty, Class)};
741 * this method does not allow use of contextual annotations.
742 *
743 * @since 2.4
744 */
745 public <T> T readValue(JsonParser p, Class<T> type) throws IOException {
746 return readValue(p, getTypeFactory().constructType(type));
747 }
748
749 /**
750 * @since 2.4
751 */
752 @SuppressWarnings("unchecked")
753 public <T> T readValue(JsonParser p, JavaType type) throws IOException {
754 JsonDeserializer<Object> deser = findRootValueDeserializer(type);
755 if (deser == null) {
Tatu Salorantac1478ac2016-09-29 08:17:03 -0700756 reportBadDefinition(type,
757 "Could not find JsonDeserializer for type "+type);
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700758 }
759 return (T) deser.deserialize(p, this);
760 }
761
762 /**
763 * Convenience method that may be used by composite or container deserializers,
764 * for reading one-off values for the composite type, taking into account
765 * annotations that the property (passed to this method -- usually property that
766 * has custom serializer that called this method) has.
767 *
768 * @since 2.4
769 */
770 public <T> T readPropertyValue(JsonParser p, BeanProperty prop, Class<T> type) throws IOException {
771 return readPropertyValue(p, prop, getTypeFactory().constructType(type));
772 }
773
774 /**
775 * @since 2.4
776 */
777 @SuppressWarnings("unchecked")
778 public <T> T readPropertyValue(JsonParser p, BeanProperty prop, JavaType type) throws IOException {
779 JsonDeserializer<Object> deser = findContextualValueDeserializer(type, prop);
780 if (deser == null) {
Tatu Salorantac1478ac2016-09-29 08:17:03 -0700781 return reportBadDefinition(type, String.format(
Tatu Saloranta851092c2016-05-21 20:08:40 -0700782 "Could not find JsonDeserializer for type %s (via property %s)",
Tatu Saloranta43fbd712016-11-09 21:43:27 -0800783 type, ClassUtil.nameOf(prop)));
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700784 }
785 return (T) deser.deserialize(p, this);
786 }
Tatu Saloranta5ae6e4b2015-10-05 21:49:01 -0700787
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700788 /*
789 /**********************************************************
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700790 /* Methods for problem handling
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800791 /**********************************************************
792 */
793
794 /**
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700795 * Method that deserializers should call if they encounter an unrecognized
796 * property (and once that is not explicitly designed as ignorable), to
797 * inform possibly configured {@link DeserializationProblemHandler}s and
798 * let it handle the problem.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800799 *
800 * @return True if there was a configured problem handler that was able to handle the
Tatu Saloranta0e3b3832012-01-22 22:08:20 -0800801 * problem
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800802 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700803 public boolean handleUnknownProperty(JsonParser p, JsonDeserializer<?> deser,
Tatu Saloranta060ce112012-02-01 22:18:09 -0800804 Object instanceOrClass, String propName)
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700805 throws IOException
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800806 {
807 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700808 while (h != null) {
809 // Can bail out if it's handled
810 if (h.value().handleUnknownProperty(this, p, deser, instanceOrClass, propName)) {
811 return true;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800812 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700813 h = h.next();
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800814 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700815 // Nope, not handled. Potentially that's a problem...
816 if (!isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
817 p.skipChildren();
818 return true;
819 }
820 // Do we know properties that are expected instead?
821 Collection<Object> propIds = (deser == null) ? null : deser.getKnownPropertyNames();
822 throw UnrecognizedPropertyException.from(_parser,
823 instanceOrClass, propName, propIds);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800824 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800825
826 /**
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700827 * Method that deserializers should call if they encounter a String value
828 * that can not be converted to expected key of a {@link java.util.Map}
829 * valued property.
830 * Default implementation will try to call {@link DeserializationProblemHandler#handleWeirdNumberValue}
831 * on configured handlers, if any, to allow for recovery; if recovery does not
832 * succeed, will throw {@link InvalidFormatException} with given message.
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700833 *
834 * @param keyClass Expected type for key
835 * @param keyValue String value from which to deserialize key
836 * @param msg Error message template caller wants to use if exception is to be thrown
837 * @param msgArgs Optional arguments to use for message, if any
838 *
839 * @return Key value to use
840 *
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700841 * @throws IOException To indicate unrecoverable problem, usually based on <code>msg</code>
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700842 *
843 * @since 2.8
844 */
845 public Object handleWeirdKey(Class<?> keyClass, String keyValue,
846 String msg, Object... msgArgs)
847 throws IOException
848 {
849 // but if not handled, just throw exception
Tatu Saloranta79124862016-10-19 22:13:29 -0700850 msg = _format(msg, msgArgs);
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700851 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700852 while (h != null) {
853 // Can bail out if it's handled
854 Object key = h.value().handleWeirdKey(this, keyClass, keyValue, msg);
Tatu Saloranta2d318f62016-05-10 21:58:00 -0700855 if (key != DeserializationProblemHandler.NOT_HANDLED) {
Tatu Salorantad01e3ab2016-05-19 09:31:38 -0700856 // Sanity check for broken handlers, otherwise nasty to debug:
857 if ((key == null) || keyClass.isInstance(key)) {
858 return key;
859 }
860 throw weirdStringException(keyValue, keyClass, String.format(
861 "DeserializationProblemHandler.handleWeirdStringValue() for type %s returned value of type %s",
862 keyClass, key.getClass()));
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700863 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700864 h = h.next();
Tatu Saloranta1e5fd122016-05-09 23:26:30 -0700865 }
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700866 throw weirdKeyException(keyClass, keyValue, msg);
867 }
868
869 /**
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -0700870 * Method that deserializers should call if they encounter a String value
871 * that can not be converted to target property type, in cases where some
872 * String values could be acceptable (either with different settings,
873 * or different value).
874 * Default implementation will try to call {@link DeserializationProblemHandler#handleWeirdStringValue}
875 * on configured handlers, if any, to allow for recovery; if recovery does not
876 * succeed, will throw {@link InvalidFormatException} with given message.
877 *
878 * @param targetClass Type of property into which incoming number should be converted
879 * @param value String value from which to deserialize property value
880 * @param msg Error message template caller wants to use if exception is to be thrown
881 * @param msgArgs Optional arguments to use for message, if any
882 *
883 * @return Property value to use
884 *
885 * @throws IOException To indicate unrecoverable problem, usually based on <code>msg</code>
886 *
887 * @since 2.8
888 */
889 public Object handleWeirdStringValue(Class<?> targetClass, String value,
890 String msg, Object... msgArgs)
891 throws IOException
892 {
893 // but if not handled, just throw exception
Tatu Saloranta79124862016-10-19 22:13:29 -0700894 msg = _format(msg, msgArgs);
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -0700895 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
896 while (h != null) {
897 // Can bail out if it's handled
Tatu Salorantad01e3ab2016-05-19 09:31:38 -0700898 Object instance = h.value().handleWeirdStringValue(this, targetClass, value, msg);
899 if (instance != DeserializationProblemHandler.NOT_HANDLED) {
900 // Sanity check for broken handlers, otherwise nasty to debug:
901 if ((instance == null) || targetClass.isInstance(instance)) {
902 return instance;
903 }
904 throw weirdStringException(value, targetClass, String.format(
905 "DeserializationProblemHandler.handleWeirdStringValue() for type %s returned value of type %s",
906 targetClass, instance.getClass()));
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -0700907 }
908 h = h.next();
909 }
910 throw weirdStringException(value, targetClass, msg);
911 }
912
913 /**
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700914 * Method that deserializers should call if they encounter a numeric value
915 * that can not be converted to target property type, in cases where some
916 * numeric values could be acceptable (either with different settings,
917 * or different numeric value).
918 * Default implementation will try to call {@link DeserializationProblemHandler#handleWeirdNumberValue}
919 * on configured handlers, if any, to allow for recovery; if recovery does not
920 * succeed, will throw {@link InvalidFormatException} with given message.
921 *
922 * @param targetClass Type of property into which incoming number should be converted
923 * @param value Number value from which to deserialize property value
924 * @param msg Error message template caller wants to use if exception is to be thrown
925 * @param msgArgs Optional arguments to use for message, if any
926 *
927 * @return Property value to use
928 *
929 * @throws IOException To indicate unrecoverable problem, usually based on <code>msg</code>
930 *
931 * @since 2.8
932 */
933 public Object handleWeirdNumberValue(Class<?> targetClass, Number value,
934 String msg, Object... msgArgs)
935 throws IOException
936 {
Tatu Saloranta79124862016-10-19 22:13:29 -0700937 msg = _format(msg, msgArgs);
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700938 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
939 while (h != null) {
940 // Can bail out if it's handled
941 Object key = h.value().handleWeirdNumberValue(this, targetClass, value, msg);
942 if (key != DeserializationProblemHandler.NOT_HANDLED) {
Tatu Salorantad01e3ab2016-05-19 09:31:38 -0700943 // Sanity check for broken handlers, otherwise nasty to debug:
944 if ((key == null) || targetClass.isInstance(key)) {
945 return key;
946 }
947 throw weirdNumberException(value, targetClass, String.format(
948 "DeserializationProblemHandler.handleWeirdNumberValue() for type %s returned value of type %s",
949 targetClass, key.getClass()));
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700950 }
951 h = h.next();
952 }
953 throw weirdNumberException(value, targetClass, msg);
954 }
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -0700955
Tatu Saloranta888c6b92016-05-15 22:16:40 -0700956 /**
Tatu Saloranta68245442016-05-21 18:08:41 -0700957 * Method that deserializers should call if they fail to instantiate value
958 * due to lack of viable instantiator (usually creator, that is, constructor
959 * or static factory method). Method should be called at point where value
960 * has not been decoded, so that handler has a chance to handle decoding
961 * using alternate mechanism, and handle underlying content (possibly by
962 * just skipping it) to keep input state valid
Tatu Saloranta609a0f82016-05-18 20:17:10 -0700963 *
Tatu Saloranta68245442016-05-21 18:08:41 -0700964 * @param instClass Type that was to be instantiated
Tatu Salorantaed416862016-10-16 13:42:12 -0700965 * @param valueInst (optional) Value instantiator to be used, if any; null if type does not
966 * use one for instantiation (custom deserialiers don't; standard POJO deserializer does)
Tatu Saloranta68245442016-05-21 18:08:41 -0700967 * @param p Parser that points to the JSON value to decode
Tatu Saloranta609a0f82016-05-18 20:17:10 -0700968 *
Tatu Saloranta68245442016-05-21 18:08:41 -0700969 * @return Object that should be constructed, if any; has to be of type <code>instClass</code>
Tatu Saloranta609a0f82016-05-18 20:17:10 -0700970 *
Tatu Salorantaed416862016-10-16 13:42:12 -0700971 * @since 2.9 (2.8 had alternate that did not take <code>ValueInstantiator</code>)
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700972 */
Tatu Salorantaed416862016-10-16 13:42:12 -0700973 @SuppressWarnings("resource")
974 public Object handleMissingInstantiator(Class<?> instClass, ValueInstantiator valueInst,
975 JsonParser p, String msg, Object... msgArgs)
Tatu Saloranta68245442016-05-21 18:08:41 -0700976 throws IOException
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700977 {
Tatu Salorantaed416862016-10-16 13:42:12 -0700978 if (p == null) {
979 p = getParser();
980 }
Tatu Saloranta79124862016-10-19 22:13:29 -0700981 msg = _format(msg, msgArgs);
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700982 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
983 while (h != null) {
984 // Can bail out if it's handled
Tatu Saloranta68245442016-05-21 18:08:41 -0700985 Object instance = h.value().handleMissingInstantiator(this,
Tatu Salorantaed416862016-10-16 13:42:12 -0700986 instClass, valueInst, p, msg);
Tatu Saloranta68245442016-05-21 18:08:41 -0700987 if (instance != DeserializationProblemHandler.NOT_HANDLED) {
988 // Sanity check for broken handlers, otherwise nasty to debug:
989 if ((instance == null) || instClass.isInstance(instance)) {
990 return instance;
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700991 }
Tatu Saloranta816bbed2016-10-05 21:13:12 -0700992 reportBadDefinition(constructType(instClass), String.format(
993"DeserializationProblemHandler.handleMissingInstantiator() for type %s returned value of type %s",
Tatu Saloranta267abe12016-11-25 18:14:20 -0800994 instClass, ClassUtil.classNameOf(instance)));
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -0700995 }
996 h = h.next();
997 }
Tatu Salorantaed416862016-10-16 13:42:12 -0700998
999 // 16-Oct-2016, tatu: This is either a definition problem (if no applicable creator
Tatu Saloranta581ba1f2017-01-25 21:55:11 -08001000 // exists), or input mismatch problem (otherwise) since none of existing creators
Tatu Salorantaed416862016-10-16 13:42:12 -07001001 // match with token.
1002 if ((valueInst != null) && !valueInst.canInstantiate()) {
1003 msg = String.format("Can not construct instance of %s (no Creators, like default construct, exist): %s",
Tatu Saloranta267abe12016-11-25 18:14:20 -08001004 ClassUtil.nameOf(instClass), msg);
Tatu Salorantaed416862016-10-16 13:42:12 -07001005 return reportBadDefinition(constructType(instClass), msg);
1006 }
1007 msg = String.format("Can not construct instance of %s (although at least one Creator exists): %s",
Tatu Saloranta267abe12016-11-25 18:14:20 -08001008 ClassUtil.nameOf(instClass), msg);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001009 return reportInputMismatch(instClass, msg);
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001010 }
1011
Tatu Saloranta609a0f82016-05-18 20:17:10 -07001012 /**
1013 * Method that deserializers should call if they fail to instantiate value
1014 * due to an exception that was thrown by constructor (or other mechanism used
1015 * to create instances).
1016 * Default implementation will try to call {@link DeserializationProblemHandler#handleInstantiationProblem}
1017 * on configured handlers, if any, to allow for recovery; if recovery does not
1018 * succeed, will throw exception constructed with {@link #instantiationException}.
1019 *
1020 * @param instClass Type that was to be instantiated
1021 * @param argument (optional) Argument that was passed to constructor or equivalent
1022 * instantiator; often a {@link java.lang.String}.
1023 * @param t Exception that caused failure
1024 *
1025 * @return Object that should be constructed, if any; has to be of type <code>instClass</code>
1026 *
1027 * @since 2.8
1028 */
1029 public Object handleInstantiationProblem(Class<?> instClass, Object argument,
1030 Throwable t)
1031 throws IOException
1032 {
1033 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
1034 while (h != null) {
1035 // Can bail out if it's handled
Tatu Salorantad01e3ab2016-05-19 09:31:38 -07001036 Object instance = h.value().handleInstantiationProblem(this, instClass, argument, t);
1037 if (instance != DeserializationProblemHandler.NOT_HANDLED) {
1038 // Sanity check for broken handlers, otherwise nasty to debug:
Tatu Saloranta43fbd712016-11-09 21:43:27 -08001039 if (instClass.isInstance(instance)) {
Tatu Salorantad01e3ab2016-05-19 09:31:38 -07001040 return instance;
1041 }
Tatu Saloranta816bbed2016-10-05 21:13:12 -07001042 reportBadDefinition(constructType(instClass), String.format(
1043"DeserializationProblemHandler.handleInstantiationProblem() for type %s returned value of type %s",
Tatu Saloranta43fbd712016-11-09 21:43:27 -08001044 instClass, ClassUtil.classNameOf(instance)));
Tatu Saloranta609a0f82016-05-18 20:17:10 -07001045 }
1046 h = h.next();
1047 }
1048 // 18-May-2016, tatu: Only wrap if not already a valid type to throw
Tatu Saloranta78c72292016-11-07 20:37:45 -08001049 ClassUtil.throwIfIOE(t);
Tatu Saloranta609a0f82016-05-18 20:17:10 -07001050 throw instantiationException(instClass, t);
1051 }
1052
Tatu Saloranta68245442016-05-21 18:08:41 -07001053 /**
Tatu Saloranta851092c2016-05-21 20:08:40 -07001054 * Method that deserializers should call if the first token of the value to
1055 * deserialize is of unexpected type (that is, type of token that deserializer
1056 * can not handle). This could occur, for example, if a Number deserializer
1057 * encounter {@link JsonToken#START_ARRAY} instead of
1058 * {@link JsonToken#VALUE_NUMBER_INT} or {@link JsonToken#VALUE_NUMBER_FLOAT}.
1059 *
1060 * @param instClass Type that was to be instantiated
1061 * @param p Parser that points to the JSON value to decode
1062 *
1063 * @return Object that should be constructed, if any; has to be of type <code>instClass</code>
1064 *
1065 * @since 2.8
1066 */
1067 public Object handleUnexpectedToken(Class<?> instClass, JsonParser p)
1068 throws IOException
1069 {
1070 return handleUnexpectedToken(instClass, p.getCurrentToken(), p, null);
1071 }
Tatu Saloranta43fbd712016-11-09 21:43:27 -08001072
Tatu Saloranta851092c2016-05-21 20:08:40 -07001073 /**
1074 * Method that deserializers should call if the first token of the value to
1075 * deserialize is of unexpected type (that is, type of token that deserializer
1076 * can not handle). This could occur, for example, if a Number deserializer
1077 * encounter {@link JsonToken#START_ARRAY} instead of
1078 * {@link JsonToken#VALUE_NUMBER_INT} or {@link JsonToken#VALUE_NUMBER_FLOAT}.
1079 *
1080 * @param instClass Type that was to be instantiated
Tatu Saloranta2a877182016-10-15 18:18:22 -07001081 * @param t Token encountered that does match expected
Tatu Saloranta851092c2016-05-21 20:08:40 -07001082 * @param p Parser that points to the JSON value to decode
1083 *
1084 * @return Object that should be constructed, if any; has to be of type <code>instClass</code>
1085 *
1086 * @since 2.8
1087 */
1088 public Object handleUnexpectedToken(Class<?> instClass, JsonToken t,
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001089 JsonParser p, String msg, Object... msgArgs)
Tatu Saloranta851092c2016-05-21 20:08:40 -07001090 throws IOException
1091 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001092 msg = _format(msg, msgArgs);
Tatu Saloranta851092c2016-05-21 20:08:40 -07001093 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
1094 while (h != null) {
1095 Object instance = h.value().handleUnexpectedToken(this,
1096 instClass, t, p, msg);
1097 if (instance != DeserializationProblemHandler.NOT_HANDLED) {
1098 if ((instance == null) || instClass.isInstance(instance)) {
1099 return instance;
1100 }
Tatu Saloranta2a877182016-10-15 18:18:22 -07001101 reportBadDefinition(constructType(instClass), String.format(
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001102 "DeserializationProblemHandler.handleUnexpectedToken() for type %s returned value of type %s",
Tatu Saloranta2a877182016-10-15 18:18:22 -07001103 instance.getClass()));
Tatu Saloranta851092c2016-05-21 20:08:40 -07001104 }
1105 h = h.next();
1106 }
Tatu Saloranta851092c2016-05-21 20:08:40 -07001107 if (msg == null) {
Tatu Saloranta73359ae2016-06-06 08:44:54 -07001108 if (t == null) {
1109 msg = String.format("Unexpected end-of-input when binding data into %s",
1110 _calcName(instClass));
1111 } else {
1112 msg = String.format("Can not deserialize instance of %s out of %s token",
1113 _calcName(instClass), t);
1114 }
Tatu Saloranta851092c2016-05-21 20:08:40 -07001115 }
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001116 reportInputMismatch(instClass, msg);
Tatu Salorantaacc533a2016-05-22 21:47:18 -07001117 return null; // never gets here
Tatu Saloranta851092c2016-05-21 20:08:40 -07001118 }
1119
1120 /**
Tatu Saloranta68245442016-05-21 18:08:41 -07001121 * Method that deserializers should call if they encounter a type id
1122 * (for polymorphic deserialization) that can not be resolved to an
1123 * actual type; usually since there is no mapping defined.
1124 * Default implementation will try to call {@link DeserializationProblemHandler#handleUnknownTypeId}
1125 * on configured handlers, if any, to allow for recovery; if recovery does not
Tatu Saloranta3ee81a62017-05-02 10:01:48 -07001126 * succeed, will throw exception constructed with {@link #invalidTypeIdException}.
Tatu Saloranta68245442016-05-21 18:08:41 -07001127 *
1128 * @param baseType Base type from which resolution starts
1129 * @param id Type id that could not be converted
1130 * @param extraDesc Additional problem description to add to default exception message,
1131 * if resolution fails.
1132 *
1133 * @return {@link JavaType} that id resolves to
1134 *
1135 * @throws IOException To indicate unrecoverable problem, if resolution can not
1136 * be made to work
1137 *
1138 * @since 2.8
1139 */
1140 public JavaType handleUnknownTypeId(JavaType baseType, String id,
Tatu Salorantad6230fd2016-05-30 21:11:19 -07001141 TypeIdResolver idResolver, String extraDesc) throws IOException
Tatu Saloranta68245442016-05-21 18:08:41 -07001142 {
1143 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
1144 while (h != null) {
1145 // Can bail out if it's handled
Tatu Salorantad6230fd2016-05-30 21:11:19 -07001146 JavaType type = h.value().handleUnknownTypeId(this, baseType, id, idResolver, extraDesc);
Tatu Saloranta68245442016-05-21 18:08:41 -07001147 if (type != null) {
1148 if (type.hasRawClass(Void.class)) {
1149 return null;
1150 }
1151 // But ensure there's type compatibility
1152 if (type.isTypeOrSubTypeOf(baseType.getRawClass())) {
1153 return type;
1154 }
Tatu Saloranta52238562017-04-28 10:52:23 -07001155 throw invalidTypeIdException(baseType, id,
Tatu Saloranta68245442016-05-21 18:08:41 -07001156 "problem handler tried to resolve into non-subtype: "+type);
1157 }
1158 h = h.next();
1159 }
Tatu Saloranta811ec172016-05-24 23:39:04 -07001160 // 24-May-2016, tatu: Actually we may still not want to fail quite yet
1161 if (!isEnabled(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE)) {
1162 return null;
1163 }
Tatu Saloranta52238562017-04-28 10:52:23 -07001164 throw invalidTypeIdException(baseType, id, extraDesc);
Tatu Saloranta68245442016-05-21 18:08:41 -07001165 }
1166
Tatu Saloranta5b8f0d92017-03-09 10:18:47 -08001167 /**
1168 * @since 2.9
1169 */
1170 public JavaType handleMissingTypeId(JavaType baseType,
1171 TypeIdResolver idResolver, String extraDesc) throws IOException
1172 {
1173 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
1174 while (h != null) {
1175 // Can bail out if it's handled
1176 JavaType type = h.value().handleMissingTypeId(this, baseType, idResolver, extraDesc);
1177 if (type != null) {
1178 if (type.hasRawClass(Void.class)) {
1179 return null;
1180 }
1181 // But ensure there's type compatibility
1182 if (type.isTypeOrSubTypeOf(baseType.getRawClass())) {
1183 return type;
1184 }
Tatu Saloranta52238562017-04-28 10:52:23 -07001185 throw invalidTypeIdException(baseType, null,
Tatu Saloranta5b8f0d92017-03-09 10:18:47 -08001186 "problem handler tried to resolve into non-subtype: "+type);
1187 }
1188 h = h.next();
1189 }
1190 // 09-Mar-2017, tatu: We may want to consider yet another feature at some
1191 // point to allow returning `null`... but that seems bit risky for now
1192// if (!isEnabled(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE)) {
1193// return null;
1194// }
1195 throw missingTypeIdException(baseType, extraDesc);
1196 }
1197
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001198 /*
1199 /**********************************************************
Tatu Saloranta68245442016-05-21 18:08:41 -07001200 /* Methods for problem reporting, in cases where recovery
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001201 /* is not considered possible: input problem
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001202 /**********************************************************
1203 */
1204
1205 /**
Tatu Saloranta68245442016-05-21 18:08:41 -07001206 * Method for deserializers to call
1207 * when the token encountered was of type different than what <b>should</b>
1208 * be seen at that position, usually within a sequence of expected tokens.
1209 * Note that this method will throw a {@link JsonMappingException} and no
1210 * recovery is attempted (via {@link DeserializationProblemHandler}, as
1211 * problem is considered to be difficult to recover from, in general.
1212 *
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001213 * @since 2.9
Tatu Saloranta68245442016-05-21 18:08:41 -07001214 */
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001215 public void reportWrongTokenException(JsonDeserializer<?> deser,
1216 JsonToken expToken, String msg, Object... msgArgs)
1217 throws JsonMappingException
1218 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001219 msg = _format(msg, msgArgs);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001220 throw wrongTokenException(getParser(), deser.handledType(), expToken, msg);
1221 }
1222
1223 /**
1224 * Method for deserializers to call
1225 * when the token encountered was of type different than what <b>should</b>
1226 * be seen at that position, usually within a sequence of expected tokens.
1227 * Note that this method will throw a {@link JsonMappingException} and no
1228 * recovery is attempted (via {@link DeserializationProblemHandler}, as
1229 * problem is considered to be difficult to recover from, in general.
1230 *
1231 * @since 2.9
1232 */
1233 public void reportWrongTokenException(JavaType targetType,
1234 JsonToken expToken, String msg, Object... msgArgs)
1235 throws JsonMappingException
1236 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001237 msg = _format(msg, msgArgs);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001238 throw wrongTokenException(getParser(), targetType, expToken, msg);
1239 }
1240
1241 /**
1242 * Method for deserializers to call
1243 * when the token encountered was of type different than what <b>should</b>
1244 * be seen at that position, usually within a sequence of expected tokens.
1245 * Note that this method will throw a {@link JsonMappingException} and no
1246 * recovery is attempted (via {@link DeserializationProblemHandler}, as
1247 * problem is considered to be difficult to recover from, in general.
1248 *
1249 * @since 2.9
1250 */
1251 public void reportWrongTokenException(Class<?> targetType,
1252 JsonToken expToken, String msg, Object... msgArgs)
1253 throws JsonMappingException
1254 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001255 msg = _format(msg, msgArgs);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001256 throw wrongTokenException(getParser(), targetType, expToken, msg);
1257 }
Tatu Saloranta9d1fb752016-06-07 22:47:04 -07001258
1259 /**
1260 * @since 2.8
1261 */
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001262 public <T> T reportUnresolvedObjectId(ObjectIdReader oidReader, Object bean)
Tatu Saloranta9d1fb752016-06-07 22:47:04 -07001263 throws JsonMappingException
1264 {
1265 String msg = String.format("No Object Id found for an instance of %s, to assign to property '%s'",
Tatu Saloranta267abe12016-11-25 18:14:20 -08001266 ClassUtil.classNameOf(bean), oidReader.propertyName);
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001267 return reportInputMismatch(oidReader.idProperty, msg);
Tatu Saloranta9d1fb752016-06-07 22:47:04 -07001268 }
1269
Tatu Salorantabb06aa02016-09-08 22:38:23 -07001270 /**
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001271 * Helper method used to indicate a problem with input in cases where more
1272 * specific <code>reportXxx()</code> method was not available.
1273 *
1274 * @since 2.9
1275 */
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001276 public <T> T reportInputMismatch(BeanProperty prop,
1277 String msg, Object... msgArgs) throws JsonMappingException
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001278 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001279 msg = _format(msg, msgArgs);
Tatu Salorantab2f6f9e2016-11-29 13:20:29 -08001280 JavaType type = (prop == null) ? null : prop.getType();
1281 throw MismatchedInputException.from(getParser(), type, msg);
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001282 }
1283
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001284 /**
1285 * Helper method used to indicate a problem with input in cases where more
1286 * specific <code>reportXxx()</code> method was not available.
1287 *
1288 * @since 2.9
1289 */
1290 public <T> T reportInputMismatch(JsonDeserializer<?> src,
1291 String msg, Object... msgArgs) throws JsonMappingException
1292 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001293 msg = _format(msg, msgArgs);
Tatu Salorantaa0bd1592016-11-25 18:49:52 -08001294 throw MismatchedInputException.from(getParser(), src.handledType(), msg);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001295 }
1296
1297 /**
1298 * Helper method used to indicate a problem with input in cases where more
1299 * specific <code>reportXxx()</code> method was not available.
1300 *
1301 * @since 2.9
1302 */
1303 public <T> T reportInputMismatch(Class<?> targetType,
1304 String msg, Object... msgArgs) throws JsonMappingException
1305 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001306 msg = _format(msg, msgArgs);
Tatu Salorantaa0bd1592016-11-25 18:49:52 -08001307 throw MismatchedInputException.from(getParser(), targetType, msg);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001308 }
1309
1310 /**
1311 * Helper method used to indicate a problem with input in cases where more
1312 * specific <code>reportXxx()</code> method was not available.
1313 *
1314 * @since 2.9
1315 */
1316 public <T> T reportInputMismatch(JavaType targetType,
1317 String msg, Object... msgArgs) throws JsonMappingException
1318 {
Tatu Saloranta79124862016-10-19 22:13:29 -07001319 msg = _format(msg, msgArgs);
Tatu Salorantaa0bd1592016-11-25 18:49:52 -08001320 throw MismatchedInputException.from(getParser(), targetType, msg);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001321 }
Tatu Salorantab8f60292016-10-25 22:50:06 -07001322
1323 @Deprecated // since 2.9
1324 public void reportWrongTokenException(JsonParser p,
1325 JsonToken expToken, String msg, Object... msgArgs)
1326 throws JsonMappingException
1327 {
1328 msg = _format(msg, msgArgs);
1329 throw wrongTokenException(p, expToken, msg);
1330 }
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001331
Tatu Salorantab8f60292016-10-25 22:50:06 -07001332 /**
1333 * Helper method for reporting a problem with unhandled unknown property.
1334 *
1335 * @param instanceOrClass Either value being populated (if one has been
1336 * instantiated), or Class that indicates type that would be (or
1337 * have been) instantiated
1338 * @param deser Deserializer that had the problem, if called by deserializer
1339 * (or on behalf of one)
1340 *
1341 * @deprecated Since 2.8 call {@link #handleUnknownProperty} instead
1342 */
1343 @Deprecated
1344 public void reportUnknownProperty(Object instanceOrClass, String fieldName,
1345 JsonDeserializer<?> deser)
1346 throws JsonMappingException
1347 {
1348 if (isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
1349 // Do we know properties that are expected instead?
1350 Collection<Object> propIds = (deser == null) ? null : deser.getKnownPropertyNames();
1351 throw UnrecognizedPropertyException.from(_parser,
1352 instanceOrClass, fieldName, propIds);
1353 }
1354 }
1355
1356 /**
1357 * @since 2.8
1358 *
1359 * @deprecated Since 2.9: not clear this ever occurs
1360 */
1361 @Deprecated // since 2.9
1362 public void reportMissingContent(String msg, Object... msgArgs) throws JsonMappingException {
Tatu Salorantaa0bd1592016-11-25 18:49:52 -08001363 throw MismatchedInputException.from(getParser(), (JavaType) null, "No content to map due to end-of-input");
Tatu Salorantab8f60292016-10-25 22:50:06 -07001364 }
1365
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001366 /*
1367 /**********************************************************
1368 /* Methods for problem reporting, in cases where recovery
1369 /* is not considered possible: POJO definition problems
1370 /**********************************************************
1371 */
1372
1373 /**
Tatu Salorantabb06aa02016-09-08 22:38:23 -07001374 * Helper method called to indicate problem in POJO (serialization) definitions or settings
1375 * regarding specific Java type, unrelated to actual JSON content to map.
1376 * Default behavior is to construct and throw a {@link JsonMappingException}.
1377 *
1378 * @since 2.9
1379 */
1380 public <T> T reportBadTypeDefinition(BeanDescription bean,
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001381 String msg, Object... msgArgs) throws JsonMappingException {
1382 msg = _format(msg, msgArgs);
Tatu Salorantae0889202017-03-30 15:43:20 -07001383 String beanDesc = ClassUtil.nameOf(bean.getBeanClass());
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001384 msg = String.format("Invalid type definition for type %s: %s", beanDesc, msg);
1385 throw InvalidDefinitionException.from(_parser, msg, bean, null);
Tatu Salorantabb06aa02016-09-08 22:38:23 -07001386 }
1387
1388 /**
1389 * Helper method called to indicate problem in POJO (serialization) definitions or settings
1390 * regarding specific property (of a type), unrelated to actual JSON content to map.
1391 * Default behavior is to construct and throw a {@link JsonMappingException}.
1392 *
1393 * @since 2.9
1394 */
1395 public <T> T reportBadPropertyDefinition(BeanDescription bean, BeanPropertyDefinition prop,
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001396 String msg, Object... msgArgs) throws JsonMappingException {
1397 msg = _format(msg, msgArgs);
Tatu Saloranta43fbd712016-11-09 21:43:27 -08001398 String propName = ClassUtil.nameOf(prop);
Tatu Salorantae0889202017-03-30 15:43:20 -07001399 String beanDesc = ClassUtil.nameOf(bean.getBeanClass());
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001400 msg = String.format("Invalid definition for property %s (of type %s): %s",
1401 propName, beanDesc, msg);
1402 throw InvalidDefinitionException.from(_parser, msg, bean, prop);
Tatu Salorantabb06aa02016-09-08 22:38:23 -07001403 }
1404
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001405 @Override
1406 public <T> T reportBadDefinition(JavaType type, String msg) throws JsonMappingException {
1407 throw InvalidDefinitionException.from(_parser, msg, type);
Tatu Saloranta851092c2016-05-21 20:08:40 -07001408 }
1409
Tatu Salorantab8f60292016-10-25 22:50:06 -07001410 /**
1411 * Method that deserializer may call if it is called to do an update ("merge")
1412 * but deserializer operates on a non-mergeable type. Although this should
1413 * usually be caught earlier, sometimes it may only be caught during operation
1414 * and if so this is the method to call.
1415 * Note that if {@link MapperFeature#IGNORE_MERGE_FOR_UNMERGEABLE} is enabled,
1416 * this method will simply return null; otherwise {@link InvalidDefinitionException}
1417 * will be thrown.
1418 *
1419 * @since 2.9
1420 */
Tatu Salorantab14a79b2017-04-21 19:06:08 -07001421 public <T> T reportBadMerge(JsonDeserializer<?> deser) throws JsonMappingException
1422 {
Tatu Salorantab8f60292016-10-25 22:50:06 -07001423 if (isEnabled(MapperFeature.IGNORE_MERGE_FOR_UNMERGEABLE)) {
1424 return null;
1425 }
Tatu Salorantab14a79b2017-04-21 19:06:08 -07001426 JavaType type = constructType(deser.handledType());
1427 String msg = String.format("Invalid configuration: values of type %s can not be merged", type);
Tatu Salorantab8f60292016-10-25 22:50:06 -07001428 throw InvalidDefinitionException.from(getParser(), msg, type);
1429 }
1430
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001431 /*
1432 /**********************************************************
1433 /* Methods for constructing semantic exceptions; usually not
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001434 /* to be called directly, call `handleXxx()` instead
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001435 /**********************************************************
1436 */
1437
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001438 /**
Tatu Saloranta68245442016-05-21 18:08:41 -07001439 * Helper method for constructing {@link JsonMappingException} to indicate
Tatu Saloranta98dd0912016-05-15 23:13:44 -07001440 * that the token encountered was of type different than what <b>should</b>
1441 * be seen at that position, usually within a sequence of expected tokens.
1442 * Note that most of the time this method should NOT be directly called;
1443 * instead, {@link #reportWrongTokenException} should be called and will
1444 * call this method as necessary.
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001445 *
1446 * @since 2.9
Tatu Saloranta98dd0912016-05-15 23:13:44 -07001447 */
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001448 public JsonMappingException wrongTokenException(JsonParser p, JavaType targetType,
Tatu Saloranta79124862016-10-19 22:13:29 -07001449 JsonToken expToken, String extra)
Tatu Saloranta98dd0912016-05-15 23:13:44 -07001450 {
1451 String msg = String.format("Unexpected token (%s), expected %s",
1452 p.getCurrentToken(), expToken);
Tatu Saloranta79124862016-10-19 22:13:29 -07001453 msg = _colonConcat(msg, extra);
Tatu Salorantaa0bd1592016-11-25 18:49:52 -08001454 return MismatchedInputException.from(p, targetType, msg);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001455 }
1456
1457 public JsonMappingException wrongTokenException(JsonParser p, Class<?> targetType,
Tatu Saloranta79124862016-10-19 22:13:29 -07001458 JsonToken expToken, String extra)
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001459 {
1460 String msg = String.format("Unexpected token (%s), expected %s",
1461 p.getCurrentToken(), expToken);
Tatu Saloranta79124862016-10-19 22:13:29 -07001462 msg = _colonConcat(msg, extra);
Tatu Salorantaa0bd1592016-11-25 18:49:52 -08001463 return MismatchedInputException.from(p, targetType, msg);
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001464 }
1465
1466 @Deprecated // since 2.9
1467 public JsonMappingException wrongTokenException(JsonParser p, JsonToken expToken,
1468 String msg)
1469 {
1470 return wrongTokenException(p, (JavaType) null, expToken, msg);
Tatu Saloranta98dd0912016-05-15 23:13:44 -07001471 }
1472
1473 /**
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001474 * Helper method for constructing exception to indicate that given JSON
1475 * Object field name was not in format to be able to deserialize specified
1476 * key type.
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001477 * Note that most of the time this method should NOT be called; instead,
1478 * {@link #handleWeirdKey} should be called which will call this method
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001479 * if necessary.
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001480 */
1481 public JsonMappingException weirdKeyException(Class<?> keyClass, String keyValue,
1482 String msg) {
1483 return InvalidFormatException.from(_parser,
1484 String.format("Can not deserialize Map key of type %s from String %s: %s",
Tatu Saloranta267abe12016-11-25 18:14:20 -08001485 ClassUtil.nameOf(keyClass), _quotedString(keyValue), msg),
Tatu Saloranta1e5fd122016-05-09 23:26:30 -07001486 keyValue, keyClass);
1487 }
1488
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001489 /**
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001490 * Helper method for constructing exception to indicate that input JSON
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001491 * String was not suitable for deserializing into given target type.
1492 * Note that most of the time this method should NOT be called; instead,
1493 * {@link #handleWeirdStringValue} should be called which will call this method
1494 * if necessary.
1495 *
1496 * @param value String value from input being deserialized
1497 * @param instClass Type that String should be deserialized into
1498 * @param msg Message that describes specific problem
1499 *
1500 * @since 2.1
1501 */
1502 public JsonMappingException weirdStringException(String value, Class<?> instClass,
1503 String msg) {
1504 return InvalidFormatException.from(_parser,
1505 String.format("Can not deserialize value of type %s from String %s: %s",
Tatu Saloranta267abe12016-11-25 18:14:20 -08001506 ClassUtil.nameOf(instClass), _quotedString(value), msg),
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001507 value, instClass);
1508 }
1509
1510 /**
1511 * Helper method for constructing exception to indicate that input JSON
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001512 * Number was not suitable for deserializing into given target type.
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001513 * Note that most of the time this method should NOT be called; instead,
1514 * {@link #handleWeirdNumberValue} should be called which will call this method
1515 * if necessary.
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001516 */
1517 public JsonMappingException weirdNumberException(Number value, Class<?> instClass,
1518 String msg) {
1519 return InvalidFormatException.from(_parser,
1520 String.format("Can not deserialize value of type %s from number %s: %s",
Tatu Saloranta267abe12016-11-25 18:14:20 -08001521 ClassUtil.nameOf(instClass), String.valueOf(value), msg),
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001522 value, instClass);
1523 }
Tatu Salorantab1041d02016-05-19 08:22:50 -07001524
1525 /**
1526 * Helper method for constructing instantiation exception for specified type,
1527 * to indicate problem with physically constructing instance of
1528 * specified class (missing constructor, exception from constructor)
1529 *<p>
1530 * Note that most of the time this method should NOT be called; instead,
1531 * {@link #handleInstantiationProblem} should be called which will call this method
1532 * if necessary.
1533 */
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001534 public JsonMappingException instantiationException(Class<?> instClass, Throwable cause) {
1535 // Most likely problem with Creator definition, right?
1536 JavaType type = constructType(instClass);
1537 String msg = String.format("Can not construct instance of %s, problem: %s",
Tatu Saloranta267abe12016-11-25 18:14:20 -08001538 ClassUtil.nameOf(instClass), cause.getMessage());
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001539 InvalidDefinitionException e = InvalidDefinitionException.from(_parser, msg, type);
1540 e.initCause(cause);
1541 return e;
Tatu Salorantab1041d02016-05-19 08:22:50 -07001542 }
1543
Tatu Saloranta888c6b92016-05-15 22:16:40 -07001544 /**
Tatu Saloranta68245442016-05-21 18:08:41 -07001545 * Helper method for constructing instantiation exception for specified type,
1546 * to indicate that instantiation failed due to missing instantiator
1547 * (creator; constructor or factory method).
1548 *<p>
1549 * Note that most of the time this method should NOT be called; instead,
1550 * {@link #handleMissingInstantiator} should be called which will call this method
1551 * if necessary.
1552 */
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001553 public JsonMappingException instantiationException(Class<?> instClass, String msg0) {
1554 // Most likely problem with Creator definition, right?
1555 JavaType type = constructType(instClass);
Tatu Saloranta267abe12016-11-25 18:14:20 -08001556 String msg = String.format("Can not construct instance of %s: %s",
1557 ClassUtil.nameOf(instClass), msg0);
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001558 return InvalidDefinitionException.from(_parser, msg, type);
Tatu Saloranta68245442016-05-21 18:08:41 -07001559 }
1560
1561 /**
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001562 * Helper method for constructing exception to indicate that given type id
1563 * could not be resolved to a valid subtype of specified base type, during
1564 * polymorphic deserialization.
Tatu Salorantab1041d02016-05-19 08:22:50 -07001565 *<p>
Tatu Saloranta0b6cb9b2016-05-15 22:59:17 -07001566 * Note that most of the time this method should NOT be called; instead,
1567 * {@link #handleUnknownTypeId} should be called which will call this method
1568 * if necessary.
Tatu Saloranta52238562017-04-28 10:52:23 -07001569 *
1570 * @since 2.9
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001571 */
Tatu Saloranta52238562017-04-28 10:52:23 -07001572 public JsonMappingException invalidTypeIdException(JavaType baseType, String typeId,
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001573 String extraDesc) {
Tatu Saloranta52238562017-04-28 10:52:23 -07001574 String msg = String.format("Could not resolve type id '%s' as a subtype of %s",
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001575 typeId, baseType);
Tatu Saloranta125ac182017-03-09 11:10:02 -08001576 return InvalidTypeIdException.from(_parser, _colonConcat(msg, extraDesc), baseType, typeId);
Tatu Saloranta2d318f62016-05-10 21:58:00 -07001577 }
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001578
Tatu Saloranta5b8f0d92017-03-09 10:18:47 -08001579 /**
1580 * @since 2.9
1581 */
1582 public JsonMappingException missingTypeIdException(JavaType baseType,
1583 String extraDesc) {
1584 String msg = String.format("Missing type id when trying to resolve subtype of %s",
1585 baseType);
Tatu Saloranta125ac182017-03-09 11:10:02 -08001586 return InvalidTypeIdException.from(_parser, _colonConcat(msg, extraDesc), baseType, null);
Tatu Saloranta5b8f0d92017-03-09 10:18:47 -08001587 }
1588
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001589 /*
1590 /**********************************************************
Tatu Saloranta851092c2016-05-21 20:08:40 -07001591 /* Deprecated exception factory methods
Tatu Saloranta34eaa4f2016-05-05 13:11:44 -07001592 /**********************************************************
1593 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001594
Tatu Saloranta7a4193f2016-05-05 12:55:05 -07001595 /**
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001596 * @since 2.5
Tatu Saloranta2ffca932016-05-05 12:23:14 -07001597 *
Tatu Saloranta33ba4ad2016-05-10 20:03:26 -07001598 * @deprecated Since 2.8 use {@link #handleUnknownTypeId} instead
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001599 */
Tatu Saloranta2ffca932016-05-05 12:23:14 -07001600 @Deprecated
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001601 public JsonMappingException unknownTypeException(JavaType type, String id,
Tatu Saloranta43fbd712016-11-09 21:43:27 -08001602 String extraDesc)
1603 {
Tatu Saloranta8c3eb032016-04-20 22:52:38 -07001604 String msg = String.format("Could not resolve type id '%s' into a subtype of %s",
1605 id, type);
Tatu Saloranta79124862016-10-19 22:13:29 -07001606 msg = _colonConcat(msg, extraDesc);
Tatu Salorantaa0bd1592016-11-25 18:49:52 -08001607 return MismatchedInputException.from(_parser, type, msg);
Tatu Saloranta7fc32382014-12-26 17:19:09 -08001608 }
1609
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001610 /**
1611 * Helper method for constructing exception to indicate that end-of-input was
1612 * reached while still expecting more tokens to deserialize value of specified type.
1613 *
1614 * @deprecated Since 2.8; currently no way to catch EOF at databind level
1615 */
1616 @Deprecated
1617 public JsonMappingException endOfInputException(Class<?> instClass) {
Tatu Salorantaa0bd1592016-11-25 18:49:52 -08001618 return MismatchedInputException.from(_parser, instClass,
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001619 "Unexpected end-of-input when trying to deserialize a "+instClass.getName());
Tatu Saloranta1ecc6b52016-05-10 22:18:53 -07001620 }
1621
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001622 /*
1623 /**********************************************************
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001624 /* Deprecated methods for constructing, throwing non-specific
1625 /* JsonMappingExceptions: as of 2.9, should use more specific
1626 /* ones.
1627 /**********************************************************
1628 */
1629
1630 /**
1631 * Fallback method that may be called if no other <code>reportXxx</code>
1632 * is applicable -- but only in that case.
1633 *
1634 * @since 2.8
1635 *
Tatu Salorantad9b0cae2017-04-24 22:49:03 -07001636 * @deprecated Since 2.9: use a more specific method, or {@link #reportBadDefinition(JavaType, String)},
Tatu Salorantafbc1fa22016-10-06 15:07:52 -07001637 * or {@link #reportInputMismatch} instead
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001638 */
1639 @Deprecated // since 2.9
1640 public void reportMappingException(String msg, Object... msgArgs)
1641 throws JsonMappingException
1642 {
Tatu Salorantae27ec2d2016-10-24 22:44:16 -07001643 throw JsonMappingException.from(getParser(), _format(msg, msgArgs));
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001644 }
1645
1646 /**
1647 * Helper method for constructing generic mapping exception with specified
1648 * message and current location information.
1649 * Note that application code should almost always call
1650 * one of <code>handleXxx</code> methods, or {@link #reportMappingException(String, Object...)}
1651 * instead.
1652 *
1653 * @since 2.6
1654 *
1655 * @deprecated Since 2.9 use more specific error reporting methods instead
1656 */
1657 @Deprecated
1658 public JsonMappingException mappingException(String message) {
1659 return JsonMappingException.from(getParser(), message);
1660 }
1661
1662 /**
1663 * Helper method for constructing generic mapping exception with specified
1664 * message and current location information
1665 * Note that application code should almost always call
1666 * one of <code>handleXxx</code> methods, or {@link #reportMappingException(String, Object...)}
1667 * instead.
1668 *
1669 * @since 2.6
1670 *
1671 * @deprecated Since 2.9 use more specific error reporting methods instead
1672 */
1673 @Deprecated
Tatu Saloranta4fc0fb32016-10-20 23:04:31 -07001674 public JsonMappingException mappingException(String msg, Object... msgArgs) {
1675 return JsonMappingException.from(getParser(), _format(msg, msgArgs));
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001676 }
1677
1678 /**
1679 * Helper method for constructing generic mapping exception for specified type
1680 *
1681 * @deprecated Since 2.8 use {@link #handleUnexpectedToken(Class, JsonParser)} instead
1682 */
1683 @Deprecated
1684 public JsonMappingException mappingException(Class<?> targetClass) {
1685 return mappingException(targetClass, _parser.getCurrentToken());
1686 }
1687
1688 /**
1689 * @deprecated Since 2.8 use {@link #handleUnexpectedToken(Class, JsonParser)} instead
1690 */
1691 @Deprecated
1692 public JsonMappingException mappingException(Class<?> targetClass, JsonToken token) {
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001693 return JsonMappingException.from(_parser,
Tatu Saloranta43fbd712016-11-09 21:43:27 -08001694 String.format("Can not deserialize instance of %s out of %s token",
1695 _calcName(targetClass), token));
Tatu Salorantac1478ac2016-09-29 08:17:03 -07001696 }
1697
1698 /*
1699 /**********************************************************
Tatu Saloranta851092c2016-05-21 20:08:40 -07001700 /* Other internal methods
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001701 /**********************************************************
1702 */
1703
1704 protected DateFormat getDateFormat()
1705 {
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -08001706 if (_dateFormat != null) {
1707 return _dateFormat;
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001708 }
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -08001709 /* 24-Feb-2012, tatu: At this point, all timezone configuration
Cowtowncoder8d0d6e42015-01-22 15:36:13 -08001710 * should have occurred, with respect to default dateformat
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -08001711 * and timezone configuration. But we still better clone
1712 * an instance as formatters may be stateful.
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -08001713 */
1714 DateFormat df = _config.getDateFormat();
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -08001715 _dateFormat = df = (DateFormat) df.clone();
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -08001716 return df;
Tatu Saloranta06c20b12012-01-29 21:36:52 -08001717 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001718}