blob: ad1014bdd50d097ca3c98087e288417d63120a01 [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.*;
7
Tatu Salorantad71dffa2012-02-07 21:05:21 -08008import com.fasterxml.jackson.annotation.ObjectIdGenerator;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08009import com.fasterxml.jackson.core.*;
Tatub37ff332012-01-24 16:19:36 -080010
Tatu Saloranta06c20b12012-01-29 21:36:52 -080011import com.fasterxml.jackson.databind.deser.*;
Tatu Saloranta34a8adf2012-02-08 22:07:36 -080012import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId;
Tatuc3a73d02012-01-31 12:45:49 -080013import com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer;
Tatu Salorantadd348562012-07-18 17:25:02 -070014import com.fasterxml.jackson.databind.exc.InvalidFormatException;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080015import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
Tatub37ff332012-01-24 16:19:36 -080016import com.fasterxml.jackson.databind.introspect.Annotated;
Tatu Saloranta557bcd32012-02-10 09:44:51 -080017import com.fasterxml.jackson.databind.introspect.ObjectIdInfo;
Tatuc3a73d02012-01-31 12:45:49 -080018import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
Tatu Saloranta2f823442011-12-23 20:25:27 -080019import com.fasterxml.jackson.databind.node.JsonNodeFactory;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080020import com.fasterxml.jackson.databind.type.TypeFactory;
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -080021import com.fasterxml.jackson.databind.util.*;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080022
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080023/**
Tatu Saloranta97f84822012-01-29 21:38:40 -080024 * Context for the process of deserialization a single root-level value.
25 * Used to allow passing in configuration settings and reusable temporary
26 * objects (scrap arrays, containers).
Tatu Saloranta060ce112012-02-01 22:18:09 -080027 *<p>
28 * Instance life-cycle is such that an partially configured "blueprint" object
29 * is registered with {@link ObjectMapper} (and {@link ObjectReader},
30 * and when an actual instance is needed for deserialization,
31 * a fully configured instance will
Tatu Saloranta71e876b2012-02-05 19:15:48 -080032 * be created using a method in excented API of sub-class
33 * ({@link com.fasterxml.jackson.databind.deser.DefaultDeserializationContext#createInstance}).
Tatu Saloranta060ce112012-02-01 22:18:09 -080034 * Each instance is guaranteed to only be used from single-threaded context;
35 * instances may be reused iff no configuration has changed.
36 *<p>
37 * Defined as abstract class so that implementations must define methods
38 * for reconfiguring blueprints and creating instances.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080039 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080040public abstract class DeserializationContext
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080041{
Tatu Saloranta06c20b12012-01-29 21:36:52 -080042 /**
43 * Let's limit length of error messages, for cases where underlying data
44 * may be very large -- no point in spamming logs with megs of meaningless
45 * data.
46 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080047 private final static int MAX_ERROR_STR_LEN = 500;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080048
Tatu Saloranta060ce112012-02-01 22:18:09 -080049 /*
50 /**********************************************************
51 /* Configuration, immutable
52 /**********************************************************
53 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -080054
Tatu Saloranta71e876b2012-02-05 19:15:48 -080055 /**
56 * Object that handle details of {@link JsonDeserializer} caching.
57 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080058 protected final DeserializerCache _cache;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080059
Tatu Saloranta060ce112012-02-01 22:18:09 -080060 /*
61 /**********************************************************
62 /* Configuration, changeable via fluent factories
63 /**********************************************************
64 */
65
66 /**
67 * Read-only factory instance; exposed to let
68 * owners (<code>ObjectMapper</code>, <code>ObjectReader</code>)
69 * access it.
70 */
Tatu Salorantaaa512742012-02-22 22:51:33 -080071 protected final DeserializerFactory _factory;
72
73 /*
74 /**********************************************************
Tatu Saloranta060ce112012-02-01 22:18:09 -080075 /* Configuration that gets set for instances (not blueprints)
Tatu Saloranta71e876b2012-02-05 19:15:48 -080076 /* (partly denormalized for performance)
Tatu Saloranta060ce112012-02-01 22:18:09 -080077 /**********************************************************
78 */
79
Tatu Saloranta71e876b2012-02-05 19:15:48 -080080 /**
81 * Generic deserialization processing configuration
82 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080083 protected final DeserializationConfig _config;
Tatu Saloranta71e876b2012-02-05 19:15:48 -080084
85 /**
86 * Bitmap of {@link DeserializationFeature}s that are enabled
87 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080088 protected final int _featureFlags;
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -080089
Tatu Saloranta71e876b2012-02-05 19:15:48 -080090 /**
91 * Currently active view, if any.
92 */
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -080093 protected final Class<?> _view;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080094
95 /**
96 * Currently active parser used for deserialization.
97 * May be different from the outermost parser
98 * when content is buffered.
99 */
100 protected JsonParser _parser;
Tatuc3a73d02012-01-31 12:45:49 -0800101
Tatu Saloranta71e876b2012-02-05 19:15:48 -0800102 /**
103 * Object used for resolving references to injectable
104 * values.
105 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800106 protected final InjectableValues _injectableValues;
107
Tatu Saloranta060ce112012-02-01 22:18:09 -0800108 /*
109 /**********************************************************
110 /* Per-operation reusable helper objects (not for blueprints)
111 /**********************************************************
112 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800113
114 protected ArrayBuilders _arrayBuilders;
115
116 protected ObjectBuffer _objectBuffer;
117
118 protected DateFormat _dateFormat;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800119
120 /*
121 /**********************************************************
122 /* Life-cycle
123 /**********************************************************
124 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800125
126 protected DeserializationContext(DeserializerFactory df) {
127 this(df, null);
128 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800129
Tatu Saloranta060ce112012-02-01 22:18:09 -0800130 protected DeserializationContext(DeserializerFactory df,
131 DeserializerCache cache)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800132 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800133 if (df == null) {
134 throw new IllegalArgumentException("Can not pass null DeserializerFactory");
135 }
136 _factory = df;
137 _cache = (cache == null) ? new DeserializerCache() : cache;
138
139 _featureFlags = 0;
140 _config = null;
141 _injectableValues = null;
142 _view = null;
143 }
144
145 protected DeserializationContext(DeserializationContext src,
146 DeserializerFactory factory)
147 {
148 _cache = src._cache;
149 _factory = factory;
150
151 _config = src._config;
152 _featureFlags = src._featureFlags;
153 _view = src._view;
154 _parser = src._parser;
155 _injectableValues = src._injectableValues;
156 }
157
158 protected DeserializationContext(DeserializationContext src,
159 DeserializationConfig config, JsonParser jp,
160 InjectableValues injectableValues)
161 {
162 _cache = src._cache;
163 _factory = src._factory;
164
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800165 _config = config;
Tatu Salorantae3ae58e2012-01-28 23:08:16 -0800166 _featureFlags = config.getDeserializationFeatures();
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800167 _view = config.getActiveView();
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800168 _parser = jp;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800169 _injectableValues = injectableValues;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800170 }
Tatu Saloranta060ce112012-02-01 22:18:09 -0800171
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800172 /*
173 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800174 /* Public API, accessors
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800175 /**********************************************************
176 */
177
178 /**
179 * Method for accessing configuration setting object for
180 * currently active deserialization.
181 */
182 public DeserializationConfig getConfig() { return _config; }
183
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800184 /**
185 * Convenience method for checking whether specified on/off
186 * feature is enabled
187 */
Tatu9610aff2012-02-02 11:30:08 -0800188 public final boolean isEnabled(DeserializationFeature feat) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800189 /* 03-Dec-2010, tatu: minor shortcut; since this is called quite often,
190 * let's use a local copy of feature settings:
191 */
192 return (_featureFlags & feat.getMask()) != 0;
193 }
194
Tatu9610aff2012-02-02 11:30:08 -0800195 public final boolean isEnabled(MapperFeature feat) {
Tatub37ff332012-01-24 16:19:36 -0800196 return _config.isEnabled(feat);
197 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800198
199 public final AnnotationIntrospector getAnnotationIntrospector() {
200 return _config.getAnnotationIntrospector();
201 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800202
203 /**
204 * Method for accessing the currently active parser.
205 * May be different from the outermost parser
206 * when content is buffered.
207 *<p>
208 * Use of this method is discouraged: if code has direct access
209 * to the active parser, that should be used instead.
210 */
211 public final JsonParser getParser() { return _parser; }
212
213 public final Object findInjectableValue(Object valueId,
214 BeanProperty forProperty, Object beanInstance)
215 {
216 if (_injectableValues == null) {
217 throw new IllegalStateException("No 'injectableValues' configured, can not inject value with id ["+valueId+"]");
218 }
219 return _injectableValues.findInjectableValue(valueId, this, forProperty, beanInstance);
220 }
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800221
Tatu Saloranta060ce112012-02-01 22:18:09 -0800222 /**
223 * Accessor for locating currently active view, if any;
224 * returns null if no view has been set.
225 */
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800226 public final Class<?> getActiveView() {
227 return _view;
228 }
Tatu Saloranta060ce112012-02-01 22:18:09 -0800229
230 /**
231 * Convenience method, functionally equivalent to:
232 *<pre>
233 * getConfig().canOverrideAccessModifiers();
234 * </pre>
235 */
Tatub37ff332012-01-24 16:19:36 -0800236 public final boolean canOverrideAccessModifiers() {
237 return _config.canOverrideAccessModifiers();
238 }
239
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800240 /**
241 * Convenience method for accessing the default Base64 encoding
242 * used for decoding base64 encoded binary content.
243 * Same as calling:
244 *<pre>
245 * getConfig().getBase64Variant();
246 *</pre>
247 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800248 public final Base64Variant getBase64Variant() {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800249 return _config.getBase64Variant();
250 }
251
Tatu Saloranta060ce112012-02-01 22:18:09 -0800252 /**
253 * Convenience method, functionally equivalent to:
254 *<pre>
255 * getConfig().getNodeFactory();
256 * </pre>
257 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800258 public final JsonNodeFactory getNodeFactory() {
259 return _config.getNodeFactory();
260 }
261
Tatu Saloranta060ce112012-02-01 22:18:09 -0800262 /**
263 * Convenience method, functionally equivalent to:
264 *<pre>
Tatu Saloranta060ce112012-02-01 22:18:09 -0800265 * getConfig().getTypeFactory();
266 * </pre>
267 */
Tatu Salorantabb802d22012-01-23 22:33:09 -0800268 public final TypeFactory getTypeFactory() {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800269 return _config.getTypeFactory();
270 }
271
Tatu Salorantaaa512742012-02-22 22:51:33 -0800272 /**
Tatu Salorantae6faa452012-02-23 19:44:42 -0800273 * Method for accessing default Locale to use: convenience method for
274 *<pre>
275 * getConfig().getLocale();
276 *</pre>
Tatu Salorantaaa512742012-02-22 22:51:33 -0800277 */
278 public Locale getLocale() {
Tatu Salorantae6faa452012-02-23 19:44:42 -0800279 return _config.getLocale();
Tatu Salorantaaa512742012-02-22 22:51:33 -0800280 }
281
Tatu Salorantae6faa452012-02-23 19:44:42 -0800282 /**
283 * Method for accessing default TimeZone to use: convenience method for
284 *<pre>
285 * getConfig().getTimeZone();
286 *</pre>
287 */
Tatu Salorantaaa512742012-02-22 22:51:33 -0800288 public TimeZone getTimeZone() {
Tatu Salorantae6faa452012-02-23 19:44:42 -0800289 return _config.getTimeZone();
Tatu Salorantaaa512742012-02-22 22:51:33 -0800290 }
291
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800292 /*
293 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800294 /* Public API, pass-through to DeserializerCache
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800295 /**********************************************************
296 */
Tatuc3a73d02012-01-31 12:45:49 -0800297
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800298 /**
Tatu Saloranta060ce112012-02-01 22:18:09 -0800299 * Method for checking whether we could find a deserializer
300 * for given type.
301 */
302 public boolean hasValueDeserializerFor(JavaType type) {
303 return _cache.hasValueDeserializerFor(this, _factory, type);
304 }
305
306
307 /**
Tatuc3a73d02012-01-31 12:45:49 -0800308 * Method for finding a value deserializer, and creating a contextual
309 * version if necessary, for value reached via specified property.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800310 */
Tatuc3a73d02012-01-31 12:45:49 -0800311 @SuppressWarnings("unchecked")
312 public final JsonDeserializer<Object> findContextualValueDeserializer(JavaType type,
313 BeanProperty property) throws JsonMappingException
314 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800315 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this,
316 _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800317 if (deser != null) {
318 if (deser instanceof ContextualDeserializer) {
319 deser = (JsonDeserializer<Object>)((ContextualDeserializer) deser).createContextual(this, property);
320 }
321 }
322 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800323 }
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800324
325 /**
Tatuc3a73d02012-01-31 12:45:49 -0800326 * Method for finding a deserializer for root-level value.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800327 */
Tatuc3a73d02012-01-31 12:45:49 -0800328 @SuppressWarnings("unchecked")
Tatu Saloranta9b9d0432012-01-30 09:20:26 -0800329 public final JsonDeserializer<Object> findRootValueDeserializer(JavaType type)
Tatuc3a73d02012-01-31 12:45:49 -0800330 throws JsonMappingException
331 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800332 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this,
333 _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800334 if (deser == null) { // can this occur?
335 return null;
336 }
337 if (deser instanceof ContextualDeserializer) {
338 deser = (JsonDeserializer<Object>)((ContextualDeserializer) deser).createContextual(this, null);
339 }
340 TypeDeserializer typeDeser = _factory.findTypeDeserializer(_config, type);
341 if (typeDeser != null) {
342 // important: contextualize to indicate this is for root value
343 typeDeser = typeDeser.forProperty(null);
344 return new TypeWrappedDeserializer(typeDeser, deser);
345 }
346 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800347 }
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800348
349 /**
350 * Convenience method, functionally same as:
351 *<pre>
352 * getDeserializerProvider().findKeyDeserializer(getConfig(), propertyType, property);
353 *</pre>
354 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800355 public final KeyDeserializer findKeyDeserializer(JavaType keyType,
356 BeanProperty property) throws JsonMappingException {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800357 KeyDeserializer kd = _cache.findKeyDeserializer(this,
358 _factory, keyType);
Tatud0bb3152012-01-31 13:04:06 -0800359 // Second: contextualize?
360 if (kd instanceof ContextualKeyDeserializer) {
361 kd = ((ContextualKeyDeserializer) kd).createContextual(this, property);
362 }
363 return kd;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800364 }
365
Tatub37ff332012-01-24 16:19:36 -0800366 /*
367 /**********************************************************
Tatu Saloranta34a8adf2012-02-08 22:07:36 -0800368 /* Public API, ObjectId handling
369 /**********************************************************
370 */
371
372 /**
373 * Method called to find and return entry corresponding to given
374 * Object Id: will add an entry if necessary, and never returns null
375 */
376 public abstract ReadableObjectId findObjectId(Object id,
377 ObjectIdGenerator<?> generator);
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800378
379 /*
380 /**********************************************************
381 /* Public API, type handling
382 /**********************************************************
383 */
384
385 /**
386 * Convenience method, functionally equivalent to:
387 *<pre>
388 * getConfig().constructType(cls);
389 * </pre>
390 */
391 public final JavaType constructType(Class<?> cls) {
392 return _config.constructType(cls);
393 }
394
395 /**
396 * Helper method to use for locating Class for given name. Should be used
397 * instead of basic <code>Class.forName(className);</code> as it can
398 * try using contextual class loader, or use platform-specific workarounds
399 * (like on Android, GAE).
400 */
401 public Class<?> findClass(String className) throws ClassNotFoundException
402 {
403 // By default, delegate to ClassUtil: can be overridden with custom handling
404 return ClassUtil.findClass(className);
405 }
Tatu Saloranta34a8adf2012-02-08 22:07:36 -0800406
407 /*
408 /**********************************************************
Tatub37ff332012-01-24 16:19:36 -0800409 /* Extended API: handler instantiation
410 /**********************************************************
411 */
412
Tatu Saloranta557bcd32012-02-10 09:44:51 -0800413 public abstract JsonDeserializer<Object> deserializerInstance(Annotated annotated,
Tatuc3a73d02012-01-31 12:45:49 -0800414 Object deserDef)
Tatu Saloranta557bcd32012-02-10 09:44:51 -0800415 throws JsonMappingException;
Tatub37ff332012-01-24 16:19:36 -0800416
Tatu Saloranta557bcd32012-02-10 09:44:51 -0800417 public abstract KeyDeserializer keyDeserializerInstance(Annotated annotated,
Tatud0bb3152012-01-31 13:04:06 -0800418 Object deserDef)
Tatu Saloranta557bcd32012-02-10 09:44:51 -0800419 throws JsonMappingException;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800420
Tatu Saloranta557bcd32012-02-10 09:44:51 -0800421 public abstract ObjectIdGenerator<?> objectIdGeneratorInstance(Annotated annotated,
422 ObjectIdInfo objectIdInfo)
423 throws JsonMappingException;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800424
425 /*
426 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800427 /* Public API, helper object recycling
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800428 /**********************************************************
429 */
430
431 /**
432 * Method that can be used to get access to a reusable ObjectBuffer,
433 * useful for efficiently constructing Object arrays and Lists.
434 * Note that leased buffers should be returned once deserializer
435 * is done, to allow for reuse during same round of deserialization.
436 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800437 public final ObjectBuffer leaseObjectBuffer()
438 {
439 ObjectBuffer buf = _objectBuffer;
440 if (buf == null) {
441 buf = new ObjectBuffer();
442 } else {
443 _objectBuffer = null;
444 }
445 return buf;
446 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800447
448 /**
449 * Method to call to return object buffer previously leased with
450 * {@link #leaseObjectBuffer}.
451 *
452 * @param buf Returned object buffer
453 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800454 public final void returnObjectBuffer(ObjectBuffer buf)
455 {
456 /* Already have a reusable buffer? Let's retain bigger one
457 * (or if equal, favor newer one, shorter life-cycle)
458 */
459 if (_objectBuffer == null
460 || buf.initialCapacity() >= _objectBuffer.initialCapacity()) {
461 _objectBuffer = buf;
462 }
463 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800464
465 /**
466 * Method for accessing object useful for building arrays of
467 * primitive types (such as int[]).
468 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800469 public final ArrayBuilders getArrayBuilders()
470 {
471 if (_arrayBuilders == null) {
472 _arrayBuilders = new ArrayBuilders();
473 }
474 return _arrayBuilders;
475 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800476
477 /*
478 /**********************************************************
479 /* Parsing methods that may use reusable/-cyclable objects
480 /**********************************************************
481 */
482
483 /**
484 * Convenience method for parsing a Date from given String, using
485 * currently configured date format (accessed using
486 * {@link DeserializationConfig#getDateFormat()}).
487 *<p>
488 * Implementation will handle thread-safety issues related to
489 * date formats such that first time this method is called,
490 * date format is cloned, and cloned instance will be retained
491 * for use during this deserialization round.
492 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800493 public Date parseDate(String dateStr)
494 throws IllegalArgumentException
495 {
496 try {
497 return getDateFormat().parse(dateStr);
Tatu Salorantaaa512742012-02-22 22:51:33 -0800498 } catch (ParseException e) {
499 throw new IllegalArgumentException("Failed to parse Date value '"+dateStr+"': "+e.getMessage());
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800500 }
501 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800502
503 /**
504 * Convenience method for constructing Calendar instance set
505 * to specified time, to be modified and used by caller.
506 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800507 public Calendar constructCalendar(Date d)
508 {
509 /* 08-Jan-2008, tatu: not optimal, but should work for the
510 * most part; let's revise as needed.
511 */
Tatu Salorantaaa512742012-02-22 22:51:33 -0800512 Calendar c = Calendar.getInstance(getTimeZone());
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800513 c.setTime(d);
514 return c;
515 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800516
517 /*
518 /**********************************************************
519 /* Methods for problem handling, reporting
520 /**********************************************************
521 */
522
523 /**
524 * Method deserializers can call to inform configured {@link DeserializationProblemHandler}s
525 * of an unrecognized property.
526 *
527 * @return True if there was a configured problem handler that was able to handle the
Tatu Saloranta0e3b3832012-01-22 22:08:20 -0800528 * problem
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800529 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800530 /**
531 * Method deserializers can call to inform configured {@link DeserializationProblemHandler}s
532 * of an unrecognized property.
533 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800534 public boolean handleUnknownProperty(JsonParser jp, JsonDeserializer<?> deser,
535 Object instanceOrClass, String propName)
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800536 throws IOException, JsonProcessingException
537 {
538 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
539 if (h != null) {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800540 while (h != null) {
541 // Can bail out if it's handled
542 if (h.value().handleUnknownProperty(this, jp, deser, instanceOrClass, propName)) {
543 return true;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800544 }
Tatu Saloranta060ce112012-02-01 22:18:09 -0800545 h = h.next();
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800546 }
547 }
548 return false;
549 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800550
551 /**
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800552 * Helper method for reporting a problem with unhandled unknown exception
553 *
554 * @param instanceOrClass Either value being populated (if one has been
555 * instantiated), or Class that indicates type that would be (or
556 * have been) instantiated
Tatu Saloranta05fce932012-03-19 17:14:05 -0700557 * @param deser Deserializer that had the problem, if called by deserializer
558 * (or on behalf of one)
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800559 */
Tatu Saloranta05fce932012-03-19 17:14:05 -0700560 public void reportUnknownProperty(Object instanceOrClass, String fieldName,
561 JsonDeserializer<?> deser)
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800562 throws JsonMappingException
563 {
Tatu Saloranta05fce932012-03-19 17:14:05 -0700564 if (!isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
565 return;
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800566 }
Tatu Saloranta05fce932012-03-19 17:14:05 -0700567 // Do we know properties that are expected instead?
568 Collection<Object> propIds = (deser == null) ? null : deser.getKnownPropertyNames();
569 throw UnrecognizedPropertyException.from(_parser,
570 instanceOrClass, fieldName, propIds);
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800571 }
572
573 /*
574 /**********************************************************
575 /* Methods for constructing exceptions
576 /**********************************************************
577 */
578
579 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800580 * Helper method for constructing generic mapping exception for specified type
581 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800582 public JsonMappingException mappingException(Class<?> targetClass) {
583 return mappingException(targetClass, _parser.getCurrentToken());
584 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800585
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800586 public JsonMappingException mappingException(Class<?> targetClass, JsonToken token)
587 {
588 String clsName = _calcName(targetClass);
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800589 return JsonMappingException.from(_parser,
590 "Can not deserialize instance of "+clsName+" out of "+token+" token");
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800591 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800592
593 /**
594 * Helper method for constructing generic mapping exception with specified
595 * message and current location information
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800596 */
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800597 public JsonMappingException mappingException(String message) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800598 return JsonMappingException.from(getParser(), message);
599 }
600
601 /**
602 * Helper method for constructing instantiation exception for specified type,
603 * to indicate problem with physically constructing instance of
604 * specified class (missing constructor, exception from constructor)
605 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800606 public JsonMappingException instantiationException(Class<?> instClass, Throwable t)
607 {
608 return JsonMappingException.from(_parser,
609 "Can not construct instance of "+instClass.getName()+", problem: "+t.getMessage(),
610 t);
611 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800612
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800613 public JsonMappingException instantiationException(Class<?> instClass, String msg) {
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800614 return JsonMappingException.from(_parser, "Can not construct instance of "+instClass.getName()+", problem: "+msg);
615 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800616
617 /**
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800618 * Method that will construct an exception suitable for throwing when
619 * some String values are acceptable, but the one encountered is not.
Tatu Salorantadd348562012-07-18 17:25:02 -0700620 *
621 *
622 * @deprecated Since 2.1 should use variant that takes value
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800623 */
Tatu Salorantadd348562012-07-18 17:25:02 -0700624 @Deprecated
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800625 public JsonMappingException weirdStringException(Class<?> instClass, String msg) {
Tatu Salorantadd348562012-07-18 17:25:02 -0700626 return weirdStringException(null, instClass, msg);
627 }
628
629 /**
630 * Method that will construct an exception suitable for throwing when
631 * some String values are acceptable, but the one encountered is not.
632 *
633 * @param value String value from input being deserialized
634 * @param instClass Type that String should be deserialized into
635 * @param msg Message that describes specific problem
636 *
637 * @since 2.1
638 */
639 public JsonMappingException weirdStringException(String value, Class<?> instClass, String msg) {
640 return InvalidFormatException.from(_parser,
641 "Can not construct instance of "+instClass.getName()+" from String value '"+_valueDesc()+"': "+msg,
642 value, instClass);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800643 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800644
645 /**
646 * Helper method for constructing exception to indicate that input JSON
647 * Number was not suitable for deserializing into given type.
648 */
Tatu Salorantadd348562012-07-18 17:25:02 -0700649 @Deprecated
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800650 public JsonMappingException weirdNumberException(Class<?> instClass, String msg) {
Tatu Salorantadd348562012-07-18 17:25:02 -0700651 return weirdStringException(null, instClass, msg);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800652 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800653
654 /**
Tatu Salorantadd348562012-07-18 17:25:02 -0700655 * Helper method for constructing exception to indicate that input JSON
656 * Number was not suitable for deserializing into given target type.
657 */
658 public JsonMappingException weirdNumberException(Number value, Class<?> instClass, String msg) {
659 return InvalidFormatException.from(_parser,
660 "Can not construct instance of "+instClass.getName()+" from number value ("+_valueDesc()+"): "+msg,
661 null, instClass);
662 }
663
664 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800665 * Helper method for constructing exception to indicate that given JSON
666 * Object field name was not in format to be able to deserialize specified
667 * key type.
668 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800669 public JsonMappingException weirdKeyException(Class<?> keyClass, String keyValue, String msg)
670 {
Tatu Salorantadd348562012-07-18 17:25:02 -0700671 return InvalidFormatException.from(_parser,
672 "Can not construct Map key of type "+keyClass.getName()+" from String \""+_desc(keyValue)+"\": "+msg,
673 keyValue, keyClass);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800674 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800675
676 /**
677 * Helper method for indicating that the current token was expected to be another
678 * token.
679 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800680 public JsonMappingException wrongTokenException(JsonParser jp, JsonToken expToken, String msg)
681 {
682 return JsonMappingException.from(jp, "Unexpected token ("+jp.getCurrentToken()+"), expected "+expToken+": "+msg);
683 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800684
685 /**
686 * Helper method for constructing exception to indicate that given
687 * type id (parsed from JSON) could not be converted to a Java type.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800688 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800689 public JsonMappingException unknownTypeException(JavaType type, String id)
690 {
691 return JsonMappingException.from(_parser, "Could not resolve type id '"+id+"' into a subtype of "+type);
692 }
693
694 /*
695 /**********************************************************
696 /* Overridable internal methods
697 /**********************************************************
698 */
699
700 protected DateFormat getDateFormat()
701 {
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -0800702 if (_dateFormat != null) {
703 return _dateFormat;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800704 }
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -0800705 /* 24-Feb-2012, tatu: At this point, all timezone configuration
706 * should have occured, with respect to default dateformat
707 * and timezone configuration. But we still better clone
708 * an instance as formatters may be stateful.
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -0800709 */
710 DateFormat df = _config.getDateFormat();
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -0800711 _dateFormat = df = (DateFormat) df.clone();
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -0800712 return df;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800713 }
714
715 protected String determineClassName(Object instance)
716 {
717 return ClassUtil.getClassDescription(instance);
718 }
719
720 /*
721 /**********************************************************
722 /* Other internal methods
723 /**********************************************************
724 */
725
726 protected String _calcName(Class<?> cls)
727 {
728 if (cls.isArray()) {
729 return _calcName(cls.getComponentType())+"[]";
730 }
731 return cls.getName();
732 }
733
734 protected String _valueDesc()
735 {
736 try {
737 return _desc(_parser.getText());
738 } catch (Exception e) {
739 return "[N/A]";
740 }
741 }
742 protected String _desc(String desc)
743 {
744 // !!! should we quote it? (in case there are control chars, linefeeds)
745 if (desc.length() > MAX_ERROR_STR_LEN) {
746 desc = desc.substring(0, MAX_ERROR_STR_LEN) + "]...[" + desc.substring(desc.length() - MAX_ERROR_STR_LEN);
747 }
748 return desc;
749 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800750}