blob: 777f4fc22a60b69d505631235c00123b431c6e7c [file] [log] [blame]
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001package com.fasterxml.jackson.databind;
2
3import java.io.IOException;
4import java.lang.reflect.Type;
Tatu6679cae2012-02-01 17:32:42 -08005import java.text.DateFormat;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08006import java.util.Date;
7
8import com.fasterxml.jackson.core.*;
Tatu6679cae2012-02-01 17:32:42 -08009
10import com.fasterxml.jackson.databind.annotation.NoClass;
Tatu9610aff2012-02-02 11:30:08 -080011import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
12import com.fasterxml.jackson.databind.cfg.SerializationConfig;
Tatu Salorantaaaba9c12012-01-24 18:51:44 -080013import com.fasterxml.jackson.databind.introspect.Annotated;
Tatu Salorantad1e678e2011-12-23 17:38:40 -080014import com.fasterxml.jackson.databind.jsonschema.JsonSchema;
Tatu6679cae2012-02-01 17:32:42 -080015import com.fasterxml.jackson.databind.jsonschema.SchemaAware;
Tatu Salorantadf6302f2011-12-23 20:05:35 -080016import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
Tatu6679cae2012-02-01 17:32:42 -080017import com.fasterxml.jackson.databind.node.ObjectNode;
18import com.fasterxml.jackson.databind.ser.*;
19import com.fasterxml.jackson.databind.ser.impl.*;
20import com.fasterxml.jackson.databind.ser.std.NullSerializer;
21import com.fasterxml.jackson.databind.ser.std.StdKeySerializers;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080022import com.fasterxml.jackson.databind.type.TypeFactory;
Tatu6679cae2012-02-01 17:32:42 -080023import com.fasterxml.jackson.databind.util.ClassUtil;
24import com.fasterxml.jackson.databind.util.RootNameLookup;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080025
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080026/**
Tatu6679cae2012-02-01 17:32:42 -080027 * Class that defines API used by {@link ObjectMapper} and
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080028 * {@link JsonSerializer}s to obtain serializers capable of serializing
Tatu6679cae2012-02-01 17:32:42 -080029 * instances of specific types; as well as the default implementation
30 * of the functionality.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080031 *<p>
Tatu6679cae2012-02-01 17:32:42 -080032 * Provider handles caching aspects of serializer handling; all construction
33 * details are delegated to {@link SerializerFactory} instance.
34 *<p>
35 * Object life-cycle is such that an initial instance ("blueprint") is created
36 * and referenced by {@link ObjectMapper} and {@link ObjectWriter} intances;
37 * but for actual usage, a configured instance is created by using
38 * {@link #createInstance}.
39 * Only this instance can be used for actual serialization calls; blueprint
40 * object is only to be used for creating instances.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080041 */
42public abstract class SerializerProvider
43{
44 protected final static JavaType TYPE_OBJECT = TypeFactory.defaultInstance().uncheckedSimpleType(Object.class);
Tatu6679cae2012-02-01 17:32:42 -080045
46 /**
47 * Setting for determining whether mappings for "unknown classes" should be
48 * cached for faster resolution. Usually this isn't needed, but maybe it
49 * is in some cases?
50 */
51 protected final static boolean CACHE_UNKNOWN_MAPPINGS = false;
52
53 public final static JsonSerializer<Object> DEFAULT_NULL_KEY_SERIALIZER =
54 new FailingSerializer("Null key for a Map not allowed in JSON (use a converting NullKeySerializer?)");
55
56 public final static JsonSerializer<Object> DEFAULT_UNKNOWN_SERIALIZER = new UnknownSerializer();
57
58 /*
59 /**********************************************************
60 /* Configuration, general
61 /**********************************************************
62 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080063
64 /**
65 * Serialization configuration to use for serialization processing.
66 */
67 protected final SerializationConfig _config;
68
69 /**
Tatu6679cae2012-02-01 17:32:42 -080070 * View used for currently active serialization, if any.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080071 */
72 protected final Class<?> _serializationView;
Tatu6679cae2012-02-01 17:32:42 -080073
74 /*
75 /**********************************************************
76 /* Configuration, factories
77 /**********************************************************
78 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080079
Tatu6679cae2012-02-01 17:32:42 -080080 /**
81 * Factory used for constructing actual serializer instances.
82 */
83 final protected SerializerFactory _serializerFactory;
84
85 /*
86 /**********************************************************
87 /* Configuration, caching
88 /**********************************************************
89 */
90
91 /**
92 * Cache for doing type-to-value-serializer lookups.
93 */
94 final protected SerializerCache _serializerCache;
95
96 /**
97 * Helper object for keeping track of introspected root names
98 */
99 final protected RootNameLookup _rootNames;
100
101 /*
102 /**********************************************************
103 /* Configuration, specialized serializers
104 /**********************************************************
105 */
106
107 /**
108 * Serializer that gets called for values of types for which no
109 * serializers can be constructed.
110 *<p>
111 * The default serializer will simply thrown an exception; a possible
112 * alternative that can be used would be
113 * {@link ToStringSerializer}.
114 */
115 protected JsonSerializer<Object> _unknownTypeSerializer = DEFAULT_UNKNOWN_SERIALIZER;
116
117 /**
118 * Serializer used to output non-null keys of Maps (which will get
119 * output as JSON Objects), if not null; if null, us the standard
120 * default key serializer.
121 */
122 protected JsonSerializer<Object> _keySerializer;
123
124 /**
125 * Serializer used to output a null value. Default implementation
126 * writes nulls using {@link JsonGenerator#writeNull}.
127 */
128 protected JsonSerializer<Object> _nullValueSerializer = NullSerializer.instance;
129
130 /**
131 * Serializer used to (try to) output a null key, due to an entry of
132 * {@link java.util.Map} having null key.
133 * The default implementation will throw an exception if this happens;
134 * alternative implementation (like one that would write an Empty String)
135 * can be defined.
136 */
137 protected JsonSerializer<Object> _nullKeySerializer = DEFAULT_NULL_KEY_SERIALIZER;
138
139 /*
140 /**********************************************************
141 /* State, for non-blueprint instances
142 /**********************************************************
143 */
144
145 /**
146 * For fast lookups, we will have a local non-shared read-only
147 * map that contains serializers previously fetched.
148 */
149 protected final ReadOnlyClassToSerializerMap _knownSerializers;
150
151 /**
152 * Lazily acquired and instantiated formatter object: initialized
153 * first time it is needed, reused afterwards. Used via instances
154 * (not blueprints), so that access need not be thread-safe.
155 */
156 protected DateFormat _dateFormat;
157
158 /*
159 /**********************************************************
160 /* Life-cycle
161 /**********************************************************
162 */
163
164 /**
165 * Constructor for creating master (or "blue-print") provider object,
166 * which is only used as the template for constructing per-binding
167 * instances.
168 */
169 public SerializerProvider()
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800170 {
Tatu6679cae2012-02-01 17:32:42 -0800171 _config = null;
172 _serializerFactory = null;
173 _serializerCache = new SerializerCache();
174 // Blueprints doesn't have access to any serializers...
175 _knownSerializers = null;
176 _rootNames = new RootNameLookup();
177
178 _serializationView = null;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800179 }
180
Tatu6679cae2012-02-01 17:32:42 -0800181 /**
182 * "Copy-constructor", used from {@link #createInstance} (or by
183 * sub-classes)
184 *
185 * @param src Blueprint object used as the baseline for this instance
186 */
187 protected SerializerProvider(SerializerProvider src,
188 SerializationConfig config, SerializerFactory f)
189 {
190 if (config == null) {
191 throw new NullPointerException();
192 }
193 _serializerFactory = f;
194 _config = config;
195
196 _serializerCache = src._serializerCache;
197 _unknownTypeSerializer = src._unknownTypeSerializer;
198 _keySerializer = src._keySerializer;
199 _nullValueSerializer = src._nullValueSerializer;
200 _nullKeySerializer = src._nullKeySerializer;
201 _rootNames = src._rootNames;
202
203 /* Non-blueprint instances do have a read-only map; one that doesn't
204 * need synchronization for lookups.
205 */
206 _knownSerializers = _serializerCache.getReadOnlyLookupMap();
207
208 _serializationView = config.getActiveView();
209 }
210
211 /**
212 * Overridable method, used to create a non-blueprint instances from the blueprint.
213 * This is needed to retain state during serialization.
214 */
215 public abstract SerializerProvider createInstance(SerializationConfig config,
216 SerializerFactory jsf);
217
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800218 /*
219 /**********************************************************
220 /* Methods for configuring default settings
221 /**********************************************************
222 */
223
224 /**
225 * Method that can be used to specify serializer that will be
226 * used to write JSON property names matching null keys for Java
227 * Maps (which will throw an exception if try write such property
228 * name)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800229 */
Tatu6679cae2012-02-01 17:32:42 -0800230 public void setDefaultKeySerializer(JsonSerializer<Object> ks)
231 {
232 if (ks == null) {
233 throw new IllegalArgumentException("Can not pass null JsonSerializer");
234 }
235 _keySerializer = ks;
236 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800237
238 /**
239 * Method that can be used to specify serializer that will be
240 * used to write JSON values matching Java null values
241 * instead of default one (which simply writes JSON null)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800242 */
Tatu6679cae2012-02-01 17:32:42 -0800243 public void setNullValueSerializer(JsonSerializer<Object> nvs)
244 {
245 if (nvs == null) {
246 throw new IllegalArgumentException("Can not pass null JsonSerializer");
247 }
248 _nullValueSerializer = nvs;
249 }
250
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800251 /**
252 * Method that can be used to specify serializer to use for serializing
253 * all non-null JSON property names, unless more specific key serializer
254 * is found (i.e. if not custom key serializer has been registered for
255 * Java type).
256 *<p>
257 * Note that key serializer registration are different from value serializer
258 * registrations.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800259 */
Tatu6679cae2012-02-01 17:32:42 -0800260 public void setNullKeySerializer(JsonSerializer<Object> nks)
261 {
262 if (nks == null) {
263 throw new IllegalArgumentException("Can not pass null JsonSerializer");
264 }
265 _nullKeySerializer = nks;
266 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800267
268 /*
269 /**********************************************************
270 /* Methods that ObjectMapper will call
271 /**********************************************************
272 */
273
274 /**
Tatu6679cae2012-02-01 17:32:42 -0800275 * The method to be called by {@link ObjectMapper} and {@link ObjectWriter}
276 * for serializing given value, using serializers that
277 * this provider has access to (via caching and/or creating new serializers
278 * as need be).
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800279 */
Tatu Saloranta8e433552012-02-01 17:58:46 -0800280 public void serializeValue(JsonGenerator jgen, Object value)
Tatu6679cae2012-02-01 17:32:42 -0800281 throws IOException, JsonGenerationException
282 {
Tatu Saloranta8e433552012-02-01 17:58:46 -0800283 JsonSerializer<Object> ser;
284 boolean wrap;
285
286 if (value == null) {
287 // no type provided; must just use the default null serializer
288 ser = getDefaultNullValueSerializer();
289 wrap = false; // no name to use for wrapping; can't do!
290 } else {
291 Class<?> cls = value.getClass();
292 // true, since we do want to cache root-level typed serializers (ditto for null property)
293 ser = findTypedValueSerializer(cls, true, null);
294
295 // Ok: should we wrap result in an additional property ("root name")?
296 String rootName = _config.getRootName();
297 if (rootName == null) { // not explicitly specified
298 // [JACKSON-163]
Tatu9610aff2012-02-02 11:30:08 -0800299 wrap = _config.isEnabled(SerializationFeature.WRAP_ROOT_VALUE);
Tatu Saloranta8e433552012-02-01 17:58:46 -0800300 if (wrap) {
301 jgen.writeStartObject();
302 jgen.writeFieldName(_rootNames.findRootName(value.getClass(), _config));
303 }
304 } else if (rootName.length() == 0) {
305 wrap = false;
306 } else { // [JACKSON-764]
307 // empty String means explicitly disabled; non-empty that it is enabled
308 wrap = true;
309 jgen.writeStartObject();
310 jgen.writeFieldName(rootName);
311 }
312 }
313 try {
314 ser.serialize(value, jgen, this);
315 if (wrap) {
316 jgen.writeEndObject();
317 }
318 } catch (IOException ioe) {
319 /* As per [JACKSON-99], should not wrap IOException or its
320 * sub-classes (like JsonProcessingException, JsonMappingException)
321 */
322 throw ioe;
323 } catch (Exception e) {
324 // but others are wrapped
325 String msg = e.getMessage();
326 if (msg == null) {
327 msg = "[no message for "+e.getClass().getName()+"]";
328 }
329 throw new JsonMappingException(msg, e);
330 }
Tatu6679cae2012-02-01 17:32:42 -0800331 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800332
333 /**
Tatu6679cae2012-02-01 17:32:42 -0800334 * The method to be called by {@link ObjectMapper} and {@link ObjectWriter}
335 * for serializing given value (assumed to be of specified root type,
336 * instead of runtime type of value),
337 * using serializers that
338 * this provider has access to (via caching and/or creating new serializers
339 * as need be),
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800340 *
341 * @param rootType Type to use for locating serializer to use, instead of actual
342 * runtime type. Must be actual type, or one of its super types
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800343 */
Tatu Saloranta8e433552012-02-01 17:58:46 -0800344 public void serializeValue(JsonGenerator jgen, Object value,
Tatu6679cae2012-02-01 17:32:42 -0800345 JavaType rootType)
346 throws IOException, JsonGenerationException
347 {
Tatu Saloranta8e433552012-02-01 17:58:46 -0800348 boolean wrap;
349
350 JsonSerializer<Object> ser;
351 if (value == null) {
352 ser = getDefaultNullValueSerializer();
353 wrap = false;
354 } else {
355 // Let's ensure types are compatible at this point
356 if (!rootType.getRawClass().isAssignableFrom(value.getClass())) {
357 _reportIncompatibleRootType(value, rootType);
358 }
359 // root value, not reached via property:
360 ser = findTypedValueSerializer(rootType, true, null);
361 // [JACKSON-163]
Tatu9610aff2012-02-02 11:30:08 -0800362 wrap = _config.isEnabled(SerializationFeature.WRAP_ROOT_VALUE);
Tatu Saloranta8e433552012-02-01 17:58:46 -0800363 if (wrap) {
364 jgen.writeStartObject();
365 jgen.writeFieldName(_rootNames.findRootName(rootType, _config));
366 }
367 }
368 try {
369 ser.serialize(value, jgen, this);
370 if (wrap) {
371 jgen.writeEndObject();
372 }
373 } catch (IOException ioe) { // no wrapping for IO (and derived)
374 throw ioe;
375 } catch (Exception e) { // but others do need to be, to get path etc
376 String msg = e.getMessage();
377 if (msg == null) {
378 msg = "[no message for "+e.getClass().getName()+"]";
379 }
380 throw new JsonMappingException(msg, e);
381 }
Tatu6679cae2012-02-01 17:32:42 -0800382 }
383
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800384 /**
Tatu Saloranta8e433552012-02-01 17:58:46 -0800385 * The method to be called by {@link ObjectMapper} and {@link ObjectWriter}
386 * to generate <a href="http://json-schema.org/">JSON schema</a> for
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800387 * given type.
388 *
389 * @param type The type for which to generate schema
390 */
Tatu6679cae2012-02-01 17:32:42 -0800391 public JsonSchema generateJsonSchema(Class<?> type)
392 throws JsonMappingException
393 {
394 if (type == null) {
395 throw new IllegalArgumentException("A class must be provided");
396 }
397 /* no need for embedded type information for JSON schema generation (all
398 * type information it needs is accessible via "untyped" serializer)
399 */
400 JsonSerializer<Object> ser = findValueSerializer(type, null);
401 JsonNode schemaNode = (ser instanceof SchemaAware) ?
402 ((SchemaAware) ser).getSchema(this, null) :
403 JsonSchema.getDefaultSchemaNode();
404 if (!(schemaNode instanceof ObjectNode)) {
405 throw new IllegalArgumentException("Class " + type.getName() +
406 " would not be serialized as a JSON object and therefore has no schema");
407 }
408 return new JsonSchema((ObjectNode) schemaNode);
409 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800410
411 /**
412 * Method that can be called to see if this serializer provider
413 * can find a serializer for an instance of given class.
414 *<p>
415 * Note that no Exceptions are thrown, including unchecked ones:
416 * implementations are to swallow exceptions if necessary.
417 */
Tatu6679cae2012-02-01 17:32:42 -0800418 public boolean hasSerializerFor(Class<?> cls) {
419 return _findExplicitUntypedSerializer(cls, null) != null;
420 }
421
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800422 /*
423 /**********************************************************
424 /* Access to configuration
425 /**********************************************************
426 */
427
428 /**
429 * Method for accessing configuration for the serialization processing.
430 */
431 public final SerializationConfig getConfig() { return _config; }
432
433 /**
434 * Convenience method for checking whether specified serialization
435 * feature is enabled or not.
436 * Shortcut for:
437 *<pre>
438 * getConfig().isEnabled(feature);
439 *</pre>
440 */
Tatu9610aff2012-02-02 11:30:08 -0800441 public final boolean isEnabled(MapperFeature feature) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800442 return _config.isEnabled(feature);
443 }
444
445 /**
Tatudfed9242012-01-19 12:31:44 -0800446 * Convenience method for checking whether specified serialization
447 * feature is enabled or not.
448 * Shortcut for:
449 *<pre>
450 * getConfig().isEnabled(feature);
451 *</pre>
452 */
Tatu9610aff2012-02-02 11:30:08 -0800453 public final boolean isEnabled(SerializationFeature feature) {
Tatudfed9242012-01-19 12:31:44 -0800454 return _config.isEnabled(feature);
455 }
Tatu Salorantaaaba9c12012-01-24 18:51:44 -0800456
457 /**
458 * Convenience method for accessing serialization view in use (if any); equivalent to:
459 *<pre>
460 * getConfig().canOverrideAccessModifiers();
461 *</pre>
462 */
463 public final boolean canOverrideAccessModifiers() {
464 return _config.canOverrideAccessModifiers();
465 }
466
467 /**
468 * Convenience method for accessing serialization view in use (if any); equivalent to:
469 *<pre>
470 * getConfig().getAnnotationIntrospector();
471 *</pre>
472 */
473 public final AnnotationIntrospector getAnnotationIntrospector() {
474 return _config.getAnnotationIntrospector();
475 }
Tatudfed9242012-01-19 12:31:44 -0800476
477 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800478 * Convenience method for accessing serialization view in use (if any); equivalent to:
479 *<pre>
480 * getConfig().getSerializationView();
481 *</pre>
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800482 */
483 public final Class<?> getSerializationView() { return _serializationView; }
484
485 /**
486 * Convenience method for accessing provider to find serialization filters used,
487 * equivalent to calling:
488 *<pre>
489 * getConfig().getFilterProvider();
490 *</pre>
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800491 */
492 public final FilterProvider getFilterProvider() {
493 return _config.getFilterProvider();
494 }
495
496 /**
Tatu418a2392012-01-12 21:52:07 -0800497 * Convenience method for constructing {@link JavaType} for given JDK
498 * type (usually {@link java.lang.Class})
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800499 */
500 public JavaType constructType(Type type) {
501 return _config.getTypeFactory().constructType(type);
502 }
503
504 /**
Tatu418a2392012-01-12 21:52:07 -0800505 * Convenience method for constructing subtypes, retaining generic
506 * type parameter (if any)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800507 */
508 public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass) {
509 return _config.constructSpecializedType(baseType, subclass);
510 }
511
512 /*
513 /**********************************************************
514 /* General serializer locating functionality
515 /**********************************************************
516 */
517
518 /**
519 * Method called to get hold of a serializer for a value of given type;
520 * or if no such serializer can be found, a default handler (which
521 * may do a best-effort generic serialization or just simply
522 * throw an exception when invoked).
523 *<p>
524 * Note: this method is only called for non-null values; not for keys
525 * or null values. For these, check out other accessor methods.
526 *<p>
527 * Note that starting with version 1.5, serializers should also be type-aware
528 * if they handle polymorphic types. That means that it may be necessary
529 * to also use a {@link TypeSerializer} based on declared (static) type
530 * being serializer (whereas actual data may be serialized using dynamic
531 * type)
532 *
533 * @throws JsonMappingException if there are fatal problems with
534 * accessing suitable serializer; including that of not
535 * finding any serializer
536 */
Tatu6679cae2012-02-01 17:32:42 -0800537 public JsonSerializer<Object> findValueSerializer(Class<?> valueType,
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800538 BeanProperty property)
Tatu6679cae2012-02-01 17:32:42 -0800539 throws JsonMappingException
540 {
541 // Fast lookup from local lookup thingy works?
542 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
543 if (ser == null) {
544 // If not, maybe shared map already has it?
545 ser = _serializerCache.untypedValueSerializer(valueType);
546 if (ser == null) {
547 // ... possibly as fully typed?
548 ser = _serializerCache.untypedValueSerializer(_config.constructType(valueType));
549 if (ser == null) {
550 // If neither, must create
551 ser = _createAndCacheUntypedSerializer(valueType, property);
552 // Not found? Must use the unknown type serializer
553 /* Couldn't create? Need to return the fallback serializer, which
554 * most likely will report an error: but one question is whether
555 * we should cache it?
556 */
557 if (ser == null) {
558 ser = getUnknownTypeSerializer(valueType);
559 // Should this be added to lookups?
560 if (CACHE_UNKNOWN_MAPPINGS) {
561 _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
562 }
563 return ser;
564 }
565 }
566 }
567 }
568 // at this point, resolution has occured, but not contextualization
569 return _handleContextual(ser, property);
570 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800571
572 /**
Tatu6679cae2012-02-01 17:32:42 -0800573 * Similar to {@link #findValueSerializer(Class,BeanProperty)}, but takes
574 * full generics-aware type instead of raw class.
575 * This is necessary for accurate handling of external type information,
576 * to handle polymorphic types.
Tatu Salorantafd9690c2012-01-16 17:24:33 -0800577 *
578 * @param property When creating secondary serializers, property for which
579 * serializer is needed: annotations of the property (or bean that contains it)
580 * may be checked to create contextual serializers.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800581 */
Tatu6679cae2012-02-01 17:32:42 -0800582 public JsonSerializer<Object> findValueSerializer(JavaType valueType, BeanProperty property)
583 throws JsonMappingException
584 {
585 // Fast lookup from local lookup thingy works?
586 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
587 if (ser == null) {
588 // If not, maybe shared map already has it?
589 ser = _serializerCache.untypedValueSerializer(valueType);
590 if (ser == null) {
591 // If neither, must create
592 ser = _createAndCacheUntypedSerializer(valueType, property);
593 // Not found? Must use the unknown type serializer
594 /* Couldn't create? Need to return the fallback serializer, which
595 * most likely will report an error: but one question is whether
596 * we should cache it?
597 */
598 if (ser == null) {
599 ser = getUnknownTypeSerializer(valueType.getRawClass());
600 // Should this be added to lookups?
601 if (CACHE_UNKNOWN_MAPPINGS) {
602 _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
603 }
604 return ser;
605 }
606 }
607 }
608 return _handleContextual(ser, property);
609 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800610
611 /**
612 * Method called to locate regular serializer, matching type serializer,
613 * and if both found, wrap them in a serializer that calls both in correct
614 * sequence. This method is currently only used for root-level serializer
615 * handling to allow for simpler caching. A call can always be replaced
616 * by equivalent calls to access serializer and type serializer separately.
617 *
618 * @param valueType Type for purpose of locating a serializer; usually dynamic
619 * runtime type, but can also be static declared type, depending on configuration
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800620 * @param cache Whether resulting value serializer should be cached or not; this is just
Tatu418a2392012-01-12 21:52:07 -0800621 * a hint
Tatu Salorantafd9690c2012-01-16 17:24:33 -0800622 * @param property When creating secondary serializers, property for which
623 * serializer is needed: annotations of the property (or bean that contains it)
624 * may be checked to create contextual serializers.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800625 */
Tatu6679cae2012-02-01 17:32:42 -0800626 public JsonSerializer<Object> findTypedValueSerializer(Class<?> valueType,
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800627 boolean cache, BeanProperty property)
Tatu6679cae2012-02-01 17:32:42 -0800628 throws JsonMappingException
629 {
630 // Two-phase lookups; local non-shared cache, then shared:
631 JsonSerializer<Object> ser = _knownSerializers.typedValueSerializer(valueType);
632 if (ser != null) {
633 return ser;
634 }
635 // If not, maybe shared map already has it?
636 ser = _serializerCache.typedValueSerializer(valueType);
637 if (ser != null) {
638 return ser;
639 }
640
641 // Well, let's just compose from pieces:
642 ser = findValueSerializer(valueType, property);
643 TypeSerializer typeSer = _serializerFactory.createTypeSerializer(_config,
644 _config.constructType(valueType));
645 if (typeSer != null) {
646 typeSer = typeSer.forProperty(property);
647 ser = new TypeWrappedSerializer(typeSer, ser);
648 }
649 if (cache) {
650 _serializerCache.addTypedSerializer(valueType, ser);
651 }
652 return ser;
653 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800654
655 /**
656 * Method called to locate regular serializer, matching type serializer,
657 * and if both found, wrap them in a serializer that calls both in correct
658 * sequence. This method is currently only used for root-level serializer
659 * handling to allow for simpler caching. A call can always be replaced
660 * by equivalent calls to access serializer and type serializer separately.
661 *
662 * @param valueType Declared type of value being serialized (which may not
663 * be actual runtime type); used for finding both value serializer and
664 * type serializer to use for adding polymorphic type (if any)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800665 * @param cache Whether resulting value serializer should be cached or not; this is just
666 * a hint
Tatu Salorantafd9690c2012-01-16 17:24:33 -0800667 * @param property When creating secondary serializers, property for which
668 * serializer is needed: annotations of the property (or bean that contains it)
669 * may be checked to create contextual serializers.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800670 */
Tatu6679cae2012-02-01 17:32:42 -0800671 public JsonSerializer<Object> findTypedValueSerializer(JavaType valueType, boolean cache,
672 BeanProperty property)
673 throws JsonMappingException
674 {
675 // Two-phase lookups; local non-shared cache, then shared:
676 JsonSerializer<Object> ser = _knownSerializers.typedValueSerializer(valueType);
677 if (ser != null) {
678 return ser;
679 }
680 // If not, maybe shared map already has it?
681 ser = _serializerCache.typedValueSerializer(valueType);
682 if (ser != null) {
683 return ser;
684 }
685
686 // Well, let's just compose from pieces:
687 ser = findValueSerializer(valueType, property);
688 TypeSerializer typeSer = _serializerFactory.createTypeSerializer(_config, valueType);
689 if (typeSer != null) {
690 typeSer = typeSer.forProperty(property);
691 ser = new TypeWrappedSerializer(typeSer, ser);
692 }
693 if (cache) {
694 _serializerCache.addTypedSerializer(valueType, ser);
695 }
696 return ser;
697 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800698
699 /**
700 * Method called to get the serializer to use for serializing
701 * non-null Map keys. Separation from regular
702 * {@link #findValueSerializer} method is because actual write
703 * method must be different (@link JsonGenerator#writeFieldName};
704 * but also since behavior for some key types may differ.
705 *<p>
706 * Note that the serializer itself can be called with instances
707 * of any Java object, but not nulls.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800708 */
Tatu6679cae2012-02-01 17:32:42 -0800709 public JsonSerializer<Object> findKeySerializer(JavaType keyType,
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800710 BeanProperty property)
Tatu6679cae2012-02-01 17:32:42 -0800711 throws JsonMappingException
712 {
Tatu Saloranta1ef0dc32012-02-01 18:10:22 -0800713 JsonSerializer<Object> ser = _serializerFactory.createKeySerializer(_config, keyType);
Tatu6679cae2012-02-01 17:32:42 -0800714
715 // First things first: maybe there are registered custom implementations
716 // if not, use default one:
717 if (ser == null) {
718 if (_keySerializer == null) {
719 ser = StdKeySerializers.getStdKeySerializer(keyType);
720 } else {
721 ser = _keySerializer;
722 }
723 }
724 // 25-Feb-2011, tatu: As per [JACKSON-519], need to ensure contextuality works here, too
725 return _handleContextualResolvable(ser, property);
726 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800727
728 /*
729 /********************************************************
730 /* Accessors for specialized serializers
731 /********************************************************
732 */
733
734 /**
Tatu418a2392012-01-12 21:52:07 -0800735 * @since 2.0
736 */
Tatu6679cae2012-02-01 17:32:42 -0800737 public JsonSerializer<Object> getDefaultNullKeySerializer() {
738 return _nullKeySerializer;
739 }
Tatu418a2392012-01-12 21:52:07 -0800740
741 /**
742 * @since 2.0
743 */
Tatu6679cae2012-02-01 17:32:42 -0800744 public JsonSerializer<Object> getDefaultNullValueSerializer() {
745 return _nullValueSerializer;
746 }
Tatu418a2392012-01-12 21:52:07 -0800747
748 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800749 * Method called to get the serializer to use for serializing
750 * Map keys that are nulls: this is needed since JSON does not allow
751 * any non-String value as key, including null.
752 *<p>
753 * Typically, returned serializer
754 * will either throw an exception, or use an empty String; but
755 * other behaviors are possible.
756 */
Tatu418a2392012-01-12 21:52:07 -0800757 /**
758 * Method called to find a serializer to use for null values for given
759 * declared type. Note that type is completely based on declared type,
760 * since nulls in Java have no type and thus runtime type can not be
761 * determined.
762 *
763 * @since 2.0
764 */
765 public JsonSerializer<Object> findNullKeySerializer(JavaType serializationType,
766 BeanProperty property)
767 throws JsonMappingException {
768 return getDefaultNullKeySerializer();
769 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800770
771 /**
Tatu418a2392012-01-12 21:52:07 -0800772 * Method called to get the serializer to use for serializing null
773 * property values.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800774 *<p>
Tatu418a2392012-01-12 21:52:07 -0800775 * Default implementation simply calls {@link #getDefaultNullValueSerializer()};
776 * can be overridden to add custom null serialization for properties
777 * of certain type or name.
778 *
779 * @since 2.0
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800780 */
Tatu418a2392012-01-12 21:52:07 -0800781 public JsonSerializer<Object> findNullValueSerializer(BeanProperty property)
782 throws JsonMappingException {
783 return getDefaultNullValueSerializer();
784 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800785
786 /**
787 * Method called to get the serializer to use if provider
788 * can not determine an actual type-specific serializer
789 * to use; typically when none of {@link SerializerFactory}
790 * instances are able to construct a serializer.
791 *<p>
792 * Typically, returned serializer will throw an exception,
Tatu Salorantadfec1502012-01-14 18:08:00 -0800793 * although alternatively {@link com.fasterxml.jackson.databind.ser.std.ToStringSerializer}
794 * could be returned as well.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800795 *
796 * @param unknownType Type for which no serializer is found
797 */
Tatu6679cae2012-02-01 17:32:42 -0800798 public JsonSerializer<Object> getUnknownTypeSerializer(Class<?> unknownType) {
799 return _unknownTypeSerializer;
800 }
Tatu Salorantaaaba9c12012-01-24 18:51:44 -0800801
802 /*
803 /**********************************************************
804 /* Methods for creating instances based on annotations
805 /**********************************************************
806 */
807
808 /**
809 * Method that can be called to construct and configure serializer instance,
810 * either given a {@link Class} to instantiate (with default constructor),
811 * or an uninitialized serializer instance.
812 * Either way, serialize will be properly resolved
813 * (via {@link com.fasterxml.jackson.databind.ser.ResolvableSerializer}) and/or contextualized
814 * (via {@link com.fasterxml.jackson.databind.ser.ContextualSerializer}) as necessary.
815 *
816 * @param annotated Annotated entity that contained definition
817 * @param serDef Serializer definition: either an instance or class
818 */
Tatu6679cae2012-02-01 17:32:42 -0800819 public JsonSerializer<Object> serializerInstance(Annotated annotated,
Tatu Saloranta2bc8dec2012-02-01 18:54:18 -0800820 Object serDef)
Tatu6679cae2012-02-01 17:32:42 -0800821 throws JsonMappingException
822 {
823 if (serDef == null) {
824 return null;
825 }
826 JsonSerializer<?> ser;
827
828 if (serDef instanceof JsonSerializer) {
829 ser = (JsonSerializer<?>) serDef;
830 } else {
831 /* Alas, there's no way to force return type of "either class
832 * X or Y" -- need to throw an exception after the fact
833 */
834 if (!(serDef instanceof Class)) {
835 throw new IllegalStateException("AnnotationIntrospector returned serializer definition of type "
836 +serDef.getClass().getName()+"; expected type JsonSerializer or Class<JsonSerializer> instead");
837 }
838 Class<?> serClass = (Class<?>)serDef;
839 // there are some known "no class" markers to consider too:
840 if (serClass == JsonSerializer.None.class || serClass == NoClass.class) {
841 return null;
842 }
843 if (!JsonSerializer.class.isAssignableFrom(serClass)) {
844 throw new IllegalStateException("AnnotationIntrospector returned Class "
845 +serClass.getName()+"; expected Class<JsonSerializer>");
846 }
847 HandlerInstantiator hi = _config.getHandlerInstantiator();
848 if (hi != null) {
849 ser = hi.serializerInstance(_config, annotated, serClass);
850 } else {
851 ser = (JsonSerializer<?>) ClassUtil.createInstance(serClass,
852 _config.canOverrideAccessModifiers());
853 }
854 }
Tatu Saloranta2bc8dec2012-02-01 18:54:18 -0800855 return (JsonSerializer<Object>) _handleResolvable(ser);
Tatu6679cae2012-02-01 17:32:42 -0800856 }
Tatu Salorantaaaba9c12012-01-24 18:51:44 -0800857
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800858 /*
859 /********************************************************
860 /* Convenience methods
861 /********************************************************
862 */
863
864 /**
865 * Convenience method that will serialize given value (which can be
866 * null) using standard serializer locating functionality. It can
867 * be called for all values including field and Map values, but usually
868 * field values are best handled calling
869 * {@link #defaultSerializeField} instead.
870 */
871 public final void defaultSerializeValue(Object value, JsonGenerator jgen)
872 throws IOException, JsonProcessingException
873 {
874 if (value == null) {
Tatu418a2392012-01-12 21:52:07 -0800875 getDefaultNullValueSerializer().serialize(null, jgen, this);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800876 } else {
877 Class<?> cls = value.getClass();
878 findTypedValueSerializer(cls, true, null).serialize(value, jgen, this);
879 }
880 }
881
882 /**
883 * Convenience method that will serialize given field with specified
884 * value. Value may be null. Serializer is done using the usual
885 * null) using standard serializer locating functionality.
886 */
887 public final void defaultSerializeField(String fieldName, Object value, JsonGenerator jgen)
888 throws IOException, JsonProcessingException
889 {
890 jgen.writeFieldName(fieldName);
891 if (value == null) {
892 /* Note: can't easily check for suppression at this point
893 * any more; caller must check it.
894 */
Tatu418a2392012-01-12 21:52:07 -0800895 getDefaultNullValueSerializer().serialize(null, jgen, this);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800896 } else {
897 Class<?> cls = value.getClass();
898 findTypedValueSerializer(cls, true, null).serialize(value, jgen, this);
899 }
900 }
901
902 /**
903 * Method that will handle serialization of Date(-like) values, using
904 * {@link SerializationConfig} settings to determine expected serialization
905 * behavior.
906 * Note: date here means "full" date, that is, date AND time, as per
907 * Java convention (and not date-only values like in SQL)
908 */
Tatu6679cae2012-02-01 17:32:42 -0800909 /*
910 /**********************************************************
911 /* Abstract method impls, convenience methods
912 /**********************************************************
913 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800914
915 /**
916 * Method that will handle serialization of Date(-like) values, using
917 * {@link SerializationConfig} settings to determine expected serialization
918 * behavior.
919 * Note: date here means "full" date, that is, date AND time, as per
920 * Java convention (and not date-only values like in SQL)
921 */
Tatu6679cae2012-02-01 17:32:42 -0800922 public final void defaultSerializeDateValue(long timestamp, JsonGenerator jgen)
923 throws IOException, JsonProcessingException
924 {
925 // [JACKSON-87]: Support both numeric timestamps and textual
Tatu9610aff2012-02-02 11:30:08 -0800926 if (isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)) {
Tatu6679cae2012-02-01 17:32:42 -0800927 jgen.writeNumber(timestamp);
928 } else {
929 if (_dateFormat == null) {
930 // must create a clone since Formats are not thread-safe:
931 _dateFormat = (DateFormat)_config.getDateFormat().clone();
932 }
933 jgen.writeString(_dateFormat.format(new Date(timestamp)));
934 }
935 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800936
Tatu6679cae2012-02-01 17:32:42 -0800937 /**
938 * Method that will handle serialization of Date(-like) values, using
939 * {@link SerializationConfig} settings to determine expected serialization
940 * behavior.
941 * Note: date here means "full" date, that is, date AND time, as per
942 * Java convention (and not date-only values like in SQL)
943 */
944 public final void defaultSerializeDateValue(Date date, JsonGenerator jgen)
945 throws IOException, JsonProcessingException
946 {
947 // [JACKSON-87]: Support both numeric timestamps and textual
Tatu9610aff2012-02-02 11:30:08 -0800948 if (isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)) {
Tatu6679cae2012-02-01 17:32:42 -0800949 jgen.writeNumber(date.getTime());
950 } else {
951 if (_dateFormat == null) {
952 DateFormat blueprint = _config.getDateFormat();
953 // must create a clone since Formats are not thread-safe:
954 _dateFormat = (DateFormat)blueprint.clone();
955 }
956 jgen.writeString(_dateFormat.format(date));
957 }
958 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800959
960 /**
961 * Method that will handle serialization of Dates used as {@link java.util.Map} keys,
Tatu9610aff2012-02-02 11:30:08 -0800962 * based on {@link SerializationFeature#WRITE_DATE_KEYS_AS_TIMESTAMPS}
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800963 * value (and if using textual representation, configured date format)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800964 */
Tatu6679cae2012-02-01 17:32:42 -0800965 public void defaultSerializeDateKey(long timestamp, JsonGenerator jgen)
966 throws IOException, JsonProcessingException
967 {
Tatu9610aff2012-02-02 11:30:08 -0800968 if (isEnabled(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)) {
Tatu6679cae2012-02-01 17:32:42 -0800969 jgen.writeFieldName(String.valueOf(timestamp));
970 } else {
971 if (_dateFormat == null) {
972 DateFormat blueprint = _config.getDateFormat();
973 // must create a clone since Formats are not thread-safe:
974 _dateFormat = (DateFormat)blueprint.clone();
975 }
976 jgen.writeFieldName(_dateFormat.format(new Date(timestamp)));
977 }
978 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800979
980 /**
981 * Method that will handle serialization of Dates used as {@link java.util.Map} keys,
Tatu9610aff2012-02-02 11:30:08 -0800982 * based on {@link SerializationFeature#WRITE_DATE_KEYS_AS_TIMESTAMPS}
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800983 * value (and if using textual representation, configured date format)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800984 */
Tatu6679cae2012-02-01 17:32:42 -0800985 public void defaultSerializeDateKey(Date date, JsonGenerator jgen)
986 throws IOException, JsonProcessingException
987 {
Tatu9610aff2012-02-02 11:30:08 -0800988 if (isEnabled(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)) {
Tatu6679cae2012-02-01 17:32:42 -0800989 jgen.writeFieldName(String.valueOf(date.getTime()));
990 } else {
991 if (_dateFormat == null) {
992 DateFormat blueprint = _config.getDateFormat();
993 // must create a clone since Formats are not thread-safe:
994 _dateFormat = (DateFormat)blueprint.clone();
995 }
996 jgen.writeFieldName(_dateFormat.format(date));
997 }
998 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800999
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001000 public final void defaultSerializeNull(JsonGenerator jgen)
1001 throws IOException, JsonProcessingException
1002 {
Tatu418a2392012-01-12 21:52:07 -08001003 getDefaultNullValueSerializer().serialize(null, jgen, this);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001004 }
1005
1006 /*
1007 /********************************************************
1008 /* Access to caching details
1009 /********************************************************
1010 */
1011
1012 /**
1013 * Method that can be used to determine how many serializers this
1014 * provider is caching currently
1015 * (if it does caching: default implementation does)
1016 * Exact count depends on what kind of serializers get cached;
1017 * default implementation caches all serializers, including ones that
1018 * are eagerly constructed (for optimal access speed)
1019 *<p>
1020 * The main use case for this method is to allow conditional flushing of
1021 * serializer cache, if certain number of entries is reached.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001022 */
Tatu6679cae2012-02-01 17:32:42 -08001023 public int cachedSerializersCount() {
1024 return _serializerCache.size();
1025 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001026
1027 /**
1028 * Method that will drop all serializers currently cached by this provider.
1029 * This can be used to remove memory usage (in case some serializers are
1030 * only used once or so), or to force re-construction of serializers after
1031 * configuration changes for mapper than owns the provider.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001032 */
Tatu6679cae2012-02-01 17:32:42 -08001033 public void flushCachedSerializers() {
1034 _serializerCache.flush();
1035 }
1036
Tatu6679cae2012-02-01 17:32:42 -08001037 protected void _reportIncompatibleRootType(Object value, JavaType rootType)
1038 throws IOException, JsonProcessingException
1039 {
1040 /* 07-Jan-2010, tatu: As per [JACKSON-456] better handle distinction between wrapper types,
1041 * primitives
1042 */
1043 if (rootType.isPrimitive()) {
1044 Class<?> wrapperType = ClassUtil.wrapperType(rootType.getRawClass());
1045 // If it's just difference between wrapper, primitive, let it slide
1046 if (wrapperType.isAssignableFrom(value.getClass())) {
1047 return;
1048 }
1049 }
1050 throw new JsonMappingException("Incompatible types: declared root type ("+rootType+") vs "
1051 +value.getClass().getName());
1052 }
1053
1054 /**
1055 * Method that will try to find a serializer, either from cache
1056 * or by constructing one; but will not return an "unknown" serializer
1057 * if this can not be done but rather returns null.
1058 *
1059 * @return Serializer if one can be found, null if not.
1060 */
1061 protected JsonSerializer<Object> _findExplicitUntypedSerializer(Class<?> runtimeType,
1062 BeanProperty property)
1063 {
1064 // Fast lookup from local lookup thingy works?
1065 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(runtimeType);
1066 if (ser != null) {
1067 return ser;
1068 }
1069 // If not, maybe shared map already has it?
1070 ser = _serializerCache.untypedValueSerializer(runtimeType);
1071 if (ser != null) {
1072 return ser;
1073 }
1074 try {
1075 return _createAndCacheUntypedSerializer(runtimeType, property);
1076 } catch (Exception e) {
1077 return null;
1078 }
1079 }
1080
1081 /*
1082 /**********************************************************
1083 /* Low-level methods for actually constructing and initializing
1084 /* serializers
1085 /**********************************************************
1086 */
1087
1088 /**
1089 * Method that will try to construct a value serializer; and if
1090 * one is successfully created, cache it for reuse.
1091 */
1092 protected JsonSerializer<Object> _createAndCacheUntypedSerializer(Class<?> type,
1093 BeanProperty property)
1094 throws JsonMappingException
1095 {
1096 JsonSerializer<Object> ser;
1097 try {
1098 ser = _createUntypedSerializer(_config.constructType(type), property);
1099 } catch (IllegalArgumentException iae) {
1100 /* We better only expose checked exceptions, since those
1101 * are what caller is expected to handle
1102 */
1103 throw new JsonMappingException(iae.getMessage(), null, iae);
1104 }
1105
1106 if (ser != null) {
1107 _serializerCache.addAndResolveNonTypedSerializer(type, ser, this);
1108 }
1109 return ser;
1110 }
1111
1112 protected JsonSerializer<Object> _createAndCacheUntypedSerializer(JavaType type,
1113 BeanProperty property)
1114 throws JsonMappingException
1115 {
1116 JsonSerializer<Object> ser;
1117 try {
1118 ser = _createUntypedSerializer(type, property);
1119 } catch (IllegalArgumentException iae) {
1120 /* We better only expose checked exceptions, since those
1121 * are what caller is expected to handle
1122 */
1123 throw new JsonMappingException(iae.getMessage(), null, iae);
1124 }
1125
1126 if (ser != null) {
1127 _serializerCache.addAndResolveNonTypedSerializer(type, ser, this);
1128 }
1129 return ser;
1130 }
1131
1132 protected JsonSerializer<Object> _createUntypedSerializer(JavaType type,
1133 BeanProperty property)
1134 throws JsonMappingException
1135 {
1136 /* 10-Dec-2008, tatu: Is there a possibility of infinite loops
1137 * here? Shouldn't be, given that we do not pass back-reference
1138 * to this provider. But if there is, we'd need to sync calls,
1139 * and keep track of creation chain to look for loops -- fairly
1140 * easy to do, but won't add yet since it seems unnecessary.
1141 */
1142 return (JsonSerializer<Object>)_serializerFactory.createSerializer(this, type, property);
1143 }
1144
1145 /**
1146 * Helper method called to resolve and contextualize given
1147 * serializer, if and as necessary.
1148 */
1149 protected JsonSerializer<Object> _handleContextualResolvable(JsonSerializer<?> ser,
1150 BeanProperty property)
1151 throws JsonMappingException
1152 {
1153 if (ser instanceof ResolvableSerializer) {
1154 ((ResolvableSerializer) ser).resolve(this);
1155 }
1156 return _handleContextual(ser, property);
1157 }
1158
1159 @SuppressWarnings("unchecked")
Tatu Saloranta1ef0dc32012-02-01 18:10:22 -08001160 protected JsonSerializer<Object> _handleResolvable(JsonSerializer<?> ser)
1161 throws JsonMappingException
1162 {
1163 if (ser instanceof ResolvableSerializer) {
1164 ((ResolvableSerializer) ser).resolve(this);
1165 }
1166 return (JsonSerializer<Object>) ser;
1167 }
1168
1169 @SuppressWarnings("unchecked")
Tatu6679cae2012-02-01 17:32:42 -08001170 protected JsonSerializer<Object> _handleContextual(JsonSerializer<?> ser,
1171 BeanProperty property)
1172 throws JsonMappingException
1173 {
1174 if (ser instanceof ContextualSerializer) {
1175 ser = ((ContextualSerializer) ser).createContextual(this, property);
1176 }
1177 return (JsonSerializer<Object>) ser;
1178 }
1179
1180 /*
1181 /**********************************************************
1182 /* Helper classes
1183 /**********************************************************
1184 */
1185
1186 /**
1187 * Standard implementation used by {@link ObjectMapper}; just implements
1188 * <code>createInstance</code> method which is abstract in
1189 * {@link SerializerProvider}
1190 */
1191 public final static class Impl extends SerializerProvider
1192 {
1193 public Impl() { super(); }
1194 private Impl( SerializerProvider src,
1195 SerializationConfig config,SerializerFactory f) {
1196 super(src, config, f);
1197 }
1198
1199 @Override
1200 public Impl createInstance(SerializationConfig config, SerializerFactory jsf) {
1201 return new Impl(this, config, jsf);
1202 }
1203
1204 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001205}