blob: 72d6dd8b2809fb8502c9df7005122567ba60d88e [file] [log] [blame]
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001package com.fasterxml.jackson.databind;
2
3import java.io.IOException;
Tatu Saloranta06c20b12012-01-29 21:36:52 -08004import java.text.DateFormat;
5import java.text.ParseException;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08006import java.util.*;
Tatu Salorantaaf263c32013-10-24 16:18:50 -07007import java.util.concurrent.atomic.AtomicReference;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08008
Tatu Salorantad71dffa2012-02-07 21:05:21 -08009import com.fasterxml.jackson.annotation.ObjectIdGenerator;
Pascal GĂ©linas184cae32014-02-05 17:35:56 -050010import com.fasterxml.jackson.annotation.ObjectIdResolver;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080011import com.fasterxml.jackson.core.*;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -070012import com.fasterxml.jackson.databind.cfg.ContextAttributes;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080013import com.fasterxml.jackson.databind.deser.*;
Tatu Saloranta34a8adf2012-02-08 22:07:36 -080014import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId;
Tatuc3a73d02012-01-31 12:45:49 -080015import com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer;
Tatu Salorantadd348562012-07-18 17:25:02 -070016import com.fasterxml.jackson.databind.exc.InvalidFormatException;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080017import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
Tatub37ff332012-01-24 16:19:36 -080018import com.fasterxml.jackson.databind.introspect.Annotated;
Tatuc3a73d02012-01-31 12:45:49 -080019import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
Tatu Saloranta2f823442011-12-23 20:25:27 -080020import com.fasterxml.jackson.databind.node.JsonNodeFactory;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080021import com.fasterxml.jackson.databind.type.TypeFactory;
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -080022import com.fasterxml.jackson.databind.util.*;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080023
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080024/**
Tatu Saloranta97f84822012-01-29 21:38:40 -080025 * Context for the process of deserialization a single root-level value.
26 * Used to allow passing in configuration settings and reusable temporary
27 * objects (scrap arrays, containers).
Tatu Saloranta060ce112012-02-01 22:18:09 -080028 *<p>
29 * Instance life-cycle is such that an partially configured "blueprint" object
30 * is registered with {@link ObjectMapper} (and {@link ObjectReader},
31 * and when an actual instance is needed for deserialization,
32 * a fully configured instance will
Tatu Saloranta71e876b2012-02-05 19:15:48 -080033 * be created using a method in excented API of sub-class
34 * ({@link com.fasterxml.jackson.databind.deser.DefaultDeserializationContext#createInstance}).
Tatu Saloranta060ce112012-02-01 22:18:09 -080035 * Each instance is guaranteed to only be used from single-threaded context;
36 * instances may be reused iff no configuration has changed.
37 *<p>
38 * Defined as abstract class so that implementations must define methods
39 * for reconfiguring blueprints and creating instances.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080040 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080041public abstract class DeserializationContext
Tatu Saloranta9439a312013-03-02 13:13:09 -080042 extends DatabindContext
Tatu Saloranta0e114112012-10-06 10:45:41 -070043 implements java.io.Serializable
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080044{
Tatu Saloranta953eab22014-05-15 21:35:28 -070045 private static final long serialVersionUID = -4290063686213707727L;
Tatu Saloranta0e114112012-10-06 10:45:41 -070046
Tatu Saloranta06c20b12012-01-29 21:36:52 -080047 /**
48 * Let's limit length of error messages, for cases where underlying data
49 * may be very large -- no point in spamming logs with megs of meaningless
50 * data.
51 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080052 private final static int MAX_ERROR_STR_LEN = 500;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080053
Tatu Saloranta060ce112012-02-01 22:18:09 -080054 /*
55 /**********************************************************
56 /* Configuration, immutable
57 /**********************************************************
58 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -080059
Tatu Saloranta71e876b2012-02-05 19:15:48 -080060 /**
61 * Object that handle details of {@link JsonDeserializer} caching.
62 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080063 protected final DeserializerCache _cache;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080064
Tatu Saloranta060ce112012-02-01 22:18:09 -080065 /*
66 /**********************************************************
67 /* Configuration, changeable via fluent factories
68 /**********************************************************
69 */
70
71 /**
72 * Read-only factory instance; exposed to let
73 * owners (<code>ObjectMapper</code>, <code>ObjectReader</code>)
74 * access it.
75 */
Tatu Salorantaaa512742012-02-22 22:51:33 -080076 protected final DeserializerFactory _factory;
77
78 /*
79 /**********************************************************
Tatu Saloranta060ce112012-02-01 22:18:09 -080080 /* Configuration that gets set for instances (not blueprints)
Tatu Saloranta71e876b2012-02-05 19:15:48 -080081 /* (partly denormalized for performance)
Tatu Saloranta060ce112012-02-01 22:18:09 -080082 /**********************************************************
83 */
84
Tatu Saloranta71e876b2012-02-05 19:15:48 -080085 /**
86 * Generic deserialization processing configuration
87 */
Tatu Saloranta060ce112012-02-01 22:18:09 -080088 protected final DeserializationConfig _config;
Tatu Saloranta71e876b2012-02-05 19:15:48 -080089
90 /**
91 * Bitmap of {@link DeserializationFeature}s that are enabled
92 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080093 protected final int _featureFlags;
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -080094
Tatu Saloranta71e876b2012-02-05 19:15:48 -080095 /**
96 * Currently active view, if any.
97 */
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -080098 protected final Class<?> _view;
Tatu Saloranta06c20b12012-01-29 21:36:52 -080099
100 /**
101 * Currently active parser used for deserialization.
102 * May be different from the outermost parser
103 * when content is buffered.
104 */
Tatu Salorantaf5211582012-10-05 17:09:47 -0700105 protected transient JsonParser _parser;
Tatuc3a73d02012-01-31 12:45:49 -0800106
Tatu Saloranta71e876b2012-02-05 19:15:48 -0800107 /**
108 * Object used for resolving references to injectable
109 * values.
110 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800111 protected final InjectableValues _injectableValues;
112
Tatu Saloranta060ce112012-02-01 22:18:09 -0800113 /*
114 /**********************************************************
115 /* Per-operation reusable helper objects (not for blueprints)
116 /**********************************************************
117 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800118
Tatu Salorantaf5211582012-10-05 17:09:47 -0700119 protected transient ArrayBuilders _arrayBuilders;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800120
Tatu Salorantaf5211582012-10-05 17:09:47 -0700121 protected transient ObjectBuffer _objectBuffer;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800122
Tatu Salorantaf5211582012-10-05 17:09:47 -0700123 protected transient DateFormat _dateFormat;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700124
125 /**
126 * Lazily-constructed holder for per-call attributes.
127 *
128 * @since 2.3
129 */
130 protected transient ContextAttributes _attributes;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800131
132 /*
133 /**********************************************************
134 /* Life-cycle
135 /**********************************************************
136 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800137
138 protected DeserializationContext(DeserializerFactory df) {
139 this(df, null);
140 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800141
Tatu Saloranta060ce112012-02-01 22:18:09 -0800142 protected DeserializationContext(DeserializerFactory df,
143 DeserializerCache cache)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800144 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800145 if (df == null) {
146 throw new IllegalArgumentException("Can not pass null DeserializerFactory");
147 }
148 _factory = df;
149 _cache = (cache == null) ? new DeserializerCache() : cache;
150
151 _featureFlags = 0;
152 _config = null;
153 _injectableValues = null;
154 _view = null;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700155 _attributes = null;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800156 }
157
158 protected DeserializationContext(DeserializationContext src,
159 DeserializerFactory factory)
160 {
161 _cache = src._cache;
162 _factory = factory;
163
164 _config = src._config;
165 _featureFlags = src._featureFlags;
166 _view = src._view;
167 _parser = src._parser;
168 _injectableValues = src._injectableValues;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700169 _attributes = src._attributes;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800170 }
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700171
172 /**
173 * Constructor used for creating actual per-call instances.
174 */
Tatu Saloranta060ce112012-02-01 22:18:09 -0800175 protected DeserializationContext(DeserializationContext src,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700176 DeserializationConfig config, JsonParser p,
Tatu Saloranta060ce112012-02-01 22:18:09 -0800177 InjectableValues injectableValues)
178 {
179 _cache = src._cache;
180 _factory = src._factory;
181
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800182 _config = config;
Tatu Salorantae3ae58e2012-01-28 23:08:16 -0800183 _featureFlags = config.getDeserializationFeatures();
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800184 _view = config.getActiveView();
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700185 _parser = p;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800186 _injectableValues = injectableValues;
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700187 _attributes = config.getAttributes();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800188 }
Tatu Saloranta9439a312013-03-02 13:13:09 -0800189
Tatu Saloranta23328aa2014-10-28 22:38:15 -0700190 /**
191 * Copy-constructor for use with <code>copy()</code> by {@link ObjectMapper#copy()}
192 */
193 protected DeserializationContext(DeserializationContext src) {
194 _cache = new DeserializerCache();
195 _factory = src._factory;
196
197 _config = src._config;
198 _featureFlags = src._featureFlags;
199 _view = src._view;
200 _injectableValues = null;
201 }
202
Tatu Saloranta9439a312013-03-02 13:13:09 -0800203 /*
204 /**********************************************************
205 /* DatabindContext implementation
206 /**********************************************************
207 */
208
209 @Override
210 public DeserializationConfig getConfig() { return _config; }
211
212 @Override
213 public final Class<?> getActiveView() { return _view; }
214
215 @Override
216 public final AnnotationIntrospector getAnnotationIntrospector() {
217 return _config.getAnnotationIntrospector();
218 }
219
220 @Override
221 public final TypeFactory getTypeFactory() {
222 return _config.getTypeFactory();
223 }
Tatu Saloranta2f26e6a2013-10-06 22:05:32 -0700224
225 /*
226 /**********************************************************
227 /* Generic attributes (2.3+)
228 /**********************************************************
229 */
230
231 @Override
232 public Object getAttribute(Object key) {
233 return _attributes.getAttribute(key);
234 }
235
236 @Override
237 public DeserializationContext setAttribute(Object key, Object value)
238 {
239 _attributes = _attributes.withPerCallAttribute(key, value);
240 return this;
241 }
Tatu Saloranta060ce112012-02-01 22:18:09 -0800242
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800243 /*
244 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800245 /* Public API, accessors
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800246 /**********************************************************
247 */
248
249 /**
Dmitry Katsuboe70c66f2012-09-03 16:00:30 +0200250 * Method for getting current {@link DeserializerFactory}.
251 */
252 public DeserializerFactory getFactory() {
253 return _factory;
254 }
Tatu Saloranta9439a312013-03-02 13:13:09 -0800255
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800256 /**
257 * Convenience method for checking whether specified on/off
258 * feature is enabled
259 */
Tatu9610aff2012-02-02 11:30:08 -0800260 public final boolean isEnabled(DeserializationFeature feat) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800261 /* 03-Dec-2010, tatu: minor shortcut; since this is called quite often,
262 * let's use a local copy of feature settings:
263 */
264 return (_featureFlags & feat.getMask()) != 0;
265 }
266
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800267 /**
Tatu Saloranta0ac36ba2013-08-21 18:08:51 -0700268 * "Bulk" access method for checking that all features specified by
269 * mask are enabled.
270 *
271 * @since 2.3
272 */
273 public final boolean hasDeserializationFeatures(int featureMask) {
274 return _config.hasDeserializationFeatures(featureMask);
275 }
276
277 /**
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800278 * Method for accessing the currently active parser.
279 * May be different from the outermost parser
280 * when content is buffered.
281 *<p>
282 * Use of this method is discouraged: if code has direct access
283 * to the active parser, that should be used instead.
284 */
285 public final JsonParser getParser() { return _parser; }
286
287 public final Object findInjectableValue(Object valueId,
288 BeanProperty forProperty, Object beanInstance)
289 {
290 if (_injectableValues == null) {
291 throw new IllegalStateException("No 'injectableValues' configured, can not inject value with id ["+valueId+"]");
292 }
293 return _injectableValues.findInjectableValue(valueId, this, forProperty, beanInstance);
294 }
Tatu Salorantab2d3c7d2012-01-27 21:41:48 -0800295
Tatu Saloranta060ce112012-02-01 22:18:09 -0800296 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800297 * Convenience method for accessing the default Base64 encoding
298 * used for decoding base64 encoded binary content.
299 * Same as calling:
300 *<pre>
301 * getConfig().getBase64Variant();
302 *</pre>
303 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800304 public final Base64Variant getBase64Variant() {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800305 return _config.getBase64Variant();
306 }
307
Tatu Saloranta060ce112012-02-01 22:18:09 -0800308 /**
309 * Convenience method, functionally equivalent to:
310 *<pre>
311 * getConfig().getNodeFactory();
312 * </pre>
313 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800314 public final JsonNodeFactory getNodeFactory() {
315 return _config.getNodeFactory();
316 }
317
Tatu Saloranta060ce112012-02-01 22:18:09 -0800318 /**
Tatu Salorantae6faa452012-02-23 19:44:42 -0800319 * Method for accessing default Locale to use: convenience method for
320 *<pre>
321 * getConfig().getLocale();
322 *</pre>
Tatu Salorantaaa512742012-02-22 22:51:33 -0800323 */
324 public Locale getLocale() {
Tatu Salorantae6faa452012-02-23 19:44:42 -0800325 return _config.getLocale();
Tatu Salorantaaa512742012-02-22 22:51:33 -0800326 }
327
Tatu Salorantae6faa452012-02-23 19:44:42 -0800328 /**
329 * Method for accessing default TimeZone to use: convenience method for
330 *<pre>
331 * getConfig().getTimeZone();
332 *</pre>
333 */
Tatu Salorantaaa512742012-02-22 22:51:33 -0800334 public TimeZone getTimeZone() {
Tatu Salorantae6faa452012-02-23 19:44:42 -0800335 return _config.getTimeZone();
Tatu Salorantaaa512742012-02-22 22:51:33 -0800336 }
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700337
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800338 /*
339 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800340 /* Public API, pass-through to DeserializerCache
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800341 /**********************************************************
342 */
Tatuc3a73d02012-01-31 12:45:49 -0800343
Tatu Salorantaaf263c32013-10-24 16:18:50 -0700344 @Deprecated // since 2.3, use overloaded variant
345 public boolean hasValueDeserializerFor(JavaType type) {
346 return hasValueDeserializerFor(type, null);
347 }
348
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800349 /**
Tatu Saloranta060ce112012-02-01 22:18:09 -0800350 * Method for checking whether we could find a deserializer
351 * for given type.
Tatu Salorantaaf263c32013-10-24 16:18:50 -0700352 *
353 * @param type
354 * @since 2.3
Tatu Saloranta060ce112012-02-01 22:18:09 -0800355 */
Tatu Salorantaaf263c32013-10-24 16:18:50 -0700356 public boolean hasValueDeserializerFor(JavaType type, AtomicReference<Throwable> cause) {
357 try {
358 return _cache.hasValueDeserializerFor(this, _factory, type);
359 } catch (JsonMappingException e) {
360 if (cause != null) {
361 cause.set(e);
362 }
363 } catch (RuntimeException e) {
364 if (cause == null) { // earlier behavior
365 throw e;
366 }
367 cause.set(e);
368 }
369 return false;
Tatu Saloranta060ce112012-02-01 22:18:09 -0800370 }
371
Tatu Saloranta060ce112012-02-01 22:18:09 -0800372 /**
Tatuc3a73d02012-01-31 12:45:49 -0800373 * Method for finding a value deserializer, and creating a contextual
374 * version if necessary, for value reached via specified property.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800375 */
Tatuc3a73d02012-01-31 12:45:49 -0800376 @SuppressWarnings("unchecked")
377 public final JsonDeserializer<Object> findContextualValueDeserializer(JavaType type,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700378 BeanProperty prop) throws JsonMappingException
Tatuc3a73d02012-01-31 12:45:49 -0800379 {
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700380 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this, _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800381 if (deser != null) {
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700382 deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, prop);
Tatuc3a73d02012-01-31 12:45:49 -0800383 }
384 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800385 }
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700386
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800387 /**
Tatuc3a73d02012-01-31 12:45:49 -0800388 * Method for finding a deserializer for root-level value.
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800389 */
Tatuc3a73d02012-01-31 12:45:49 -0800390 @SuppressWarnings("unchecked")
Tatu Saloranta9b9d0432012-01-30 09:20:26 -0800391 public final JsonDeserializer<Object> findRootValueDeserializer(JavaType type)
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700392 throws JsonMappingException
Tatuc3a73d02012-01-31 12:45:49 -0800393 {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800394 JsonDeserializer<Object> deser = _cache.findValueDeserializer(this,
395 _factory, type);
Tatuc3a73d02012-01-31 12:45:49 -0800396 if (deser == null) { // can this occur?
397 return null;
398 }
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700399 deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, null);
Tatuc3a73d02012-01-31 12:45:49 -0800400 TypeDeserializer typeDeser = _factory.findTypeDeserializer(_config, type);
401 if (typeDeser != null) {
402 // important: contextualize to indicate this is for root value
403 typeDeser = typeDeser.forProperty(null);
404 return new TypeWrappedDeserializer(typeDeser, deser);
405 }
406 return deser;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800407 }
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800408
409 /**
410 * Convenience method, functionally same as:
411 *<pre>
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700412 * getDeserializerProvider().findKeyDeserializer(getConfig(), prop.getType(), prop);
Tatu Salorantae8dc6032012-01-23 22:43:26 -0800413 *</pre>
414 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800415 public final KeyDeserializer findKeyDeserializer(JavaType keyType,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700416 BeanProperty prop) throws JsonMappingException {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800417 KeyDeserializer kd = _cache.findKeyDeserializer(this,
418 _factory, keyType);
Tatud0bb3152012-01-31 13:04:06 -0800419 // Second: contextualize?
420 if (kd instanceof ContextualKeyDeserializer) {
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700421 kd = ((ContextualKeyDeserializer) kd).createContextual(this, prop);
Tatud0bb3152012-01-31 13:04:06 -0800422 }
423 return kd;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800424 }
425
Tatub37ff332012-01-24 16:19:36 -0800426 /*
427 /**********************************************************
Tatu Saloranta34a8adf2012-02-08 22:07:36 -0800428 /* Public API, ObjectId handling
429 /**********************************************************
430 */
431
432 /**
433 * Method called to find and return entry corresponding to given
434 * Object Id: will add an entry if necessary, and never returns null
435 */
Pascal GĂ©linas184cae32014-02-05 17:35:56 -0500436 public abstract ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator, ObjectIdResolver resolver);
437
Tatu Saloranta301ea2d2014-03-16 22:26:12 -0700438 @Deprecated // since 2.4
Pascal GĂ©linas184cae32014-02-05 17:35:56 -0500439 public abstract ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator);
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800440
Pascal GĂ©linas096e02b2013-12-18 17:21:42 -0500441 /**
442 * Method called to ensure that every object id encounter during processing
443 * are resolved.
444 *
445 * @throws UnresolvedForwardReference
446 */
447 public abstract void checkUnresolvedObjectId()
448 throws UnresolvedForwardReference;
449
Tatu Salorantabf5e0fa2012-03-08 21:45:30 -0800450 /*
451 /**********************************************************
452 /* Public API, type handling
453 /**********************************************************
454 */
455
456 /**
457 * Convenience method, functionally equivalent to:
458 *<pre>
459 * getConfig().constructType(cls);
460 * </pre>
461 */
462 public final JavaType constructType(Class<?> cls) {
463 return _config.constructType(cls);
464 }
465
466 /**
467 * Helper method to use for locating Class for given name. Should be used
468 * instead of basic <code>Class.forName(className);</code> as it can
469 * try using contextual class loader, or use platform-specific workarounds
470 * (like on Android, GAE).
471 */
472 public Class<?> findClass(String className) throws ClassNotFoundException
473 {
474 // By default, delegate to ClassUtil: can be overridden with custom handling
475 return ClassUtil.findClass(className);
476 }
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800477
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800478 /*
479 /**********************************************************
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800480 /* Public API, helper object recycling
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800481 /**********************************************************
482 */
483
484 /**
485 * Method that can be used to get access to a reusable ObjectBuffer,
486 * useful for efficiently constructing Object arrays and Lists.
487 * Note that leased buffers should be returned once deserializer
488 * is done, to allow for reuse during same round of deserialization.
489 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800490 public final ObjectBuffer leaseObjectBuffer()
491 {
492 ObjectBuffer buf = _objectBuffer;
493 if (buf == null) {
494 buf = new ObjectBuffer();
495 } else {
496 _objectBuffer = null;
497 }
498 return buf;
499 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800500
501 /**
502 * Method to call to return object buffer previously leased with
503 * {@link #leaseObjectBuffer}.
504 *
505 * @param buf Returned object buffer
506 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800507 public final void returnObjectBuffer(ObjectBuffer buf)
508 {
509 /* Already have a reusable buffer? Let's retain bigger one
510 * (or if equal, favor newer one, shorter life-cycle)
511 */
512 if (_objectBuffer == null
513 || buf.initialCapacity() >= _objectBuffer.initialCapacity()) {
514 _objectBuffer = buf;
515 }
516 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800517
518 /**
519 * Method for accessing object useful for building arrays of
520 * primitive types (such as int[]).
521 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800522 public final ArrayBuilders getArrayBuilders()
523 {
524 if (_arrayBuilders == null) {
525 _arrayBuilders = new ArrayBuilders();
526 }
527 return _arrayBuilders;
528 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800529
530 /*
531 /**********************************************************
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700532 /* Extended API: handler instantiation
533 /**********************************************************
534 */
535
536 public abstract JsonDeserializer<Object> deserializerInstance(Annotated annotated,
537 Object deserDef)
538 throws JsonMappingException;
539
540 public abstract KeyDeserializer keyDeserializerInstance(Annotated annotated,
541 Object deserDef)
542 throws JsonMappingException;
543
544 /*
545 /**********************************************************
546 /* Extended API: resolving contextual deserializers; called
547 /* by structured deserializers for their value/component
548 /* deserializers
549 /**********************************************************
550 */
551
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700552 /**
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700553 * Method called for primary property deserializers (ones
Tatu Saloranta59fe29c2013-09-05 22:37:06 -0700554 * directly created to deserialize values of a POJO property),
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700555 * to handle details of resolving
556 * {@link ContextualDeserializer} with given property context.
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700557 *
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700558 * @param prop Property for which the given primary deserializer is used; never null.
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700559 *
560 * @since 2.3
561 */
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700562 public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> deser,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700563 BeanProperty prop)
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700564 throws JsonMappingException
565 {
Tatu Saloranta47ac6bd2013-09-05 20:55:00 -0700566 if (deser != null) {
567 if (deser instanceof ContextualDeserializer) {
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700568 deser = ((ContextualDeserializer) deser).createContextual(this, prop);
Tatu Saloranta47ac6bd2013-09-05 20:55:00 -0700569 }
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700570 }
571 return deser;
572 }
Tatu Salorantab530c4d2013-09-04 22:20:13 -0700573
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700574 /**
575 * Method called for secondary property deserializers (ones
576 * NOT directly created to deal with an annotatable POJO property,
577 * but instead created as a component -- such as value deserializers
578 * for structured types, or deserializers for root values)
579 * to handle details of resolving
580 * {@link ContextualDeserializer} with given property context.
Tatu Saloranta59fe29c2013-09-05 22:37:06 -0700581 * Given that these deserializers are not directly related to given property
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700582 * (or, in case of root value property, to any property), annotations
583 * accessible may or may not be relevant.
584 *
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700585 * @param prop Property for which deserializer is used, if any; null
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700586 * when deserializing root values
587 *
588 * @since 2.3
589 */
590 public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?> deser,
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700591 BeanProperty prop)
592 throws JsonMappingException {
593 if (deser != null && (deser instanceof ContextualDeserializer)) {
594 deser = ((ContextualDeserializer) deser).createContextual(this, prop);
Tatu Saloranta4f90dbc2013-09-05 21:45:53 -0700595 }
596 return deser;
597 }
598
Tatu Salorantaf72fe212013-09-04 22:07:32 -0700599 /*
600 /**********************************************************
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800601 /* Parsing methods that may use reusable/-cyclable objects
602 /**********************************************************
603 */
604
605 /**
606 * Convenience method for parsing a Date from given String, using
607 * currently configured date format (accessed using
608 * {@link DeserializationConfig#getDateFormat()}).
609 *<p>
610 * Implementation will handle thread-safety issues related to
611 * date formats such that first time this method is called,
612 * date format is cloned, and cloned instance will be retained
613 * for use during this deserialization round.
614 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700615 public Date parseDate(String dateStr) throws IllegalArgumentException
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800616 {
617 try {
Tatu Salorantaef00ac62013-11-03 09:56:39 -0800618 DateFormat df = getDateFormat();
619 return df.parse(dateStr);
Tatu Salorantaaa512742012-02-22 22:51:33 -0800620 } catch (ParseException e) {
621 throw new IllegalArgumentException("Failed to parse Date value '"+dateStr+"': "+e.getMessage());
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800622 }
623 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800624
625 /**
626 * Convenience method for constructing Calendar instance set
627 * to specified time, to be modified and used by caller.
628 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700629 public Calendar constructCalendar(Date d) {
630 // 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 -0800631 Calendar c = Calendar.getInstance(getTimeZone());
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800632 c.setTime(d);
633 return c;
634 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800635
636 /*
637 /**********************************************************
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700638 /* Convenience methods for reading parsed values
639 /**********************************************************
640 */
641
642 /**
643 * Convenience method that may be used by composite or container deserializers,
644 * for reading one-off values contained (for sequences, it is more efficient
645 * to actually fetch deserializer once for the whole collection).
646 *<p>
647 * NOTE: when deserializing values of properties contained in composite types,
648 * rather use {@link #readPropertyValue(JsonParser, BeanProperty, Class)};
649 * this method does not allow use of contextual annotations.
650 *
651 * @since 2.4
652 */
653 public <T> T readValue(JsonParser p, Class<T> type) throws IOException {
654 return readValue(p, getTypeFactory().constructType(type));
655 }
656
657 /**
658 * @since 2.4
659 */
660 @SuppressWarnings("unchecked")
661 public <T> T readValue(JsonParser p, JavaType type) throws IOException {
662 JsonDeserializer<Object> deser = findRootValueDeserializer(type);
663 if (deser == null) {
664 }
665 return (T) deser.deserialize(p, this);
666 }
667
668 /**
669 * Convenience method that may be used by composite or container deserializers,
670 * for reading one-off values for the composite type, taking into account
671 * annotations that the property (passed to this method -- usually property that
672 * has custom serializer that called this method) has.
673 *
674 * @since 2.4
675 */
676 public <T> T readPropertyValue(JsonParser p, BeanProperty prop, Class<T> type) throws IOException {
677 return readPropertyValue(p, prop, getTypeFactory().constructType(type));
678 }
679
680 /**
681 * @since 2.4
682 */
683 @SuppressWarnings("unchecked")
684 public <T> T readPropertyValue(JsonParser p, BeanProperty prop, JavaType type) throws IOException {
685 JsonDeserializer<Object> deser = findContextualValueDeserializer(type, prop);
686 if (deser == null) {
687
688 }
689 return (T) deser.deserialize(p, this);
690 }
691
692 /*
693 /**********************************************************
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800694 /* Methods for problem handling, reporting
695 /**********************************************************
696 */
697
698 /**
699 * Method deserializers can call to inform configured {@link DeserializationProblemHandler}s
700 * of an unrecognized property.
701 *
702 * @return True if there was a configured problem handler that was able to handle the
Tatu Saloranta0e3b3832012-01-22 22:08:20 -0800703 * problem
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800704 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800705 /**
706 * Method deserializers can call to inform configured {@link DeserializationProblemHandler}s
707 * of an unrecognized property.
708 */
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700709 public boolean handleUnknownProperty(JsonParser p, JsonDeserializer<?> deser,
Tatu Saloranta060ce112012-02-01 22:18:09 -0800710 Object instanceOrClass, String propName)
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800711 throws IOException, JsonProcessingException
712 {
713 LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
714 if (h != null) {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800715 while (h != null) {
716 // Can bail out if it's handled
Tatu Saloranta478d4a42014-03-16 21:53:33 -0700717 if (h.value().handleUnknownProperty(this, p, deser, instanceOrClass, propName)) {
Tatu Saloranta060ce112012-02-01 22:18:09 -0800718 return true;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800719 }
Tatu Saloranta060ce112012-02-01 22:18:09 -0800720 h = h.next();
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800721 }
722 }
723 return false;
724 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800725
726 /**
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800727 * Helper method for reporting a problem with unhandled unknown exception
728 *
729 * @param instanceOrClass Either value being populated (if one has been
730 * instantiated), or Class that indicates type that would be (or
731 * have been) instantiated
Tatu Saloranta05fce932012-03-19 17:14:05 -0700732 * @param deser Deserializer that had the problem, if called by deserializer
733 * (or on behalf of one)
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800734 */
Tatu Saloranta05fce932012-03-19 17:14:05 -0700735 public void reportUnknownProperty(Object instanceOrClass, String fieldName,
736 JsonDeserializer<?> deser)
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800737 throws JsonMappingException
738 {
Tatu Saloranta05fce932012-03-19 17:14:05 -0700739 if (!isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
740 return;
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800741 }
Tatu Saloranta05fce932012-03-19 17:14:05 -0700742 // Do we know properties that are expected instead?
743 Collection<Object> propIds = (deser == null) ? null : deser.getKnownPropertyNames();
744 throw UnrecognizedPropertyException.from(_parser,
745 instanceOrClass, fieldName, propIds);
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800746 }
747
748 /*
749 /**********************************************************
750 /* Methods for constructing exceptions
751 /**********************************************************
752 */
753
754 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800755 * Helper method for constructing generic mapping exception for specified type
756 */
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800757 public JsonMappingException mappingException(Class<?> targetClass) {
758 return mappingException(targetClass, _parser.getCurrentToken());
759 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800760
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -0800761 public JsonMappingException mappingException(Class<?> targetClass, JsonToken token) {
762 return JsonMappingException.from(_parser, "Can not deserialize instance of "+_calcName(targetClass)+" out of "+token+" token");
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800763 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800764
765 /**
766 * Helper method for constructing generic mapping exception with specified
767 * message and current location information
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800768 */
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800769 public JsonMappingException mappingException(String message) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800770 return JsonMappingException.from(getParser(), message);
771 }
772
773 /**
774 * Helper method for constructing instantiation exception for specified type,
775 * to indicate problem with physically constructing instance of
776 * specified class (missing constructor, exception from constructor)
777 */
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -0800778 public JsonMappingException instantiationException(Class<?> instClass, Throwable t) {
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800779 return JsonMappingException.from(_parser,
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -0800780 "Can not construct instance of "+instClass.getName()+", problem: "+t.getMessage(), t);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800781 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800782
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800783 public JsonMappingException instantiationException(Class<?> instClass, String msg) {
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800784 return JsonMappingException.from(_parser, "Can not construct instance of "+instClass.getName()+", problem: "+msg);
785 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800786
787 /**
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800788 * Method that will construct an exception suitable for throwing when
789 * some String values are acceptable, but the one encountered is not.
Tatu Salorantadd348562012-07-18 17:25:02 -0700790 *
791 *
792 * @deprecated Since 2.1 should use variant that takes value
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800793 */
Tatu Salorantadd348562012-07-18 17:25:02 -0700794 @Deprecated
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800795 public JsonMappingException weirdStringException(Class<?> instClass, String msg) {
Tatu Salorantadd348562012-07-18 17:25:02 -0700796 return weirdStringException(null, instClass, msg);
797 }
798
799 /**
800 * Method that will construct an exception suitable for throwing when
801 * some String values are acceptable, but the one encountered is not.
802 *
803 * @param value String value from input being deserialized
804 * @param instClass Type that String should be deserialized into
805 * @param msg Message that describes specific problem
806 *
807 * @since 2.1
808 */
809 public JsonMappingException weirdStringException(String value, Class<?> instClass, String msg) {
810 return InvalidFormatException.from(_parser,
811 "Can not construct instance of "+instClass.getName()+" from String value '"+_valueDesc()+"': "+msg,
812 value, instClass);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800813 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800814
815 /**
816 * Helper method for constructing exception to indicate that input JSON
817 * Number was not suitable for deserializing into given type.
818 */
Tatu Salorantadd348562012-07-18 17:25:02 -0700819 @Deprecated
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800820 public JsonMappingException weirdNumberException(Class<?> instClass, String msg) {
Tatu Salorantadd348562012-07-18 17:25:02 -0700821 return weirdStringException(null, instClass, msg);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800822 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800823
824 /**
Tatu Salorantadd348562012-07-18 17:25:02 -0700825 * Helper method for constructing exception to indicate that input JSON
826 * Number was not suitable for deserializing into given target type.
827 */
828 public JsonMappingException weirdNumberException(Number value, Class<?> instClass, String msg) {
829 return InvalidFormatException.from(_parser,
830 "Can not construct instance of "+instClass.getName()+" from number value ("+_valueDesc()+"): "+msg,
831 null, instClass);
832 }
833
834 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800835 * Helper method for constructing exception to indicate that given JSON
836 * Object field name was not in format to be able to deserialize specified
837 * key type.
838 */
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -0800839 public JsonMappingException weirdKeyException(Class<?> keyClass, String keyValue, String msg) {
Tatu Salorantadd348562012-07-18 17:25:02 -0700840 return InvalidFormatException.from(_parser,
841 "Can not construct Map key of type "+keyClass.getName()+" from String \""+_desc(keyValue)+"\": "+msg,
842 keyValue, keyClass);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800843 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800844
845 /**
846 * Helper method for indicating that the current token was expected to be another
847 * token.
848 */
Tatu Saloranta953eab22014-05-15 21:35:28 -0700849 public JsonMappingException wrongTokenException(JsonParser p, JsonToken expToken, String msg0) {
850 String msg = "Unexpected token ("+p.getCurrentToken()+"), expected "+expToken;
851 if (msg0 != null) {
852 msg = msg + ": "+msg0;
853 }
854 return JsonMappingException.from(p, msg);
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800855 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800856
857 /**
858 * Helper method for constructing exception to indicate that given
859 * type id (parsed from JSON) could not be converted to a Java type.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800860 */
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -0800861 public JsonMappingException unknownTypeException(JavaType type, String id) {
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800862 return JsonMappingException.from(_parser, "Could not resolve type id '"+id+"' into a subtype of "+type);
863 }
864
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -0800865 public JsonMappingException endOfInputException(Class<?> instClass) {
Tatu Saloranta5bd18092012-09-14 20:19:43 -0700866 return JsonMappingException.from(_parser, "Unexpected end-of-input when trying to deserialize a "
867 +instClass.getName());
868 }
869
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800870 /*
871 /**********************************************************
872 /* Overridable internal methods
873 /**********************************************************
874 */
875
876 protected DateFormat getDateFormat()
877 {
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -0800878 if (_dateFormat != null) {
879 return _dateFormat;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800880 }
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -0800881 /* 24-Feb-2012, tatu: At this point, all timezone configuration
882 * should have occured, with respect to default dateformat
883 * and timezone configuration. But we still better clone
884 * an instance as formatters may be stateful.
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -0800885 */
886 DateFormat df = _config.getDateFormat();
Tatu Saloranta3f0ca2e2012-02-25 15:54:08 -0800887 _dateFormat = df = (DateFormat) df.clone();
Tatu Saloranta3b88a6b2012-02-24 09:53:59 -0800888 return df;
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800889 }
890
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -0800891 protected String determineClassName(Object instance) {
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800892 return ClassUtil.getClassDescription(instance);
893 }
894
895 /*
896 /**********************************************************
897 /* Other internal methods
898 /**********************************************************
899 */
900
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -0800901 protected String _calcName(Class<?> cls) {
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800902 if (cls.isArray()) {
903 return _calcName(cls.getComponentType())+"[]";
904 }
905 return cls.getName();
906 }
907
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -0800908 protected String _valueDesc() {
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800909 try {
910 return _desc(_parser.getText());
911 } catch (Exception e) {
912 return "[N/A]";
913 }
914 }
Tatu Saloranta80e1b7e2014-01-11 20:11:33 -0800915
916 protected String _desc(String desc) {
Tatu Saloranta06c20b12012-01-29 21:36:52 -0800917 // !!! should we quote it? (in case there are control chars, linefeeds)
918 if (desc.length() > MAX_ERROR_STR_LEN) {
919 desc = desc.substring(0, MAX_ERROR_STR_LEN) + "]...[" + desc.substring(desc.length() - MAX_ERROR_STR_LEN);
920 }
921 return desc;
922 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800923}