blob: 54c44cb6add14674db5236a6b0649bb6d2e89cd2 [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
8import com.fasterxml.jackson.core.*;
Tatub37ff332012-01-24 16:19:36 -08009
Tatu Saloranta06c20b12012-01-29 21:36:52 -080010import com.fasterxml.jackson.databind.annotation.NoClass;
Tatu9610aff2012-02-02 11:30:08 -080011import com.fasterxml.jackson.databind.cfg.DeserializationConfig;
12import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080013import com.fasterxml.jackson.databind.deser.*;
Tatu Saloranta060ce112012-02-01 22:18:09 -080014import com.fasterxml.jackson.databind.deser.impl.DeserializerCache;
Tatuc3a73d02012-01-31 12:45:49 -080015import com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080016import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
Tatub37ff332012-01-24 16:19:36 -080017import com.fasterxml.jackson.databind.introspect.Annotated;
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;
21import com.fasterxml.jackson.databind.util.ArrayBuilders;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080022import com.fasterxml.jackson.databind.util.ClassUtil;
23import com.fasterxml.jackson.databind.util.LinkedNode;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080024import com.fasterxml.jackson.databind.util.ObjectBuffer;
25
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080026/**
Tatu Saloranta97f84822012-01-29 21:38:40 -080027 * Context for the process of deserialization a single root-level value.
28 * Used to allow passing in configuration settings and reusable temporary
29 * objects (scrap arrays, containers).
Tatu Saloranta060ce112012-02-01 22:18:09 -080030 *<p>
31 * Instance life-cycle is such that an partially configured "blueprint" object
32 * is registered with {@link ObjectMapper} (and {@link ObjectReader},
33 * and when an actual instance is needed for deserialization,
34 * a fully configured instance will
35 * be created using {@link #createInstance}.
36 * Each instance is guaranteed to only be used from single-threaded context;
37 * instances may be reused iff no configuration has changed.
38 *<p>
39 * Defined as abstract class so that implementations must define methods
40 * for reconfiguring blueprints and creating instances.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080041 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080042public abstract class DeserializationContext
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080043{
Tatu Saloranta06c20b12012-01-29 21:36:52 -080044 /**
45 * Let's limit length of error messages, for cases where underlying data
46 * may be very large -- no point in spamming logs with megs of meaningless
47 * data.
48 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080049 private final static int MAX_ERROR_STR_LEN = 500;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080050
Tatu Saloranta060ce112012-02-01 22:18:09 -080051 /*
52 /**********************************************************
53 /* Configuration, immutable
54 /**********************************************************
55 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -080056
Tatu Saloranta060ce112012-02-01 22:18:09 -080057 protected final DeserializerCache _cache;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080058
Tatu Saloranta060ce112012-02-01 22:18:09 -080059 /*
60 /**********************************************************
61 /* Configuration, changeable via fluent factories
62 /**********************************************************
63 */
64
65 /**
66 * Read-only factory instance; exposed to let
67 * owners (<code>ObjectMapper</code>, <code>ObjectReader</code>)
68 * access it.
69 */
70 public final DeserializerFactory _factory;
71
72 /*
73 /**********************************************************
74 /* Configuration that gets set for instances (not blueprints)
75 /**********************************************************
76 */
77
78 protected final DeserializationConfig _config;
79
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080080 protected final int _featureFlags;
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -080081
82 protected final Class<?> _view;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080083
84 /**
85 * Currently active parser used for deserialization.
86 * May be different from the outermost parser
87 * when content is buffered.
88 */
89 protected JsonParser _parser;
Tatuc3a73d02012-01-31 12:45:49 -080090
Tatu Saloranta06c20b12012-01-29 21:36:52 -080091 protected final InjectableValues _injectableValues;
92
Tatu Saloranta060ce112012-02-01 22:18:09 -080093 /*
94 /**********************************************************
95 /* Per-operation reusable helper objects (not for blueprints)
96 /**********************************************************
97 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -080098
99 protected ArrayBuilders _arrayBuilders;
100
101 protected ObjectBuffer _objectBuffer;
102
103 protected DateFormat _dateFormat;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800104
105 /*
106 /**********************************************************
107 /* Life-cycle
108 /**********************************************************
109 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800110
111 protected DeserializationContext(DeserializerFactory df) {
112 this(df, null);
113 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800114
Tatu Saloranta060ce112012-02-01 22:18:09 -0800115 protected DeserializationContext(DeserializerFactory df,
116 DeserializerCache cache)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800117 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800118 if (df == null) {
119 throw new IllegalArgumentException("Can not pass null DeserializerFactory");
120 }
121 _factory = df;
122 _cache = (cache == null) ? new DeserializerCache() : cache;
123
124 _featureFlags = 0;
125 _config = null;
126 _injectableValues = null;
127 _view = null;
128 }
129
130 protected DeserializationContext(DeserializationContext src,
131 DeserializerFactory factory)
132 {
133 _cache = src._cache;
134 _factory = factory;
135
136 _config = src._config;
137 _featureFlags = src._featureFlags;
138 _view = src._view;
139 _parser = src._parser;
140 _injectableValues = src._injectableValues;
141 }
142
143 protected DeserializationContext(DeserializationContext src,
144 DeserializationConfig config, JsonParser jp,
145 InjectableValues injectableValues)
146 {
147 _cache = src._cache;
148 _factory = src._factory;
149
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800150 _config = config;
Tatu Salorantae3ae58e2012-01-28 23:08:16 -0800151 _featureFlags = config.getDeserializationFeatures();
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800152 _view = config.getActiveView();
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800153 _parser = jp;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800154 _injectableValues = injectableValues;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800155 }
156
Tatu Saloranta060ce112012-02-01 22:18:09 -0800157 /**
158 * Fluent factory method used for constructing a blueprint instance
159 * with different factory
160 */
161 public abstract DeserializationContext with(DeserializerFactory factory);
162
163 /**
164 * Method called to create actual usable per-deserialization
165 * context instance.
166 */
167 public abstract DeserializationContext createInstance(DeserializationConfig config,
168 JsonParser jp, InjectableValues values);
169
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800170 /*
171 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800172 /* Public API, accessors
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800173 /**********************************************************
174 */
175
176 /**
177 * Method for accessing configuration setting object for
178 * currently active deserialization.
179 */
180 public DeserializationConfig getConfig() { return _config; }
181
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800182 /**
183 * Convenience method for checking whether specified on/off
184 * feature is enabled
185 */
Tatu9610aff2012-02-02 11:30:08 -0800186 public final boolean isEnabled(DeserializationFeature feat) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800187 /* 03-Dec-2010, tatu: minor shortcut; since this is called quite often,
188 * let's use a local copy of feature settings:
189 */
190 return (_featureFlags & feat.getMask()) != 0;
191 }
192
Tatu9610aff2012-02-02 11:30:08 -0800193 public final boolean isEnabled(MapperFeature feat) {
Tatub37ff332012-01-24 16:19:36 -0800194 return _config.isEnabled(feat);
195 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800196
197 public final AnnotationIntrospector getAnnotationIntrospector() {
198 return _config.getAnnotationIntrospector();
199 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800200
201 /**
202 * Method for accessing the currently active parser.
203 * May be different from the outermost parser
204 * when content is buffered.
205 *<p>
206 * Use of this method is discouraged: if code has direct access
207 * to the active parser, that should be used instead.
208 */
209 public final JsonParser getParser() { return _parser; }
210
211 public final Object findInjectableValue(Object valueId,
212 BeanProperty forProperty, Object beanInstance)
213 {
214 if (_injectableValues == null) {
215 throw new IllegalStateException("No 'injectableValues' configured, can not inject value with id ["+valueId+"]");
216 }
217 return _injectableValues.findInjectableValue(valueId, this, forProperty, beanInstance);
218 }
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800219
Tatu Saloranta060ce112012-02-01 22:18:09 -0800220 /**
221 * Accessor for locating currently active view, if any;
222 * returns null if no view has been set.
223 */
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800224 public final Class<?> getActiveView() {
225 return _view;
226 }
Tatu Saloranta060ce112012-02-01 22:18:09 -0800227
228 /**
229 * Convenience method, functionally equivalent to:
230 *<pre>
231 * getConfig().canOverrideAccessModifiers();
232 * </pre>
233 */
Tatub37ff332012-01-24 16:19:36 -0800234 public final boolean canOverrideAccessModifiers() {
235 return _config.canOverrideAccessModifiers();
236 }
237
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800238 /**
239 * Convenience method for accessing the default Base64 encoding
240 * used for decoding base64 encoded binary content.
241 * Same as calling:
242 *<pre>
243 * getConfig().getBase64Variant();
244 *</pre>
245 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800246 public final Base64Variant getBase64Variant() {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800247 return _config.getBase64Variant();
248 }
249
Tatu Saloranta060ce112012-02-01 22:18:09 -0800250 /**
251 * Convenience method, functionally equivalent to:
252 *<pre>
253 * getConfig().getNodeFactory();
254 * </pre>
255 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800256 public final JsonNodeFactory getNodeFactory() {
257 return _config.getNodeFactory();
258 }
259
Tatu Saloranta060ce112012-02-01 22:18:09 -0800260 /**
261 * Convenience method, functionally equivalent to:
262 *<pre>
263 * getConfig().constructType(cls);
264 * </pre>
265 */
Tatu Salorantabb802d22012-01-23 22:33:09 -0800266 public final JavaType constructType(Class<?> cls) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800267 return _config.constructType(cls);
268 }
269
Tatu Saloranta060ce112012-02-01 22:18:09 -0800270 /**
271 * Convenience method, functionally equivalent to:
272 *<pre>
273 * getConfig().getTypeFactory();
274 * </pre>
275 */
Tatu Salorantabb802d22012-01-23 22:33:09 -0800276 public final TypeFactory getTypeFactory() {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800277 return _config.getTypeFactory();
278 }
279
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800280 /*
281 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800282 /* Public API, pass-through to DeserializerCache
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800283 /**********************************************************
284 */
Tatuc3a73d02012-01-31 12:45:49 -0800285
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800286 /**
Tatu Saloranta060ce112012-02-01 22:18:09 -0800287 * Method for checking whether we could find a deserializer
288 * for given type.
289 */
290 public boolean hasValueDeserializerFor(JavaType type) {
291 return _cache.hasValueDeserializerFor(this, _factory, type);
292 }
293
294
295 /**
Tatuc3a73d02012-01-31 12:45:49 -0800296 * Method for finding a value deserializer, and creating a contextual
297 * version if necessary, for value reached via specified property.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800298 */
Tatuc3a73d02012-01-31 12:45:49 -0800299 @SuppressWarnings("unchecked")
300 public final JsonDeserializer<Object> findContextualValueDeserializer(JavaType type,
301 BeanProperty property) throws JsonMappingException
302 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800303 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this,
304 _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800305 if (deser != null) {
306 if (deser instanceof ContextualDeserializer) {
307 deser = (JsonDeserializer<Object>)((ContextualDeserializer) deser).createContextual(this, property);
308 }
309 }
310 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800311 }
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800312
313 /**
Tatuc3a73d02012-01-31 12:45:49 -0800314 * Method for finding a deserializer for root-level value.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800315 */
Tatuc3a73d02012-01-31 12:45:49 -0800316 @SuppressWarnings("unchecked")
Tatu Saloranta9b9d0432012-01-30 09:20:26 -0800317 public final JsonDeserializer<Object> findRootValueDeserializer(JavaType type)
Tatuc3a73d02012-01-31 12:45:49 -0800318 throws JsonMappingException
319 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800320 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this,
321 _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800322 if (deser == null) { // can this occur?
323 return null;
324 }
325 if (deser instanceof ContextualDeserializer) {
326 deser = (JsonDeserializer<Object>)((ContextualDeserializer) deser).createContextual(this, null);
327 }
328 TypeDeserializer typeDeser = _factory.findTypeDeserializer(_config, type);
329 if (typeDeser != null) {
330 // important: contextualize to indicate this is for root value
331 typeDeser = typeDeser.forProperty(null);
332 return new TypeWrappedDeserializer(typeDeser, deser);
333 }
334 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800335 }
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800336
337 /**
338 * Convenience method, functionally same as:
339 *<pre>
340 * getDeserializerProvider().findKeyDeserializer(getConfig(), propertyType, property);
341 *</pre>
342 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800343 public final KeyDeserializer findKeyDeserializer(JavaType keyType,
344 BeanProperty property) throws JsonMappingException {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800345 KeyDeserializer kd = _cache.findKeyDeserializer(this,
346 _factory, keyType);
Tatud0bb3152012-01-31 13:04:06 -0800347 // Second: contextualize?
348 if (kd instanceof ContextualKeyDeserializer) {
349 kd = ((ContextualKeyDeserializer) kd).createContextual(this, property);
350 }
351 return kd;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800352 }
353
Tatub37ff332012-01-24 16:19:36 -0800354 /*
355 /**********************************************************
356 /* Extended API: handler instantiation
357 /**********************************************************
358 */
359
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800360 @SuppressWarnings("unchecked")
361 public JsonDeserializer<Object> deserializerInstance(Annotated annotated,
Tatuc3a73d02012-01-31 12:45:49 -0800362 Object deserDef)
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800363 throws JsonMappingException
364 {
365 if (deserDef == null) {
366 return null;
367 }
368 JsonDeserializer<?> deser;
369
370 if (deserDef instanceof JsonDeserializer) {
371 deser = (JsonDeserializer<?>) deserDef;
372 } else {
373 /* Alas, there's no way to force return type of "either class
374 * X or Y" -- need to throw an exception after the fact
375 */
376 if (!(deserDef instanceof Class)) {
377 throw new IllegalStateException("AnnotationIntrospector returned deserializer definition of type "+deserDef.getClass().getName()+"; expected type JsonDeserializer or Class<JsonDeserializer> instead");
378 }
379 Class<?> deserClass = (Class<?>)deserDef;
380 // there are some known "no class" markers to consider too:
381 if (deserClass == JsonDeserializer.None.class || deserClass == NoClass.class) {
382 return null;
383 }
384 if (!JsonDeserializer.class.isAssignableFrom(deserClass)) {
385 throw new IllegalStateException("AnnotationIntrospector returned Class "+deserClass.getName()+"; expected Class<JsonDeserializer>");
386 }
387 HandlerInstantiator hi = _config.getHandlerInstantiator();
388 if (hi != null) {
389 deser = hi.deserializerInstance(_config, annotated, deserClass);
390 } else {
391 deser = (JsonDeserializer<?>) ClassUtil.createInstance(deserClass,
392 _config.canOverrideAccessModifiers());
393 }
394 }
395 // First: need to resolve
396 if (deser instanceof ResolvableDeserializer) {
397 ((ResolvableDeserializer) deser).resolve(this);
398 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800399 return (JsonDeserializer<Object>) deser;
400 }
Tatub37ff332012-01-24 16:19:36 -0800401
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800402 public final KeyDeserializer keyDeserializerInstance(Annotated annotated,
Tatud0bb3152012-01-31 13:04:06 -0800403 Object deserDef)
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800404 throws JsonMappingException
405 {
406 if (deserDef == null) {
407 return null;
408 }
409
410 KeyDeserializer deser;
411
412 if (deserDef instanceof KeyDeserializer) {
413 deser = (KeyDeserializer) deserDef;
414 } else {
415 if (!(deserDef instanceof Class)) {
416 throw new IllegalStateException("AnnotationIntrospector returned key deserializer definition of type "
417 +deserDef.getClass().getName()
418 +"; expected type KeyDeserializer or Class<KeyDeserializer> instead");
419 }
420 Class<?> deserClass = (Class<?>)deserDef;
421 // there are some known "no class" markers to consider too:
422 if (deserClass == KeyDeserializer.None.class || deserClass == NoClass.class) {
423 return null;
424 }
425 if (!KeyDeserializer.class.isAssignableFrom(deserClass)) {
426 throw new IllegalStateException("AnnotationIntrospector returned Class "+deserClass.getName()
427 +"; expected Class<KeyDeserializer>");
428 }
429 HandlerInstantiator hi = _config.getHandlerInstantiator();
430 if (hi != null) {
431 deser = hi.keyDeserializerInstance(_config, annotated, deserClass);
432 } else {
433 deser = (KeyDeserializer) ClassUtil.createInstance(deserClass,
434 _config.canOverrideAccessModifiers());
435 }
436 }
437 // First: need to resolve
438 if (deser instanceof ResolvableDeserializer) {
439 ((ResolvableDeserializer) deser).resolve(this);
440 }
Tatud0bb3152012-01-31 13:04:06 -0800441 /*
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800442 // Second: contextualize:
443 if (deser instanceof ContextualKeyDeserializer) {
444 deser = ((ContextualKeyDeserializer) deser).createContextual(this, property);
445 }
Tatud0bb3152012-01-31 13:04:06 -0800446 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800447 return deser;
448 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800449
450 /*
451 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800452 /* Public API, helper object recycling
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800453 /**********************************************************
454 */
455
456 /**
457 * Method that can be used to get access to a reusable ObjectBuffer,
458 * useful for efficiently constructing Object arrays and Lists.
459 * Note that leased buffers should be returned once deserializer
460 * is done, to allow for reuse during same round of deserialization.
461 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800462 public final ObjectBuffer leaseObjectBuffer()
463 {
464 ObjectBuffer buf = _objectBuffer;
465 if (buf == null) {
466 buf = new ObjectBuffer();
467 } else {
468 _objectBuffer = null;
469 }
470 return buf;
471 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800472
473 /**
474 * Method to call to return object buffer previously leased with
475 * {@link #leaseObjectBuffer}.
476 *
477 * @param buf Returned object buffer
478 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800479 public final void returnObjectBuffer(ObjectBuffer buf)
480 {
481 /* Already have a reusable buffer? Let's retain bigger one
482 * (or if equal, favor newer one, shorter life-cycle)
483 */
484 if (_objectBuffer == null
485 || buf.initialCapacity() >= _objectBuffer.initialCapacity()) {
486 _objectBuffer = buf;
487 }
488 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800489
490 /**
491 * Method for accessing object useful for building arrays of
492 * primitive types (such as int[]).
493 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800494 public final ArrayBuilders getArrayBuilders()
495 {
496 if (_arrayBuilders == null) {
497 _arrayBuilders = new ArrayBuilders();
498 }
499 return _arrayBuilders;
500 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800501
502 /*
503 /**********************************************************
504 /* Parsing methods that may use reusable/-cyclable objects
505 /**********************************************************
506 */
507
508 /**
509 * Convenience method for parsing a Date from given String, using
510 * currently configured date format (accessed using
511 * {@link DeserializationConfig#getDateFormat()}).
512 *<p>
513 * Implementation will handle thread-safety issues related to
514 * date formats such that first time this method is called,
515 * date format is cloned, and cloned instance will be retained
516 * for use during this deserialization round.
517 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800518 public Date parseDate(String dateStr)
519 throws IllegalArgumentException
520 {
521 try {
522 return getDateFormat().parse(dateStr);
523 } catch (ParseException pex) {
524 throw new IllegalArgumentException(pex.getMessage());
525 }
526 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800527
528 /**
529 * Convenience method for constructing Calendar instance set
530 * to specified time, to be modified and used by caller.
531 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800532 public Calendar constructCalendar(Date d)
533 {
534 /* 08-Jan-2008, tatu: not optimal, but should work for the
535 * most part; let's revise as needed.
536 */
537 Calendar c = Calendar.getInstance();
538 c.setTime(d);
539 return c;
540 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800541
542 /*
543 /**********************************************************
544 /* Methods for problem handling, reporting
545 /**********************************************************
546 */
547
548 /**
549 * Method deserializers can call to inform configured {@link DeserializationProblemHandler}s
550 * of an unrecognized property.
551 *
552 * @return True if there was a configured problem handler that was able to handle the
Tatu Saloranta0e3b3832012-01-22 22:08:20 -0800553 * problem
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800554 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800555 /**
556 * Method deserializers can call to inform configured {@link DeserializationProblemHandler}s
557 * of an unrecognized property.
558 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800559 public boolean handleUnknownProperty(JsonParser jp, JsonDeserializer<?> deser,
560 Object instanceOrClass, String propName)
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800561 throws IOException, JsonProcessingException
562 {
563 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
564 if (h != null) {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800565 while (h != null) {
566 // Can bail out if it's handled
567 if (h.value().handleUnknownProperty(this, jp, deser, instanceOrClass, propName)) {
568 return true;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800569 }
Tatu Saloranta060ce112012-02-01 22:18:09 -0800570 h = h.next();
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800571 }
572 }
573 return false;
574 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800575
576 /**
577 * Helper method for constructing generic mapping exception for specified type
578 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800579 public JsonMappingException mappingException(Class<?> targetClass) {
580 return mappingException(targetClass, _parser.getCurrentToken());
581 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800582
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800583 public JsonMappingException mappingException(Class<?> targetClass, JsonToken token)
584 {
585 String clsName = _calcName(targetClass);
586 return JsonMappingException.from(_parser, "Can not deserialize instance of "+clsName+" out of "+token+" token");
587 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800588
589 /**
590 * Helper method for constructing generic mapping exception with specified
591 * message and current location information
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800592 */
593 public JsonMappingException mappingException(String message)
594 {
595 return JsonMappingException.from(getParser(), message);
596 }
597
598 /**
599 * Helper method for constructing instantiation exception for specified type,
600 * to indicate problem with physically constructing instance of
601 * specified class (missing constructor, exception from constructor)
602 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800603 public JsonMappingException instantiationException(Class<?> instClass, Throwable t)
604 {
605 return JsonMappingException.from(_parser,
606 "Can not construct instance of "+instClass.getName()+", problem: "+t.getMessage(),
607 t);
608 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800609
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800610 public JsonMappingException instantiationException(Class<?> instClass, String msg)
611 {
612 return JsonMappingException.from(_parser, "Can not construct instance of "+instClass.getName()+", problem: "+msg);
613 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800614
615 /**
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800616 * Method that will construct an exception suitable for throwing when
617 * some String values are acceptable, but the one encountered is not.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800618 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800619 public JsonMappingException weirdStringException(Class<?> instClass, String msg)
620 {
621 return JsonMappingException.from(_parser, "Can not construct instance of "+instClass.getName()+" from String value '"+_valueDesc()+"': "+msg);
622 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800623
624 /**
625 * Helper method for constructing exception to indicate that input JSON
626 * Number was not suitable for deserializing into given type.
627 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800628 public JsonMappingException weirdNumberException(Class<?> instClass, String msg)
629 {
630 return JsonMappingException.from(_parser, "Can not construct instance of "+instClass.getName()+" from number value ("+_valueDesc()+"): "+msg);
631 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800632
633 /**
634 * Helper method for constructing exception to indicate that given JSON
635 * Object field name was not in format to be able to deserialize specified
636 * key type.
637 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800638 public JsonMappingException weirdKeyException(Class<?> keyClass, String keyValue, String msg)
639 {
640 return JsonMappingException.from(_parser, "Can not construct Map key of type "+keyClass.getName()+" from String \""+_desc(keyValue)+"\": "+msg);
641 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800642
643 /**
644 * Helper method for indicating that the current token was expected to be another
645 * token.
646 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800647 public JsonMappingException wrongTokenException(JsonParser jp, JsonToken expToken, String msg)
648 {
649 return JsonMappingException.from(jp, "Unexpected token ("+jp.getCurrentToken()+"), expected "+expToken+": "+msg);
650 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800651
652 /**
653 * Helper method for constructing exception to indicate that JSON Object
654 * field name did not map to a known property of type being
655 * deserialized.
656 *
657 * @param instanceOrClass Either value being populated (if one has been
658 * instantiated), or Class that indicates type that would be (or
659 * have been) instantiated
660 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800661 public JsonMappingException unknownFieldException(Object instanceOrClass, String fieldName)
662 {
663 return UnrecognizedPropertyException.from(_parser, instanceOrClass, fieldName);
664 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800665
666 /**
667 * Helper method for constructing exception to indicate that given
668 * type id (parsed from JSON) could not be converted to a Java type.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800669 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800670 public JsonMappingException unknownTypeException(JavaType type, String id)
671 {
672 return JsonMappingException.from(_parser, "Could not resolve type id '"+id+"' into a subtype of "+type);
673 }
674
675 /*
676 /**********************************************************
677 /* Overridable internal methods
678 /**********************************************************
679 */
680
681 protected DateFormat getDateFormat()
682 {
683 if (_dateFormat == null) {
684 // must create a clone since Formats are not thread-safe:
685 _dateFormat = (DateFormat)_config.getDateFormat().clone();
686 }
687 return _dateFormat;
688 }
689
690 protected String determineClassName(Object instance)
691 {
692 return ClassUtil.getClassDescription(instance);
693 }
694
695 /*
696 /**********************************************************
697 /* Other internal methods
698 /**********************************************************
699 */
700
701 protected String _calcName(Class<?> cls)
702 {
703 if (cls.isArray()) {
704 return _calcName(cls.getComponentType())+"[]";
705 }
706 return cls.getName();
707 }
708
709 protected String _valueDesc()
710 {
711 try {
712 return _desc(_parser.getText());
713 } catch (Exception e) {
714 return "[N/A]";
715 }
716 }
717 protected String _desc(String desc)
718 {
719 // !!! should we quote it? (in case there are control chars, linefeeds)
720 if (desc.length() > MAX_ERROR_STR_LEN) {
721 desc = desc.substring(0, MAX_ERROR_STR_LEN) + "]...[" + desc.substring(desc.length() - MAX_ERROR_STR_LEN);
722 }
723 return desc;
724 }
Tatu Saloranta060ce112012-02-01 22:18:09 -0800725
726 /*
727 /**********************************************************
728 /* Helper classes
729 /**********************************************************
730 */
731
732 /**
733 * Standard implementation, used if no custom context is
734 * implemented.
735 */
736 public final static class Std extends DeserializationContext
737 {
738 /**
739 * Default constructor for a blueprint object, which will use the standard
740 * {@link DeserializerCache}, given factory.
741 */
742 public Std(DeserializerFactory df) {
743 this(df, null);
744 }
745
746 /**
747 * Constructor that will pass specified deserializer factory and
748 * cache: cache may be null (in which case default implementation
749 * will be used), factory can not be null
750 */
751 public Std(DeserializerFactory df, DeserializerCache cache) {
752 super(df, cache);
753 }
754
755 protected Std(Std src, DeserializationConfig config,
756 JsonParser jp, InjectableValues values) {
757 super(src, config, jp, values);
758 }
759
760 protected Std(Std src, DeserializerFactory factory) {
761 super(src, factory);
762 }
763
764 @Override
765 public Std createInstance(DeserializationConfig config,
766 JsonParser jp, InjectableValues values) {
767 return new Std(this, config, jp, values);
768 }
769
770 @Override
771 public Std with(DeserializerFactory factory) {
772 return new Std(this, factory);
773 }
774
775 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800776}