1 package com.fasterxml.jackson.databind;
2
3 import java.io.IOException;
4 import java.text.DateFormat;
5 import java.util.Date;
6 import java.util.Locale;
7 import java.util.TimeZone;
8
9 import com.fasterxml.jackson.annotation.JsonFormat;
10 import com.fasterxml.jackson.annotation.JsonInclude;
11 import com.fasterxml.jackson.annotation.ObjectIdGenerator;
12 import com.fasterxml.jackson.core.JsonGenerator;
13 import com.fasterxml.jackson.databind.cfg.ContextAttributes;
14 import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
15 import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
16 import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
17 import com.fasterxml.jackson.databind.introspect.Annotated;
18 import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
19 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
20 import com.fasterxml.jackson.databind.ser.*;
21 import com.fasterxml.jackson.databind.ser.impl.FailingSerializer;
22 import com.fasterxml.jackson.databind.ser.impl.ReadOnlyClassToSerializerMap;
23 import com.fasterxml.jackson.databind.ser.impl.TypeWrappedSerializer;
24 import com.fasterxml.jackson.databind.ser.impl.UnknownSerializer;
25 import com.fasterxml.jackson.databind.ser.impl.WritableObjectId;
26 import com.fasterxml.jackson.databind.ser.std.NullSerializer;
27 import com.fasterxml.jackson.databind.type.TypeFactory;
28 import com.fasterxml.jackson.databind.util.ClassUtil;
29
30 /**
31 * Class that defines API used by {@link ObjectMapper} and
32 * {@link JsonSerializer}s to obtain serializers capable of serializing
33 * instances of specific types; as well as the default implementation
34 * of the functionality.
35 *<p>
36 * Provider handles caching aspects of serializer handling; all construction
37 * details are delegated to {@link SerializerFactory} instance.
38 *<p>
39 * Object life-cycle is such that an initial instance ("blueprint") is created
40 * and referenced by {@link ObjectMapper} and {@link ObjectWriter} intances;
41 * but for actual usage, a configured instance is created by using
42 * a create method in sub-class
43 * {@link com.fasterxml.jackson.databind.ser.DefaultSerializerProvider}.
44 * Only this instance can be used for actual serialization calls; blueprint
45 * object is only to be used for creating instances.
46 */
47 public abstract class SerializerProvider
48 extends DatabindContext
49 {
50 /**
51 * Setting for determining whether mappings for "unknown classes" should be
52 * cached for faster resolution. Usually this isn't needed, but maybe it
53 * is in some cases?
54 */
55 protected final static boolean CACHE_UNKNOWN_MAPPINGS = false;
56
57 public final static JsonSerializer<Object> DEFAULT_NULL_KEY_SERIALIZER =
58 new FailingSerializer("Null key for a Map not allowed in JSON (use a converting NullKeySerializer?)");
59
60 /**
61 * Placeholder serializer used when <code>java.lang.Object</code> typed property
62 * is marked to be serialized.
63 *<br>
64 * NOTE: starting with 2.6, this instance is NOT used for any other types, and
65 * separate instances are constructed for "empty" Beans.
66 *<p>
67 * NOTE: changed to <code>protected</code> for 2.3; no need to be publicly available.
68 */
69 protected final static JsonSerializer<Object> DEFAULT_UNKNOWN_SERIALIZER = new UnknownSerializer();
70
71 /*
72 /**********************************************************
73 /* Configuration, general
74 /**********************************************************
75 */
76
77 /**
78 * Serialization configuration to use for serialization processing.
79 */
80 final protected SerializationConfig _config;
81
82 /**
83 * View used for currently active serialization, if any.
84 * Only set for non-blueprint instances.
85 */
86 final protected Class<?> _serializationView;
87
88 /*
89 /**********************************************************
90 /* Configuration, factories
91 /**********************************************************
92 */
93
94 /**
95 * Factory used for constructing actual serializer instances.
96 * Only set for non-blueprint instances.
97 */
98 final protected SerializerFactory _serializerFactory;
99
100 /*
101 /**********************************************************
102 /* Helper objects for caching, reuse
103 /**********************************************************
104 */
105
106 /**
107 * Cache for doing type-to-value-serializer lookups.
108 */
109 final protected SerializerCache _serializerCache;
110
111 /**
112 * Lazily-constructed holder for per-call attributes.
113 * Only set for non-blueprint instances.
114 *
115 * @since 2.3
116 */
117 protected transient ContextAttributes _attributes;
118
119 /*
120 /**********************************************************
121 /* Configuration, specialized serializers
122 /**********************************************************
123 */
124
125 /**
126 * Serializer that gets called for values of types for which no
127 * serializers can be constructed.
128 *<p>
129 * The default serializer will simply thrown an exception.
130 */
131 protected JsonSerializer<Object> _unknownTypeSerializer = DEFAULT_UNKNOWN_SERIALIZER;
132
133 /**
134 * Serializer used to output non-null keys of Maps (which will get
135 * output as JSON Objects), if not null; if null, us the standard
136 * default key serializer.
137 */
138 protected JsonSerializer<Object> _keySerializer;
139
140 /**
141 * Serializer used to output a null value. Default implementation
142 * writes nulls using {@link JsonGenerator#writeNull}.
143 */
144 protected JsonSerializer<Object> _nullValueSerializer = NullSerializer.instance;
145
146 /**
147 * Serializer used to (try to) output a null key, due to an entry of
148 * {@link java.util.Map} having null key.
149 * The default implementation will throw an exception if this happens;
150 * alternative implementation (like one that would write an Empty String)
151 * can be defined.
152 */
153 protected JsonSerializer<Object> _nullKeySerializer = DEFAULT_NULL_KEY_SERIALIZER;
154
155 /*
156 /**********************************************************
157 /* State, for non-blueprint instances: generic
158 /**********************************************************
159 */
160
161 /**
162 * For fast lookups, we will have a local non-shared read-only
163 * map that contains serializers previously fetched.
164 */
165 protected final ReadOnlyClassToSerializerMap _knownSerializers;
166
167 /**
168 * Lazily acquired and instantiated formatter object: initialized
169 * first time it is needed, reused afterwards. Used via instances
170 * (not blueprints), so that access need not be thread-safe.
171 */
172 protected DateFormat _dateFormat;
173
174 /**
175 * Flag set to indicate that we are using vanilla null value serialization
176 *
177 * @since 2.3
178 */
179 protected final boolean _stdNullValueSerializer;
180
181 /*
182 /**********************************************************
183 /* Life-cycle
184 /**********************************************************
185 */
186
187 /**
188 * Constructor for creating master (or "blue-print") provider object,
189 * which is only used as the template for constructing per-binding
190 * instances.
191 */
192 public SerializerProvider()
193 {
194 _config = null;
195 _serializerFactory = null;
196 _serializerCache = new SerializerCache();
197 // Blueprints doesn't have access to any serializers...
198 _knownSerializers = null;
199
200 _serializationView = null;
201 _attributes = null;
202
203 // not relevant for blueprint instance, could set either way:
204 _stdNullValueSerializer = true;
205 }
206
207 /**
208 * "Copy-constructor", used by sub-classes when creating actual non-blueprint
209 * instances to use.
210 *
211 * @param src Blueprint object used as the baseline for this instance
212 */
213 protected SerializerProvider(SerializerProvider src,
214 SerializationConfig config, SerializerFactory f)
215 {
216 _serializerFactory = f;
217 _config = config;
218
219 _serializerCache = src._serializerCache;
220 _unknownTypeSerializer = src._unknownTypeSerializer;
221 _keySerializer = src._keySerializer;
222 _nullValueSerializer = src._nullValueSerializer;
223 _nullKeySerializer = src._nullKeySerializer;
224
225 _stdNullValueSerializer = (_nullValueSerializer == DEFAULT_NULL_KEY_SERIALIZER);
226
227 _serializationView = config.getActiveView();
228 _attributes = config.getAttributes();
229
230 /* Non-blueprint instances do have a read-only map; one that doesn't
231 * need synchronization for lookups.
232 */
233 _knownSerializers = _serializerCache.getReadOnlyLookupMap();
234 }
235
236 /**
237 * Copy-constructor used when making a copy of a blueprint instance.
238 *
239 * @since 2.5
240 */
241 protected SerializerProvider(SerializerProvider src)
242 {
243 // since this is assumed to be a blue-print instance, many settings missing:
244 _config = null;
245 _serializationView = null;
246 _serializerFactory = null;
247 _knownSerializers = null;
248
249 // and others initialized to default empty state
250 _serializerCache = new SerializerCache();
251
252 _unknownTypeSerializer = src._unknownTypeSerializer;
253 _keySerializer = src._keySerializer;
254 _nullValueSerializer = src._nullValueSerializer;
255 _nullKeySerializer = src._nullKeySerializer;
256
257 _stdNullValueSerializer = src._stdNullValueSerializer;
258 }
259
260 /*
261 /**********************************************************
262 /* Methods for configuring default settings
263 /**********************************************************
264 */
265
266 /**
267 * Method that can be used to specify serializer that will be
268 * used to write JSON property names matching null keys for Java
269 * Maps (which will throw an exception if try write such property
270 * name)
271 */
272 public void setDefaultKeySerializer(JsonSerializer<Object> ks)
273 {
274 if (ks == null) {
275 throw new IllegalArgumentException("Cannot pass null JsonSerializer");
276 }
277 _keySerializer = ks;
278 }
279
280 /**
281 * Method that can be used to specify serializer that will be
282 * used to write JSON values matching Java null values
283 * instead of default one (which simply writes JSON null).
284 *<p>
285 * Note that you can get finer control over serializer to use by overriding
286 * {@link #findNullValueSerializer}, which gets called once per each
287 * property.
288 */
289 public void setNullValueSerializer(JsonSerializer<Object> nvs)
290 {
291 if (nvs == null) {
292 throw new IllegalArgumentException("Cannot pass null JsonSerializer");
293 }
294 _nullValueSerializer = nvs;
295 }
296
297 /**
298 * Method that can be used to specify serializer to use for serializing
299 * all non-null JSON property names, unless more specific key serializer
300 * is found (i.e. if not custom key serializer has been registered for
301 * Java type).
302 *<p>
303 * Note that key serializer registration are different from value serializer
304 * registrations.
305 */
306 public void setNullKeySerializer(JsonSerializer<Object> nks)
307 {
308 if (nks == null) {
309 throw new IllegalArgumentException("Cannot pass null JsonSerializer");
310 }
311 _nullKeySerializer = nks;
312 }
313
314 /*
315 /**********************************************************
316 /* DatabindContext implementation (and closely related but ser-specific)
317 /**********************************************************
318 */
319
320 /**
321 * Method for accessing configuration for the serialization processing.
322 */
323 @Override
324 public final SerializationConfig getConfig() { return _config; }
325
326 @Override
327 public final AnnotationIntrospector getAnnotationIntrospector() {
328 return _config.getAnnotationIntrospector();
329 }
330
331 @Override
332 public final TypeFactory getTypeFactory() {
333 return _config.getTypeFactory();
334 }
335
336 @Override // since 2.11
337 public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass)
338 throws IllegalArgumentException
339 {
340 if (baseType.hasRawClass(subclass)) {
341 return baseType;
342 }
343 // Need little bit different handling due to [databind#2632]; pass `true` for
344 // "relaxed" type assingment checks.
345 return getConfig().getTypeFactory().constructSpecializedType(baseType, subclass, true);
346 }
347
348 @Override
349 public final Class<?> getActiveView() { return _serializationView; }
350
351 /**
352 * @deprecated Since 2.2, use {@link #getActiveView} instead.
353 */
354 @Deprecated
355 public final Class<?> getSerializationView() { return _serializationView; }
356
357 @Override
358 public final boolean canOverrideAccessModifiers() {
359 return _config.canOverrideAccessModifiers();
360 }
361
362 @Override
363 public final boolean isEnabled(MapperFeature feature) {
364 return _config.isEnabled(feature);
365 }
366
367 @Override
368 public final JsonFormat.Value getDefaultPropertyFormat(Class<?> baseType) {
369 return _config.getDefaultPropertyFormat(baseType);
370 }
371
372 /**
373 * @since 2.8
374 */
375 public final JsonInclude.Value getDefaultPropertyInclusion(Class<?> baseType) {
376 return _config.getDefaultPropertyInclusion(baseType);
377 }
378
379 /**
380 * Method for accessing default Locale to use: convenience method for
381 *<pre>
382 * getConfig().getLocale();
383 *</pre>
384 */
385 @Override
386 public Locale getLocale() {
387 return _config.getLocale();
388 }
389
390 /**
391 * Method for accessing default TimeZone to use: convenience method for
392 *<pre>
393 * getConfig().getTimeZone();
394 *</pre>
395 */
396 @Override
397 public TimeZone getTimeZone() {
398 return _config.getTimeZone();
399 }
400
401 /*
402 /**********************************************************
403 /* Generic attributes (2.3+)
404 /**********************************************************
405 */
406
407 @Override
408 public Object getAttribute(Object key) {
409 return _attributes.getAttribute(key);
410 }
411
412 @Override
413 public SerializerProvider setAttribute(Object key, Object value)
414 {
415 _attributes = _attributes.withPerCallAttribute(key, value);
416 return this;
417 }
418
419 /*
420 /**********************************************************
421 /* Access to general configuration
422 /**********************************************************
423 */
424
425 /**
426 * Convenience method for checking whether specified serialization
427 * feature is enabled or not.
428 * Shortcut for:
429 *<pre>
430 * getConfig().isEnabled(feature);
431 *</pre>
432 */
433 public final boolean isEnabled(SerializationFeature feature) {
434 return _config.isEnabled(feature);
435 }
436
437 /**
438 * "Bulk" access method for checking that all features specified by
439 * mask are enabled.
440 *
441 * @since 2.3
442 */
443 public final boolean hasSerializationFeatures(int featureMask) {
444 return _config.hasSerializationFeatures(featureMask);
445 }
446
447 /**
448 * Convenience method for accessing provider to find serialization filters used,
449 * equivalent to calling:
450 *<pre>
451 * getConfig().getFilterProvider();
452 *</pre>
453 */
454 public final FilterProvider getFilterProvider() {
455 return _config.getFilterProvider();
456 }
457
458 /**
459 *<p>
460 * NOTE: current implementation simply returns `null` as generator is not yet
461 * assigned to this provider.
462 *
463 * @since 2.8
464 */
465 public JsonGenerator getGenerator() {
466 return null;
467 }
468
469 /*
470 /**********************************************************
471 /* Access to Object Id aspects
472 /**********************************************************
473 */
474
475 /**
476 * Method called to find the Object Id for given POJO, if one
477 * has been generated. Will always return a non-null Object;
478 * contents vary depending on whether an Object Id already
479 * exists or not.
480 */
481 public abstract WritableObjectId findObjectId(Object forPojo,
482 ObjectIdGenerator<?> generatorType);
483
484 /*
485 /**********************************************************
486 /* General serializer locating functionality
487 /**********************************************************
488 */
489
490 /**
491 * Method called to get hold of a serializer for a value of given type;
492 * or if no such serializer can be found, a default handler (which
493 * may do a best-effort generic serialization or just simply
494 * throw an exception when invoked).
495 *<p>
496 * Note: this method is only called for non-null values; not for keys
497 * or null values. For these, check out other accessor methods.
498 *<p>
499 * Note that serializers produced should NOT handle polymorphic serialization
500 * aspects; separate {@link TypeSerializer} is to be constructed by caller
501 * if and as necessary.
502 *
503 * @throws JsonMappingException if there are fatal problems with
504 * accessing suitable serializer; including that of not
505 * finding any serializer
506 */
507 @SuppressWarnings("unchecked")
508 public JsonSerializer<Object> findValueSerializer(Class<?> valueType, BeanProperty property)
509 throws JsonMappingException
510 {
511 // Fast lookup from local lookup thingy works?
512 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
513 if (ser == null) {
514 // If not, maybe shared map already has it?
515 ser = _serializerCache.untypedValueSerializer(valueType);
516 if (ser == null) {
517 // ... possibly as fully typed?
518 ser = _serializerCache.untypedValueSerializer(_config.constructType(valueType));
519 if (ser == null) {
520 // If neither, must create
521 ser = _createAndCacheUntypedSerializer(valueType);
522 // Not found? Must use the unknown type serializer, which will report error later on
523 if (ser == null) {
524 ser = getUnknownTypeSerializer(valueType);
525 // Should this be added to lookups?
526 if (CACHE_UNKNOWN_MAPPINGS) {
527 _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
528 }
529 return ser;
530 }
531 }
532 }
533 }
534 // at this point, resolution has occured, but not contextualization
535 return (JsonSerializer<Object>) handleSecondaryContextualization(ser, property);
536 }
537
538 /**
539 * Similar to {@link #findValueSerializer(Class,BeanProperty)}, but takes
540 * full generics-aware type instead of raw class.
541 * This is necessary for accurate handling of external type information,
542 * to handle polymorphic types.
543 *<p>
544 * Note: this call will also contextualize serializer before returning it.
545 *
546 * @param property When creating secondary serializers, property for which
547 * serializer is needed: annotations of the property (or bean that contains it)
548 * may be checked to create contextual serializers.
549 */
550 @SuppressWarnings("unchecked")
551 public JsonSerializer<Object> findValueSerializer(JavaType valueType, BeanProperty property)
552 throws JsonMappingException
553 {
554 if (valueType == null) {
555 reportMappingProblem("Null passed for `valueType` of `findValueSerializer()`");
556 }
557 // (see comments from above method)
558 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
559 if (ser == null) {
560 ser = _serializerCache.untypedValueSerializer(valueType);
561 if (ser == null) {
562 ser = _createAndCacheUntypedSerializer(valueType);
563 if (ser == null) {
564 ser = getUnknownTypeSerializer(valueType.getRawClass());
565 if (CACHE_UNKNOWN_MAPPINGS) {
566 _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
567 }
568 return ser;
569 }
570 }
571 }
572 return (JsonSerializer<Object>) handleSecondaryContextualization(ser, property);
573 }
574
575 /**
576 * Method variant used when we do NOT want contextualization to happen; it will need
577 * to be handled at a later point, but caller wants to be able to do that
578 * as needed; sometimes to avoid infinite loops
579 *
580 * @since 2.5
581 */
582 public JsonSerializer<Object> findValueSerializer(Class<?> valueType) throws JsonMappingException
583 {
584 // (see comments from above method)
585 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
586 if (ser == null) {
587 ser = _serializerCache.untypedValueSerializer(valueType);
588 if (ser == null) {
589 ser = _serializerCache.untypedValueSerializer(_config.constructType(valueType));
590 if (ser == null) {
591 ser = _createAndCacheUntypedSerializer(valueType);
592 if (ser == null) {
593 ser = getUnknownTypeSerializer(valueType);
594 if (CACHE_UNKNOWN_MAPPINGS) {
595 _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
596 }
597 }
598 }
599 }
600 }
601 return ser;
602 }
603
604 /**
605 * Method variant used when we do NOT want contextualization to happen; it will need
606 * to be handled at a later point, but caller wants to be able to do that
607 * as needed; sometimes to avoid infinite loops
608 *
609 * @since 2.5
610 */
611 public JsonSerializer<Object> findValueSerializer(JavaType valueType)
612 throws JsonMappingException
613 {
614 // (see comments from above method)
615 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
616 if (ser == null) {
617 ser = _serializerCache.untypedValueSerializer(valueType);
618 if (ser == null) {
619 ser = _createAndCacheUntypedSerializer(valueType);
620 if (ser == null) {
621 ser = getUnknownTypeSerializer(valueType.getRawClass());
622 if (CACHE_UNKNOWN_MAPPINGS) {
623 _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
624 }
625 }
626 }
627 }
628 return ser;
629 }
630
631 /**
632 * Similar to {@link #findValueSerializer(JavaType, BeanProperty)}, but used
633 * when finding "primary" property value serializer (one directly handling
634 * value of the property). Difference has to do with contextual resolution,
635 * and method(s) called: this method should only be called when caller is
636 * certain that this is the primary property value serializer.
637 *
638 * @param valueType Type of values to serialize
639 * @param property Property that is being handled; will never be null, and its
640 * type has to match <code>valueType</code> parameter.
641 *
642 * @since 2.3
643 */
644 @SuppressWarnings("unchecked")
645 public JsonSerializer<Object> findPrimaryPropertySerializer(JavaType valueType, BeanProperty property)
646 throws JsonMappingException
647 {
648 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
649 if (ser == null) {
650 ser = _serializerCache.untypedValueSerializer(valueType);
651 if (ser == null) {
652 ser = _createAndCacheUntypedSerializer(valueType);
653 if (ser == null) {
654 ser = getUnknownTypeSerializer(valueType.getRawClass());
655 // Should this be added to lookups?
656 if (CACHE_UNKNOWN_MAPPINGS) {
657 _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
658 }
659 return ser;
660 }
661 }
662 }
663 return (JsonSerializer<Object>) handlePrimaryContextualization(ser, property);
664 }
665
666 /**
667 * See {@link #findPrimaryPropertySerializer(JavaType, BeanProperty)}
668 *
669 * @since 2.3
670 */
671 @SuppressWarnings("unchecked")
672 public JsonSerializer<Object> findPrimaryPropertySerializer(Class<?> valueType,
673 BeanProperty property)
674 throws JsonMappingException
675 {
676 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
677 if (ser == null) {
678 ser = _serializerCache.untypedValueSerializer(valueType);
679 if (ser == null) {
680 ser = _serializerCache.untypedValueSerializer(_config.constructType(valueType));
681 if (ser == null) {
682 ser = _createAndCacheUntypedSerializer(valueType);
683 if (ser == null) {
684 ser = getUnknownTypeSerializer(valueType);
685 if (CACHE_UNKNOWN_MAPPINGS) {
686 _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
687 }
688 return ser;
689 }
690 }
691 }
692 }
693 return (JsonSerializer<Object>) handlePrimaryContextualization(ser, property);
694 }
695
696 /**
697 * Alternative to {@link #findPrimaryPropertySerializer(JavaType, BeanProperty)} called not
698 * for primary value, but "content" of such primary serializer: element of an array or
699 * {@link java.util.Collection}, value of {@link java.util.Map} entry and so on.
700 * This means that {@code property} passed (if any) does NOT represent value for which
701 * serializer is requested but its secondary type (or secondary type of that type,
702 * recursively).
703 *<p>
704 * Serializer returned SHOULD NOT handle type information; caller will (have to) add
705 * suitable wrapping if necessary.
706 *<p>
707 * Note: this call will also contextualize serializer (call {@code createContextual()}
708 * before returning it, if applicable (implements {@code ContextualSerializer})
709 *
710 * @param valueType Type of values to serialize
711 * @param property Property that indirectly refers to value being serialized (optional,
712 * may be {@code null} for root level serializers)
713 *
714 * @since 2.11
715 */
716 @SuppressWarnings("unchecked")
717 public JsonSerializer<Object> findContentValueSerializer(JavaType valueType, BeanProperty property)
718 throws JsonMappingException
719 {
720 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
721 if (ser == null) {
722 ser = _serializerCache.untypedValueSerializer(valueType);
723 if (ser == null) {
724 ser = _createAndCacheUntypedSerializer(valueType);
725 if (ser == null) {
726 ser = getUnknownTypeSerializer(valueType.getRawClass());
727 // Should this be added to lookups?
728 if (CACHE_UNKNOWN_MAPPINGS) {
729 _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
730 }
731 return ser;
732 }
733 }
734 }
735 return (JsonSerializer<Object>) handleSecondaryContextualization(ser, property);
736 }
737
738 /**
739 * See {@link #findContentValueSerializer(JavaType, BeanProperty)}.
740 *
741 * @since 2.11
742 */
743 @SuppressWarnings("unchecked")
744 public JsonSerializer<Object> findContentValueSerializer(Class<?> valueType,
745 BeanProperty property)
746 throws JsonMappingException
747 {
748 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
749 if (ser == null) {
750 ser = _serializerCache.untypedValueSerializer(valueType);
751 if (ser == null) {
752 ser = _serializerCache.untypedValueSerializer(_config.constructType(valueType));
753 if (ser == null) {
754 ser = _createAndCacheUntypedSerializer(valueType);
755 if (ser == null) {
756 ser = getUnknownTypeSerializer(valueType);
757 if (CACHE_UNKNOWN_MAPPINGS) {
758 _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
759 }
760 return ser;
761 }
762 }
763 }
764 }
765 return (JsonSerializer<Object>) handleSecondaryContextualization(ser, property);
766 }
767
768 /**
769 * Method called to locate regular serializer, matching type serializer,
770 * and if both found, wrap them in a serializer that calls both in correct
771 * sequence. This method is currently only used for root-level serializer
772 * handling to allow for simpler caching. A call can always be replaced
773 * by equivalent calls to access serializer and type serializer separately.
774 *
775 * @param valueType Type for purpose of locating a serializer; usually dynamic
776 * runtime type, but can also be static declared type, depending on configuration
777 * @param cache Whether resulting value serializer should be cached or not; this is just
778 * a hint
779 * @param property When creating secondary serializers, property for which
780 * serializer is needed: annotations of the property (or bean that contains it)
781 * may be checked to create contextual serializers.
782 */
783 public JsonSerializer<Object> findTypedValueSerializer(Class<?> valueType,
784 boolean cache, BeanProperty property)
785 throws JsonMappingException
786 {
787 // Two-phase lookups; local non-shared cache, then shared:
788 JsonSerializer<Object> ser = _knownSerializers.typedValueSerializer(valueType);
789 if (ser != null) {
790 return ser;
791 }
792 // If not, maybe shared map already has it?
793 ser = _serializerCache.typedValueSerializer(valueType);
794 if (ser != null) {
795 return ser;
796 }
797
798 // Well, let's just compose from pieces:
799 ser = findValueSerializer(valueType, property);
800 TypeSerializer typeSer = _serializerFactory.createTypeSerializer(_config,
801 _config.constructType(valueType));
802 if (typeSer != null) {
803 typeSer = typeSer.forProperty(property);
804 ser = new TypeWrappedSerializer(typeSer, ser);
805 }
806 if (cache) {
807 _serializerCache.addTypedSerializer(valueType, ser);
808 }
809 return ser;
810 }
811
812 /**
813 * Method called to locate regular serializer, matching type serializer,
814 * and if both found, wrap them in a serializer that calls both in correct
815 * sequence. This method is currently only used for root-level serializer
816 * handling to allow for simpler caching. A call can always be replaced
817 * by equivalent calls to access serializer and type serializer separately.
818 *
819 * @param valueType Declared type of value being serialized (which may not
820 * be actual runtime type); used for finding both value serializer and
821 * type serializer to use for adding polymorphic type (if any)
822 * @param cache Whether resulting value serializer should be cached or not; this is just
823 * a hint
824 * @param property When creating secondary serializers, property for which
825 * serializer is needed: annotations of the property (or bean that contains it)
826 * may be checked to create contextual serializers.
827 */
828 public JsonSerializer<Object> findTypedValueSerializer(JavaType valueType, boolean cache,
829 BeanProperty property)
830 throws JsonMappingException
831 {
832 // Two-phase lookups; local non-shared cache, then shared:
833 JsonSerializer<Object> ser = _knownSerializers.typedValueSerializer(valueType);
834 if (ser != null) {
835 return ser;
836 }
837 // If not, maybe shared map already has it?
838 ser = _serializerCache.typedValueSerializer(valueType);
839 if (ser != null) {
840 return ser;
841 }
842
843 // Well, let's just compose from pieces:
844 ser = findValueSerializer(valueType, property);
845 TypeSerializer typeSer = _serializerFactory.createTypeSerializer(_config, valueType);
846 if (typeSer != null) {
847 typeSer = typeSer.forProperty(property);
848 ser = new TypeWrappedSerializer(typeSer, ser);
849 }
850 if (cache) {
851 _serializerCache.addTypedSerializer(valueType, ser);
852 }
853 return ser;
854 }
855
856 /**
857 * Method called to get the {@link TypeSerializer} to use for including Type Id necessary
858 * for serializing for the given Java class.
859 * Useful for schema generators.
860 *
861 * @since 2.6
862 */
863 public TypeSerializer findTypeSerializer(JavaType javaType) throws JsonMappingException {
864 return _serializerFactory.createTypeSerializer(_config, javaType);
865 }
866
867 /**
868 * Method called to get the serializer to use for serializing
869 * non-null Map keys. Separation from regular
870 * {@link #findValueSerializer} method is because actual write
871 * method must be different (@link JsonGenerator#writeFieldName};
872 * but also since behavior for some key types may differ.
873 *<p>
874 * Note that the serializer itself can be called with instances
875 * of any Java object, but not nulls.
876 */
877 public JsonSerializer<Object> findKeySerializer(JavaType keyType, BeanProperty property)
878 throws JsonMappingException
879 {
880 JsonSerializer<Object> ser = _serializerFactory.createKeySerializer(this, keyType, _keySerializer);
881 // 25-Feb-2011, tatu: As per [JACKSON-519], need to ensure contextuality works here, too
882 return _handleContextualResolvable(ser, property);
883 }
884
885 /**
886 * @since 2.7
887 */
888 public JsonSerializer<Object> findKeySerializer(Class<?> rawKeyType, BeanProperty property)
889 throws JsonMappingException
890 {
891 return findKeySerializer(_config.constructType(rawKeyType), property);
892 }
893
894 /*
895 /********************************************************
896 /* Accessors for specialized serializers
897 /********************************************************
898 */
899
900 /**
901 * @since 2.0
902 */
903 public JsonSerializer<Object> getDefaultNullKeySerializer() {
904 return _nullKeySerializer;
905 }
906
907 /**
908 * @since 2.0
909 */
910 public JsonSerializer<Object> getDefaultNullValueSerializer() {
911 return _nullValueSerializer;
912 }
913
914 /**
915 * Method called to get the serializer to use for serializing
916 * Map keys that are nulls: this is needed since JSON does not allow
917 * any non-String value as key, including null.
918 *<p>
919 * Typically, returned serializer
920 * will either throw an exception, or use an empty String; but
921 * other behaviors are possible.
922 */
923 /**
924 * Method called to find a serializer to use for null values for given
925 * declared type. Note that type is completely based on declared type,
926 * since nulls in Java have no type and thus runtime type cannot be
927 * determined.
928 *
929 * @since 2.0
930 */
931 public JsonSerializer<Object> findNullKeySerializer(JavaType serializationType,
932 BeanProperty property)
933 throws JsonMappingException
934 {
935 return _nullKeySerializer;
936 }
937
938 /**
939 * Method called to get the serializer to use for serializing null
940 * values for specified property.
941 *<p>
942 * Default implementation simply calls {@link #getDefaultNullValueSerializer()};
943 * can be overridden to add custom null serialization for properties
944 * of certain type or name. This gives method full granularity to basically
945 * override null handling for any specific property or class of properties.
946 *
947 * @since 2.0
948 */
949 public JsonSerializer<Object> findNullValueSerializer(BeanProperty property)
950 throws JsonMappingException {
951 return _nullValueSerializer;
952 }
953
954 /**
955 * Method called to get the serializer to use if provider
956 * cannot determine an actual type-specific serializer
957 * to use; typically when none of {@link SerializerFactory}
958 * instances are able to construct a serializer.
959 *<p>
960 * Typically, returned serializer will throw an exception,
961 * although alternatively {@link com.fasterxml.jackson.databind.ser.std.ToStringSerializer}
962 * could be returned as well.
963 *
964 * @param unknownType Type for which no serializer is found
965 */
966 public JsonSerializer<Object> getUnknownTypeSerializer(Class<?> unknownType) {
967 // 23-Apr-2015, tatu: Only return shared instance if nominal type is Object.class
968 if (unknownType == Object.class) {
969 return _unknownTypeSerializer;
970 }
971 // otherwise construct explicit instance with property handled type
972 return new UnknownSerializer(unknownType);
973 }
974
975 /**
976 * Helper method called to see if given serializer is considered to be
977 * something returned by {@link #getUnknownTypeSerializer}, that is, something
978 * for which no regular serializer was found or constructed.
979 *
980 * @since 2.5
981 */
982 public boolean isUnknownTypeSerializer(JsonSerializer<?> ser) {
983 if ((ser == _unknownTypeSerializer) || (ser == null)) {
984 return true;
985 }
986 // 23-Apr-2015, tatu: "empty" serializer is trickier; needs to consider
987 // error handling
988 if (isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)) {
989 if (ser.getClass() == UnknownSerializer.class) {
990 return true;
991 }
992 }
993 return false;
994 }
995
996 /*
997 /**********************************************************
998 /* Methods for creating instances based on annotations
999 /**********************************************************
1000 */
1001
1002 /**
1003 * Method that can be called to construct and configure serializer instance,
1004 * either given a {@link Class} to instantiate (with default constructor),
1005 * or an uninitialized serializer instance.
1006 * Either way, serialize will be properly resolved
1007 * (via {@link com.fasterxml.jackson.databind.ser.ResolvableSerializer}) and/or contextualized
1008 * (via {@link com.fasterxml.jackson.databind.ser.ContextualSerializer}) as necessary.
1009 *
1010 * @param annotated Annotated entity that contained definition
1011 * @param serDef Serializer definition: either an instance or class
1012 */
1013 public abstract JsonSerializer<Object> serializerInstance(Annotated annotated,
1014 Object serDef)
1015 throws JsonMappingException;
1016
1017 /**
1018 * Method that can be called to construct and configure {@link JsonInclude}
1019 * filter instance,
1020 * given a {@link Class} to instantiate (with default constructor, by default).
1021 *
1022 * @param forProperty (optional) If filter is created for a property, that property;
1023 * `null` if filter created via defaulting, global or per-type.
1024 *
1025 * @since 2.9
1026 */
1027 public abstract Object includeFilterInstance(BeanPropertyDefinition forProperty,
1028 Class<?> filterClass)
1029 throws JsonMappingException;
1030
1031 /**
1032 * Follow-up method that may be called after calling {@link #includeFilterInstance},
1033 * to check handling of `null` values by the filter.
1034 *
1035 * @since 2.9
1036 */
1037 public abstract boolean includeFilterSuppressNulls(Object filter)
1038 throws JsonMappingException;
1039
1040 /*
1041 /**********************************************************
1042 /* Support for contextualization
1043 /**********************************************************
1044 */
1045
1046 /**
1047 * Method called for primary property serializers (ones
1048 * directly created to serialize values of a POJO property),
1049 * to handle details of resolving
1050 * {@link ContextualSerializer} with given property context.
1051 *
1052 * @param property Property for which the given primary serializer is used; never null.
1053 *
1054 * @since 2.3
1055 */
1056 public JsonSerializer<?> handlePrimaryContextualization(JsonSerializer<?> ser,
1057 BeanProperty property)
1058 throws JsonMappingException
1059 {
1060 if (ser != null) {
1061 if (ser instanceof ContextualSerializer) {
1062 ser = ((ContextualSerializer) ser).createContextual(this, property);
1063 }
1064 }
1065 return ser;
1066 }
1067
1068 /**
1069 * Method called for secondary property serializers (ones
1070 * NOT directly created to serialize values of a POJO property
1071 * but instead created as a dependant serializer -- such as value serializers
1072 * for structured types, or serializers for root values)
1073 * to handle details of resolving
1074 * {@link ContextualDeserializer} with given property context.
1075 * Given that these serializers are not directly related to given property
1076 * (or, in case of root value property, to any property), annotations
1077 * accessible may or may not be relevant.
1078 *
1079 * @param property Property for which serializer is used, if any; null
1080 * when deserializing root values
1081 *
1082 * @since 2.3
1083 */
1084 public JsonSerializer<?> handleSecondaryContextualization(JsonSerializer<?> ser,
1085 BeanProperty property)
1086 throws JsonMappingException
1087 {
1088 if (ser != null) {
1089 if (ser instanceof ContextualSerializer) {
1090 ser = ((ContextualSerializer) ser).createContextual(this, property);
1091 }
1092 }
1093 return ser;
1094 }
1095
1096 /*
1097 /********************************************************
1098 /* Convenience methods for serializing using default methods
1099 /********************************************************
1100 */
1101
1102 /**
1103 * Convenience method that will serialize given value (which can be
1104 * null) using standard serializer locating functionality. It can
1105 * be called for all values including field and Map values, but usually
1106 * field values are best handled calling
1107 * {@link #defaultSerializeField} instead.
1108 */
1109 public final void defaultSerializeValue(Object value, JsonGenerator gen) throws IOException
1110 {
1111 if (value == null) {
1112 if (_stdNullValueSerializer) { // minor perf optimization
1113 gen.writeNull();
1114 } else {
1115 _nullValueSerializer.serialize(null, gen, this);
1116 }
1117 } else {
1118 Class<?> cls = value.getClass();
1119 findTypedValueSerializer(cls, true, null).serialize(value, gen, this);
1120 }
1121 }
1122
1123 /**
1124 * Convenience method that will serialize given field with specified
1125 * value. Value may be null. Serializer is done using the usual
1126 * null) using standard serializer locating functionality.
1127 */
1128 public final void defaultSerializeField(String fieldName, Object value, JsonGenerator gen)
1129 throws IOException
1130 {
1131 gen.writeFieldName(fieldName);
1132 if (value == null) {
1133 /* Note: can't easily check for suppression at this point
1134 * any more; caller must check it.
1135 */
1136 if (_stdNullValueSerializer) { // minor perf optimization
1137 gen.writeNull();
1138 } else {
1139 _nullValueSerializer.serialize(null, gen, this);
1140 }
1141 } else {
1142 Class<?> cls = value.getClass();
1143 findTypedValueSerializer(cls, true, null).serialize(value, gen, this);
1144 }
1145 }
1146
1147 /**
1148 * Method that will handle serialization of Date(-like) values, using
1149 * {@link SerializationConfig} settings to determine expected serialization
1150 * behavior.
1151 * Note: date here means "full" date, that is, date AND time, as per
1152 * Java convention (and not date-only values like in SQL)
1153 */
1154 public final void defaultSerializeDateValue(long timestamp, JsonGenerator gen)
1155 throws IOException
1156 {
1157 if (isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)) {
1158 gen.writeNumber(timestamp);
1159 } else {
1160 gen.writeString(_dateFormat().format(new Date(timestamp)));
1161 }
1162 }
1163
1164 /**
1165 * Method that will handle serialization of Date(-like) values, using
1166 * {@link SerializationConfig} settings to determine expected serialization
1167 * behavior.
1168 * Note: date here means "full" date, that is, date AND time, as per
1169 * Java convention (and not date-only values like in SQL)
1170 */
1171 public final void defaultSerializeDateValue(Date date, JsonGenerator gen) throws IOException
1172 {
1173 if (isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)) {
1174 gen.writeNumber(date.getTime());
1175 } else {
1176 gen.writeString(_dateFormat().format(date));
1177 }
1178 }
1179
1180 /**
1181 * Method that will handle serialization of Dates used as {@link java.util.Map} keys,
1182 * based on {@link SerializationFeature#WRITE_DATE_KEYS_AS_TIMESTAMPS}
1183 * value (and if using textual representation, configured date format)
1184 */
1185 public void defaultSerializeDateKey(long timestamp, JsonGenerator gen) throws IOException
1186 {
1187 if (isEnabled(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)) {
1188 gen.writeFieldName(String.valueOf(timestamp));
1189 } else {
1190 gen.writeFieldName(_dateFormat().format(new Date(timestamp)));
1191 }
1192 }
1193
1194 /**
1195 * Method that will handle serialization of Dates used as {@link java.util.Map} keys,
1196 * based on {@link SerializationFeature#WRITE_DATE_KEYS_AS_TIMESTAMPS}
1197 * value (and if using textual representation, configured date format)
1198 */
1199 public void defaultSerializeDateKey(Date date, JsonGenerator gen) throws IOException
1200 {
1201 if (isEnabled(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)) {
1202 gen.writeFieldName(String.valueOf(date.getTime()));
1203 } else {
1204 gen.writeFieldName(_dateFormat().format(date));
1205 }
1206 }
1207
1208 public final void defaultSerializeNull(JsonGenerator gen) throws IOException
1209 {
1210 if (_stdNullValueSerializer) { // minor perf optimization
1211 gen.writeNull();
1212 } else {
1213 _nullValueSerializer.serialize(null, gen, this);
1214 }
1215 }
1216
1217 /*
1218 /********************************************************
1219 /* Error reporting
1220 /********************************************************
1221 */
1222
1223 /**
1224 * Helper method called to indicate problem; default behavior is to construct and
1225 * throw a {@link JsonMappingException}, but in future may collect more than one
1226 * and only throw after certain number, or at the end of serialization.
1227 *
1228 * @since 2.8
1229 */
1230 public void reportMappingProblem(String message, Object... args) throws JsonMappingException {
1231 throw mappingException(message, args);
1232 }
1233
1234 /**
1235 * Helper method called to indicate problem in POJO (serialization) definitions or settings
1236 * regarding specific Java type, unrelated to actual JSON content to map.
1237 * Default behavior is to construct and throw a {@link JsonMappingException}.
1238 *
1239 * @since 2.9
1240 */
1241 public <T> T reportBadTypeDefinition(BeanDescription bean,
1242 String msg, Object... msgArgs) throws JsonMappingException {
1243 String beanDesc = "N/A";
1244 if (bean != null) {
1245 beanDesc = ClassUtil.nameOf(bean.getBeanClass());
1246 }
1247 msg = String.format("Invalid type definition for type %s: %s",
1248 beanDesc, _format(msg, msgArgs));
1249 throw InvalidDefinitionException.from(getGenerator(), msg, bean, null);
1250 }
1251
1252 /**
1253 * Helper method called to indicate problem in POJO (serialization) definitions or settings
1254 * regarding specific property (of a type), unrelated to actual JSON content to map.
1255 * Default behavior is to construct and throw a {@link JsonMappingException}.
1256 *
1257 * @since 2.9
1258 */
1259 public <T> T reportBadPropertyDefinition(BeanDescription bean, BeanPropertyDefinition prop,
1260 String message, Object... msgArgs) throws JsonMappingException {
1261 message = _format(message, msgArgs);
1262 String propName = "N/A";
1263 if (prop != null) {
1264 propName = _quotedString(prop.getName());
1265 }
1266 String beanDesc = "N/A";
1267 if (bean != null) {
1268 beanDesc = ClassUtil.nameOf(bean.getBeanClass());
1269 }
1270 message = String.format("Invalid definition for property %s (of type %s): %s",
1271 propName, beanDesc, message);
1272 throw InvalidDefinitionException.from(getGenerator(), message, bean, prop);
1273 }
1274
1275 @Override
1276 public <T> T reportBadDefinition(JavaType type, String msg) throws JsonMappingException {
1277 throw InvalidDefinitionException.from(getGenerator(), msg, type);
1278 }
1279
1280 /**
1281 * @since 2.9
1282 */
1283 public <T> T reportBadDefinition(JavaType type, String msg, Throwable cause)
1284 throws JsonMappingException {
1285 InvalidDefinitionException e = InvalidDefinitionException.from(getGenerator(), msg, type);
1286 e.initCause(cause);
1287 throw e;
1288 }
1289
1290 /**
1291 * @since 2.9
1292 */
1293 public <T> T reportBadDefinition(Class<?> raw, String msg, Throwable cause)
1294 throws JsonMappingException {
1295 InvalidDefinitionException e = InvalidDefinitionException.from(getGenerator(), msg, constructType(raw));
1296 e.initCause(cause);
1297 throw e;
1298 }
1299
1300 /**
1301 * Helper method called to indicate problem; default behavior is to construct and
1302 * throw a {@link JsonMappingException}, but in future may collect more than one
1303 * and only throw after certain number, or at the end of serialization.
1304 *
1305 * @since 2.8
1306 */
1307 public void reportMappingProblem(Throwable t, String message, Object... msgArgs) throws JsonMappingException {
1308 message = _format(message, msgArgs);
1309 throw JsonMappingException.from(getGenerator(), message, t);
1310 }
1311
1312 @Override
1313 public JsonMappingException invalidTypeIdException(JavaType baseType, String typeId,
1314 String extraDesc) {
1315 String msg = String.format("Could not resolve type id '%s' as a subtype of %s",
1316 typeId, ClassUtil.getTypeDescription(baseType));
1317 return InvalidTypeIdException.from(null, _colonConcat(msg, extraDesc), baseType, typeId);
1318 }
1319
1320 /*
1321 /********************************************************
1322 /* Error reporting, deprecated methods
1323 /********************************************************
1324 */
1325
1326 /**
1327 * Factory method for constructing a {@link JsonMappingException};
1328 * usually only indirectly used by calling
1329 * {@link #reportMappingProblem(String, Object...)}.
1330 *
1331 * @since 2.6
1332 *
1333 * @deprecated Since 2.9
1334 */
1335 @Deprecated // since 2.9
1336 public JsonMappingException mappingException(String message, Object... msgArgs) {
1337 return JsonMappingException.from(getGenerator(), _format(message, msgArgs));
1338 }
1339
1340 /**
1341 * Factory method for constructing a {@link JsonMappingException};
1342 * usually only indirectly used by calling
1343 * {@link #reportMappingProblem(Throwable, String, Object...)}
1344 *
1345 * @since 2.8
1346 *
1347 * @deprecated Since 2.9
1348 */
1349 @Deprecated // since 2.9
1350 protected JsonMappingException mappingException(Throwable t, String message, Object... msgArgs) {
1351 return JsonMappingException.from(getGenerator(), _format(message, msgArgs), t);
1352 }
1353
1354 /*
1355 /********************************************************
1356 /* Helper methods
1357 /********************************************************
1358 */
1359
1360 protected void _reportIncompatibleRootType(Object value, JavaType rootType) throws IOException
1361 {
1362 // One special case: allow primitive/wrapper type coercion
1363 if (rootType.isPrimitive()) {
1364 Class<?> wrapperType = ClassUtil.wrapperType(rootType.getRawClass());
1365 // If it's just difference between wrapper, primitive, let it slide
1366 if (wrapperType.isAssignableFrom(value.getClass())) {
1367 return;
1368 }
1369 }
1370 reportBadDefinition(rootType, String.format(
1371 "Incompatible types: declared root type (%s) vs %s",
1372 rootType, ClassUtil.classNameOf(value)));
1373 }
1374
1375 /**
1376 * Method that will try to find a serializer, either from cache
1377 * or by constructing one; but will not return an "unknown" serializer
1378 * if this cannot be done but rather returns null.
1379 *
1380 * @return Serializer if one can be found, null if not.
1381 */
1382 protected JsonSerializer<Object> _findExplicitUntypedSerializer(Class<?> runtimeType)
1383 throws JsonMappingException
1384 {
1385 // Fast lookup from local lookup thingy works?
1386 JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(runtimeType);
1387 if (ser == null) {
1388 // If not, maybe shared map already has it?
1389 ser = _serializerCache.untypedValueSerializer(runtimeType);
1390 if (ser == null) {
1391 ser = _createAndCacheUntypedSerializer(runtimeType);
1392 }
1393 }
1394 /* 18-Sep-2014, tatu: This is unfortunate patch over related change
1395 * that pushes creation of "unknown type" serializer deeper down
1396 * in BeanSerializerFactory; as a result, we need to "undo" creation
1397 * here.
1398 */
1399 if (isUnknownTypeSerializer(ser)) {
1400 return null;
1401 }
1402 return ser;
1403 }
1404
1405 /*
1406 /**********************************************************
1407 /* Low-level methods for actually constructing and initializing
1408 /* serializers
1409 /**********************************************************
1410 */
1411
1412 /**
1413 * Method that will try to construct a value serializer; and if
1414 * one is successfully created, cache it for reuse.
1415 */
1416 protected JsonSerializer<Object> _createAndCacheUntypedSerializer(Class<?> rawType)
1417 throws JsonMappingException
1418 {
1419 JavaType fullType = _config.constructType(rawType);
1420 JsonSerializer<Object> ser;
1421 try {
1422 ser = _createUntypedSerializer(fullType);
1423 } catch (IllegalArgumentException iae) {
1424 // We better only expose checked exceptions, since those
1425 // are what caller is expected to handle
1426 ser = null; // doesn't matter but compiler whines otherwise
1427 reportMappingProblem(iae, ClassUtil.exceptionMessage(iae));
1428 }
1429
1430 if (ser != null) {
1431 // 21-Dec-2015, tatu: Best to cache for both raw and full-type key
1432 _serializerCache.addAndResolveNonTypedSerializer(rawType, fullType, ser, this);
1433 }
1434 return ser;
1435 }
1436
1437 protected JsonSerializer<Object> _createAndCacheUntypedSerializer(JavaType type)
1438 throws JsonMappingException
1439 {
1440 JsonSerializer<Object> ser;
1441 try {
1442 ser = _createUntypedSerializer(type);
1443 } catch (IllegalArgumentException iae) {
1444 // We better only expose checked exceptions, since those
1445 // are what caller is expected to handle
1446 ser = null;
1447 reportMappingProblem(iae, ClassUtil.exceptionMessage(iae));
1448 }
1449
1450 if (ser != null) {
1451 // 21-Dec-2015, tatu: Should we also cache using raw key?
1452 _serializerCache.addAndResolveNonTypedSerializer(type, ser, this);
1453 }
1454 return ser;
1455 }
1456
1457 /**
1458 * @since 2.1
1459 */
1460 protected JsonSerializer<Object> _createUntypedSerializer(JavaType type)
1461 throws JsonMappingException
1462 {
1463 /* 27-Mar-2015, tatu: Wish I knew exactly why/what, but [databind#738]
1464 * can be prevented by synchronizing on cache (not on 'this', however,
1465 * since there's one instance per serialization).
1466 * Perhaps not-yet-resolved instance might be exposed too early to callers.
1467 */
1468 // 13-Apr-2018, tatu: Problem does NOT occur any more with late 2.8.x and 2.9.x
1469 // versions, likely due to concurrency fixes for `AnnotatedClass` introspection.
1470 // This sync block could probably be removed; but to minimize any risk of
1471 // regression sync block will only be removed from 3.0.
1472 // 23-Oct-2019, tatu: Due to continuation of 2.x line, removed from 2.11
1473 // synchronized (_serializerCache) {
1474 return (JsonSerializer<Object>)_serializerFactory.createSerializer(this, type);
1475 // }
1476 }
1477
1478 /**
1479 * Helper method called to resolve and contextualize given
1480 * serializer, if and as necessary.
1481 */
1482 @SuppressWarnings("unchecked")
1483 protected JsonSerializer<Object> _handleContextualResolvable(JsonSerializer<?> ser,
1484 BeanProperty property)
1485 throws JsonMappingException
1486 {
1487 if (ser instanceof ResolvableSerializer) {
1488 ((ResolvableSerializer) ser).resolve(this);
1489 }
1490 return (JsonSerializer<Object>) handleSecondaryContextualization(ser, property);
1491 }
1492
1493 @SuppressWarnings("unchecked")
1494 protected JsonSerializer<Object> _handleResolvable(JsonSerializer<?> ser)
1495 throws JsonMappingException
1496 {
1497 if (ser instanceof ResolvableSerializer) {
1498 ((ResolvableSerializer) ser).resolve(this);
1499 }
1500 return (JsonSerializer<Object>) ser;
1501 }
1502
1503 /*
1504 /**********************************************************
1505 /* Internal methods
1506 /**********************************************************
1507 */
1508
1509 protected final DateFormat _dateFormat()
1510 {
1511 if (_dateFormat != null) {
1512 return _dateFormat;
1513 }
1514 /* At this point, all timezone configuration should have occurred, with respect
1515 * to default dateformat configuration. But we still better clone
1516 * an instance as formatters are stateful, not thread-safe.
1517 */
1518 DateFormat df = _config.getDateFormat();
1519 _dateFormat = df = (DateFormat) df.clone();
1520 // [databind#939]: 26-Sep-2015, tatu: With 2.6, formatter has been (pre)configured
1521 // with TimeZone, so we should NOT try overriding it unlike with earlier versions
1522 /*
1523 TimeZone tz = getTimeZone();
1524 if (tz != df.getTimeZone()) {
1525 df.setTimeZone(tz);
1526 }
1527 */
1528 return df;
1529 }
1530 }
1531