All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fasterxml.jackson.databind.SerializerProvider Maven / Gradle / Ivy

There is a newer version: 2.17.0
Show newest version
package com.fasterxml.jackson.databind;

import java.io.IOException;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.util.*;

import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.core.*;

import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.ObjectIdInfo;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.*;
import com.fasterxml.jackson.databind.ser.impl.*;
import com.fasterxml.jackson.databind.ser.std.NullSerializer;
import com.fasterxml.jackson.databind.ser.std.StdKeySerializers;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.fasterxml.jackson.databind.util.RootNameLookup;

/**
 * Class that defines API used by {@link ObjectMapper} and
 * {@link JsonSerializer}s to obtain serializers capable of serializing
 * instances of specific types; as well as the default implementation
 * of the functionality.
 *

* Provider handles caching aspects of serializer handling; all construction * details are delegated to {@link SerializerFactory} instance. *

* Object life-cycle is such that an initial instance ("blueprint") is created * and referenced by {@link ObjectMapper} and {@link ObjectWriter} intances; * but for actual usage, a configured instance is created by using * a create method in sub-class * {@link com.fasterxml.jackson.databind.ser.DefaultSerializerProvider}. * Only this instance can be used for actual serialization calls; blueprint * object is only to be used for creating instances. */ public abstract class SerializerProvider { protected final static JavaType TYPE_OBJECT = TypeFactory.defaultInstance().uncheckedSimpleType(Object.class); /** * Setting for determining whether mappings for "unknown classes" should be * cached for faster resolution. Usually this isn't needed, but maybe it * is in some cases? */ protected final static boolean CACHE_UNKNOWN_MAPPINGS = false; public final static JsonSerializer DEFAULT_NULL_KEY_SERIALIZER = new FailingSerializer("Null key for a Map not allowed in JSON (use a converting NullKeySerializer?)"); public final static JsonSerializer DEFAULT_UNKNOWN_SERIALIZER = new UnknownSerializer(); /* /********************************************************** /* Configuration, general /********************************************************** */ /** * Serialization configuration to use for serialization processing. */ final protected SerializationConfig _config; /** * View used for currently active serialization, if any. */ final protected Class _serializationView; /* /********************************************************** /* Configuration, factories /********************************************************** */ /** * Factory used for constructing actual serializer instances. */ final protected SerializerFactory _serializerFactory; /* /********************************************************** /* Helper objects for caching /********************************************************** */ /** * Cache for doing type-to-value-serializer lookups. */ final protected SerializerCache _serializerCache; /** * Helper object for keeping track of introspected root names */ final protected RootNameLookup _rootNames; /* /********************************************************** /* Configuration, specialized serializers /********************************************************** */ /** * Serializer that gets called for values of types for which no * serializers can be constructed. *

* The default serializer will simply thrown an exception. */ protected JsonSerializer _unknownTypeSerializer = DEFAULT_UNKNOWN_SERIALIZER; /** * Serializer used to output non-null keys of Maps (which will get * output as JSON Objects), if not null; if null, us the standard * default key serializer. */ protected JsonSerializer _keySerializer; /** * Serializer used to output a null value. Default implementation * writes nulls using {@link JsonGenerator#writeNull}. */ protected JsonSerializer _nullValueSerializer = NullSerializer.instance; /** * Serializer used to (try to) output a null key, due to an entry of * {@link java.util.Map} having null key. * The default implementation will throw an exception if this happens; * alternative implementation (like one that would write an Empty String) * can be defined. */ protected JsonSerializer _nullKeySerializer = DEFAULT_NULL_KEY_SERIALIZER; /* /********************************************************** /* State, for non-blueprint instances: generic /********************************************************** */ /** * For fast lookups, we will have a local non-shared read-only * map that contains serializers previously fetched. */ protected final ReadOnlyClassToSerializerMap _knownSerializers; /** * Lazily acquired and instantiated formatter object: initialized * first time it is needed, reused afterwards. Used via instances * (not blueprints), so that access need not be thread-safe. */ protected DateFormat _dateFormat; /* /********************************************************** /* Life-cycle /********************************************************** */ /** * Constructor for creating master (or "blue-print") provider object, * which is only used as the template for constructing per-binding * instances. */ public SerializerProvider() { _config = null; _serializerFactory = null; _serializerCache = new SerializerCache(); // Blueprints doesn't have access to any serializers... _knownSerializers = null; _rootNames = new RootNameLookup(); _serializationView = null; } /** * "Copy-constructor", used by sub-classes. * * @param src Blueprint object used as the baseline for this instance */ protected SerializerProvider(SerializerProvider src, SerializationConfig config, SerializerFactory f) { if (config == null) { throw new NullPointerException(); } _serializerFactory = f; _config = config; _serializerCache = src._serializerCache; _unknownTypeSerializer = src._unknownTypeSerializer; _keySerializer = src._keySerializer; _nullValueSerializer = src._nullValueSerializer; _nullKeySerializer = src._nullKeySerializer; _rootNames = src._rootNames; /* Non-blueprint instances do have a read-only map; one that doesn't * need synchronization for lookups. */ _knownSerializers = _serializerCache.getReadOnlyLookupMap(); _serializationView = config.getActiveView(); } /* /********************************************************** /* Methods for configuring default settings /********************************************************** */ /** * Method that can be used to specify serializer that will be * used to write JSON property names matching null keys for Java * Maps (which will throw an exception if try write such property * name) */ public void setDefaultKeySerializer(JsonSerializer ks) { if (ks == null) { throw new IllegalArgumentException("Can not pass null JsonSerializer"); } _keySerializer = ks; } /** * Method that can be used to specify serializer that will be * used to write JSON values matching Java null values * instead of default one (which simply writes JSON null) */ public void setNullValueSerializer(JsonSerializer nvs) { if (nvs == null) { throw new IllegalArgumentException("Can not pass null JsonSerializer"); } _nullValueSerializer = nvs; } /** * Method that can be used to specify serializer to use for serializing * all non-null JSON property names, unless more specific key serializer * is found (i.e. if not custom key serializer has been registered for * Java type). *

* Note that key serializer registration are different from value serializer * registrations. */ public void setNullKeySerializer(JsonSerializer nks) { if (nks == null) { throw new IllegalArgumentException("Can not pass null JsonSerializer"); } _nullKeySerializer = nks; } /* /********************************************************** /* Access to general configuration /********************************************************** */ /** * Method for accessing configuration for the serialization processing. */ public final SerializationConfig getConfig() { return _config; } /** * Convenience method for checking whether specified serialization * feature is enabled or not. * Shortcut for: *
     *  getConfig().isEnabled(feature);
     *
*/ public final boolean isEnabled(MapperFeature feature) { return _config.isEnabled(feature); } /** * Convenience method for checking whether specified serialization * feature is enabled or not. * Shortcut for: *
     *  getConfig().isEnabled(feature);
     *
*/ public final boolean isEnabled(SerializationFeature feature) { return _config.isEnabled(feature); } /** * Convenience method for accessing serialization view in use (if any); equivalent to: *
     *   getConfig().canOverrideAccessModifiers();
     *
*/ public final boolean canOverrideAccessModifiers() { return _config.canOverrideAccessModifiers(); } /** * Convenience method for accessing serialization view in use (if any); equivalent to: *
     *   getConfig().getAnnotationIntrospector();
     *
*/ public final AnnotationIntrospector getAnnotationIntrospector() { return _config.getAnnotationIntrospector(); } /** * Convenience method for accessing serialization view in use (if any); equivalent to: *
     *   getConfig().getSerializationView();
     *
*/ public final Class getSerializationView() { return _serializationView; } /** * Convenience method for accessing provider to find serialization filters used, * equivalent to calling: *
     *   getConfig().getFilterProvider();
     *
*/ public final FilterProvider getFilterProvider() { return _config.getFilterProvider(); } /** * Method for accessing default Locale to use: convenience method for *
     *   getConfig().getLocale();
     *
*/ public Locale getLocale() { return _config.getLocale(); } /** * Method for accessing default TimeZone to use: convenience method for *
     *   getConfig().getTimeZone();
     *
*/ public TimeZone getTimeZone() { return _config.getTimeZone(); } /* /********************************************************** /* Access to type handling /********************************************************** */ /** * Convenience method for constructing {@link JavaType} for given JDK * type (usually {@link java.lang.Class}) */ public JavaType constructType(Type type) { return _config.getTypeFactory().constructType(type); } /** * Convenience method for constructing subtypes, retaining generic * type parameter (if any) */ public JavaType constructSpecializedType(JavaType baseType, Class subclass) { return _config.constructSpecializedType(baseType, subclass); } public TypeFactory getTypeFactory() { return _config.getTypeFactory(); } /* /********************************************************** /* Access to Object Id aspects /********************************************************** */ /** * Method called to find the Object Id for given POJO, if one * has been generated. Will always return a non-null Object; * contents vary depending on whether an Object Id already * exists or not. */ public abstract WritableObjectId findObjectId(Object forPojo, ObjectIdGenerator generatorType); /* /********************************************************** /* General serializer locating functionality /********************************************************** */ /** * Method called to get hold of a serializer for a value of given type; * or if no such serializer can be found, a default handler (which * may do a best-effort generic serialization or just simply * throw an exception when invoked). *

* Note: this method is only called for non-null values; not for keys * or null values. For these, check out other accessor methods. *

* Note that starting with version 1.5, serializers should also be type-aware * if they handle polymorphic types. That means that it may be necessary * to also use a {@link TypeSerializer} based on declared (static) type * being serializer (whereas actual data may be serialized using dynamic * type) * * @throws JsonMappingException if there are fatal problems with * accessing suitable serializer; including that of not * finding any serializer */ public JsonSerializer findValueSerializer(Class valueType, BeanProperty property) throws JsonMappingException { // Fast lookup from local lookup thingy works? JsonSerializer ser = _knownSerializers.untypedValueSerializer(valueType); if (ser == null) { // If not, maybe shared map already has it? ser = _serializerCache.untypedValueSerializer(valueType); if (ser == null) { // ... possibly as fully typed? ser = _serializerCache.untypedValueSerializer(_config.constructType(valueType)); if (ser == null) { // If neither, must create ser = _createAndCacheUntypedSerializer(valueType); // Not found? Must use the unknown type serializer /* Couldn't create? Need to return the fallback serializer, which * most likely will report an error: but one question is whether * we should cache it? */ if (ser == null) { ser = getUnknownTypeSerializer(valueType); // Should this be added to lookups? if (CACHE_UNKNOWN_MAPPINGS) { _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this); } return ser; } } } } // at this point, resolution has occured, but not contextualization return _handleContextual(ser, property); } /** * Similar to {@link #findValueSerializer(Class,BeanProperty)}, but takes * full generics-aware type instead of raw class. * This is necessary for accurate handling of external type information, * to handle polymorphic types. * * @param property When creating secondary serializers, property for which * serializer is needed: annotations of the property (or bean that contains it) * may be checked to create contextual serializers. */ public JsonSerializer findValueSerializer(JavaType valueType, BeanProperty property) throws JsonMappingException { // Fast lookup from local lookup thingy works? JsonSerializer ser = _knownSerializers.untypedValueSerializer(valueType); if (ser == null) { // If not, maybe shared map already has it? ser = _serializerCache.untypedValueSerializer(valueType); if (ser == null) { // If neither, must create ser = _createAndCacheUntypedSerializer(valueType); // Not found? Must use the unknown type serializer /* Couldn't create? Need to return the fallback serializer, which * most likely will report an error: but one question is whether * we should cache it? */ if (ser == null) { ser = getUnknownTypeSerializer(valueType.getRawClass()); // Should this be added to lookups? if (CACHE_UNKNOWN_MAPPINGS) { _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this); } return ser; } } } return _handleContextual(ser, property); } /** * Method called to locate regular serializer, matching type serializer, * and if both found, wrap them in a serializer that calls both in correct * sequence. This method is currently only used for root-level serializer * handling to allow for simpler caching. A call can always be replaced * by equivalent calls to access serializer and type serializer separately. * * @param valueType Type for purpose of locating a serializer; usually dynamic * runtime type, but can also be static declared type, depending on configuration * @param cache Whether resulting value serializer should be cached or not; this is just * a hint * @param property When creating secondary serializers, property for which * serializer is needed: annotations of the property (or bean that contains it) * may be checked to create contextual serializers. */ public JsonSerializer findTypedValueSerializer(Class valueType, boolean cache, BeanProperty property) throws JsonMappingException { // Two-phase lookups; local non-shared cache, then shared: JsonSerializer ser = _knownSerializers.typedValueSerializer(valueType); if (ser != null) { return ser; } // If not, maybe shared map already has it? ser = _serializerCache.typedValueSerializer(valueType); if (ser != null) { return ser; } // Well, let's just compose from pieces: ser = findValueSerializer(valueType, property); TypeSerializer typeSer = _serializerFactory.createTypeSerializer(_config, _config.constructType(valueType)); if (typeSer != null) { typeSer = typeSer.forProperty(property); ser = new TypeWrappedSerializer(typeSer, ser); } if (cache) { _serializerCache.addTypedSerializer(valueType, ser); } return ser; } /** * Method called to locate regular serializer, matching type serializer, * and if both found, wrap them in a serializer that calls both in correct * sequence. This method is currently only used for root-level serializer * handling to allow for simpler caching. A call can always be replaced * by equivalent calls to access serializer and type serializer separately. * * @param valueType Declared type of value being serialized (which may not * be actual runtime type); used for finding both value serializer and * type serializer to use for adding polymorphic type (if any) * @param cache Whether resulting value serializer should be cached or not; this is just * a hint * @param property When creating secondary serializers, property for which * serializer is needed: annotations of the property (or bean that contains it) * may be checked to create contextual serializers. */ public JsonSerializer findTypedValueSerializer(JavaType valueType, boolean cache, BeanProperty property) throws JsonMappingException { // Two-phase lookups; local non-shared cache, then shared: JsonSerializer ser = _knownSerializers.typedValueSerializer(valueType); if (ser != null) { return ser; } // If not, maybe shared map already has it? ser = _serializerCache.typedValueSerializer(valueType); if (ser != null) { return ser; } // Well, let's just compose from pieces: ser = findValueSerializer(valueType, property); TypeSerializer typeSer = _serializerFactory.createTypeSerializer(_config, valueType); if (typeSer != null) { typeSer = typeSer.forProperty(property); ser = new TypeWrappedSerializer(typeSer, ser); } if (cache) { _serializerCache.addTypedSerializer(valueType, ser); } return ser; } /** * Method called to get the serializer to use for serializing * non-null Map keys. Separation from regular * {@link #findValueSerializer} method is because actual write * method must be different (@link JsonGenerator#writeFieldName}; * but also since behavior for some key types may differ. *

* Note that the serializer itself can be called with instances * of any Java object, but not nulls. */ public JsonSerializer findKeySerializer(JavaType keyType, BeanProperty property) throws JsonMappingException { JsonSerializer ser = _serializerFactory.createKeySerializer(_config, keyType); // First things first: maybe there are registered custom implementations // if not, use default one: if (ser == null) { if (_keySerializer == null) { ser = StdKeySerializers.getStdKeySerializer(keyType); } else { ser = _keySerializer; } } // 25-Feb-2011, tatu: As per [JACKSON-519], need to ensure contextuality works here, too return _handleContextualResolvable(ser, property); } /* /******************************************************** /* Accessors for specialized serializers /******************************************************** */ /** * @since 2.0 */ public JsonSerializer getDefaultNullKeySerializer() { return _nullKeySerializer; } /** * @since 2.0 */ public JsonSerializer getDefaultNullValueSerializer() { return _nullValueSerializer; } /** * Method called to get the serializer to use for serializing * Map keys that are nulls: this is needed since JSON does not allow * any non-String value as key, including null. *

* Typically, returned serializer * will either throw an exception, or use an empty String; but * other behaviors are possible. */ /** * Method called to find a serializer to use for null values for given * declared type. Note that type is completely based on declared type, * since nulls in Java have no type and thus runtime type can not be * determined. * * @since 2.0 */ public JsonSerializer findNullKeySerializer(JavaType serializationType, BeanProperty property) throws JsonMappingException { return getDefaultNullKeySerializer(); } /** * Method called to get the serializer to use for serializing null * property values. *

* Default implementation simply calls {@link #getDefaultNullValueSerializer()}; * can be overridden to add custom null serialization for properties * of certain type or name. * * @since 2.0 */ public JsonSerializer findNullValueSerializer(BeanProperty property) throws JsonMappingException { return getDefaultNullValueSerializer(); } /** * Method called to get the serializer to use if provider * can not determine an actual type-specific serializer * to use; typically when none of {@link SerializerFactory} * instances are able to construct a serializer. *

* Typically, returned serializer will throw an exception, * although alternatively {@link com.fasterxml.jackson.databind.ser.std.ToStringSerializer} * could be returned as well. * * @param unknownType Type for which no serializer is found */ public JsonSerializer getUnknownTypeSerializer(Class unknownType) { return _unknownTypeSerializer; } /* /********************************************************** /* Methods for creating instances based on annotations /********************************************************** */ /** * Method that can be called to construct and configure serializer instance, * either given a {@link Class} to instantiate (with default constructor), * or an uninitialized serializer instance. * Either way, serialize will be properly resolved * (via {@link com.fasterxml.jackson.databind.ser.ResolvableSerializer}) and/or contextualized * (via {@link com.fasterxml.jackson.databind.ser.ContextualSerializer}) as necessary. * * @param annotated Annotated entity that contained definition * @param serDef Serializer definition: either an instance or class */ public abstract JsonSerializer serializerInstance(Annotated annotated, Object serDef) throws JsonMappingException; public abstract ObjectIdGenerator objectIdGeneratorInstance(Annotated annotated, ObjectIdInfo objectIdInfo) throws JsonMappingException; /* /******************************************************** /* Convenience methods /******************************************************** */ /** * Convenience method that will serialize given value (which can be * null) using standard serializer locating functionality. It can * be called for all values including field and Map values, but usually * field values are best handled calling * {@link #defaultSerializeField} instead. */ public final void defaultSerializeValue(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { if (value == null) { getDefaultNullValueSerializer().serialize(null, jgen, this); } else { Class cls = value.getClass(); findTypedValueSerializer(cls, true, null).serialize(value, jgen, this); } } /** * Convenience method that will serialize given field with specified * value. Value may be null. Serializer is done using the usual * null) using standard serializer locating functionality. */ public final void defaultSerializeField(String fieldName, Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { jgen.writeFieldName(fieldName); if (value == null) { /* Note: can't easily check for suppression at this point * any more; caller must check it. */ getDefaultNullValueSerializer().serialize(null, jgen, this); } else { Class cls = value.getClass(); findTypedValueSerializer(cls, true, null).serialize(value, jgen, this); } } /* /********************************************************** /* Convenience methods /********************************************************** */ /** * Method that will handle serialization of Date(-like) values, using * {@link SerializationConfig} settings to determine expected serialization * behavior. * Note: date here means "full" date, that is, date AND time, as per * Java convention (and not date-only values like in SQL) */ public final void defaultSerializeDateValue(long timestamp, JsonGenerator jgen) throws IOException, JsonProcessingException { // [JACKSON-87]: Support both numeric timestamps and textual if (isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)) { jgen.writeNumber(timestamp); } else { jgen.writeString(_dateFormat().format(new Date(timestamp))); } } /** * Method that will handle serialization of Date(-like) values, using * {@link SerializationConfig} settings to determine expected serialization * behavior. * Note: date here means "full" date, that is, date AND time, as per * Java convention (and not date-only values like in SQL) */ public final void defaultSerializeDateValue(Date date, JsonGenerator jgen) throws IOException, JsonProcessingException { // [JACKSON-87]: Support both numeric timestamps and textual if (isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)) { jgen.writeNumber(date.getTime()); } else { jgen.writeString(_dateFormat().format(date)); } } /** * Method that will handle serialization of Dates used as {@link java.util.Map} keys, * based on {@link SerializationFeature#WRITE_DATE_KEYS_AS_TIMESTAMPS} * value (and if using textual representation, configured date format) */ public void defaultSerializeDateKey(long timestamp, JsonGenerator jgen) throws IOException, JsonProcessingException { if (isEnabled(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)) { jgen.writeFieldName(String.valueOf(timestamp)); } else { jgen.writeFieldName(_dateFormat().format(new Date(timestamp))); } } /** * Method that will handle serialization of Dates used as {@link java.util.Map} keys, * based on {@link SerializationFeature#WRITE_DATE_KEYS_AS_TIMESTAMPS} * value (and if using textual representation, configured date format) */ public void defaultSerializeDateKey(Date date, JsonGenerator jgen) throws IOException, JsonProcessingException { if (isEnabled(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)) { jgen.writeFieldName(String.valueOf(date.getTime())); } else { jgen.writeFieldName(_dateFormat().format(date)); } } public final void defaultSerializeNull(JsonGenerator jgen) throws IOException, JsonProcessingException { getDefaultNullValueSerializer().serialize(null, jgen, this); } /* /******************************************************** /* Helper methods /******************************************************** */ protected void _reportIncompatibleRootType(Object value, JavaType rootType) throws IOException, JsonProcessingException { /* 07-Jan-2010, tatu: As per [JACKSON-456] better handle distinction between wrapper types, * primitives */ if (rootType.isPrimitive()) { Class wrapperType = ClassUtil.wrapperType(rootType.getRawClass()); // If it's just difference between wrapper, primitive, let it slide if (wrapperType.isAssignableFrom(value.getClass())) { return; } } throw new JsonMappingException("Incompatible types: declared root type ("+rootType+") vs " +value.getClass().getName()); } /** * Method that will try to find a serializer, either from cache * or by constructing one; but will not return an "unknown" serializer * if this can not be done but rather returns null. * * @return Serializer if one can be found, null if not. */ protected JsonSerializer _findExplicitUntypedSerializer(Class runtimeType) { // Fast lookup from local lookup thingy works? JsonSerializer ser = _knownSerializers.untypedValueSerializer(runtimeType); if (ser != null) { return ser; } // If not, maybe shared map already has it? ser = _serializerCache.untypedValueSerializer(runtimeType); if (ser != null) { return ser; } try { return _createAndCacheUntypedSerializer(runtimeType); } catch (Exception e) { return null; } } /* /********************************************************** /* Low-level methods for actually constructing and initializing /* serializers /********************************************************** */ /** * Method that will try to construct a value serializer; and if * one is successfully created, cache it for reuse. */ protected JsonSerializer _createAndCacheUntypedSerializer(Class type) throws JsonMappingException { JsonSerializer ser; try { ser = _createUntypedSerializer(_config.constructType(type)); } catch (IllegalArgumentException iae) { /* We better only expose checked exceptions, since those * are what caller is expected to handle */ throw new JsonMappingException(iae.getMessage(), null, iae); } if (ser != null) { _serializerCache.addAndResolveNonTypedSerializer(type, ser, this); } return ser; } protected JsonSerializer _createAndCacheUntypedSerializer(JavaType type) throws JsonMappingException { JsonSerializer ser; try { ser = _createUntypedSerializer(type); } catch (IllegalArgumentException iae) { /* We better only expose checked exceptions, since those * are what caller is expected to handle */ throw new JsonMappingException(iae.getMessage(), null, iae); } if (ser != null) { _serializerCache.addAndResolveNonTypedSerializer(type, ser, this); } return ser; } /** * @since 2.1 */ @SuppressWarnings("deprecation") protected JsonSerializer _createUntypedSerializer(JavaType type) throws JsonMappingException { /* 30-Sep-2012, tatu: For now need to call the deprecated method; for 2.2, * convert to using new one. But note that we do NOT pass 'property' along. */ return (JsonSerializer)_serializerFactory.createSerializer(this, type, null); } /** * Helper method called to resolve and contextualize given * serializer, if and as necessary. */ protected JsonSerializer _handleContextualResolvable(JsonSerializer ser, BeanProperty property) throws JsonMappingException { if (ser instanceof ResolvableSerializer) { ((ResolvableSerializer) ser).resolve(this); } return _handleContextual(ser, property); } @SuppressWarnings("unchecked") protected JsonSerializer _handleResolvable(JsonSerializer ser) throws JsonMappingException { if (ser instanceof ResolvableSerializer) { ((ResolvableSerializer) ser).resolve(this); } return (JsonSerializer) ser; } @SuppressWarnings("unchecked") protected JsonSerializer _handleContextual(JsonSerializer ser, BeanProperty property) throws JsonMappingException { if (ser instanceof ContextualSerializer) { ser = ((ContextualSerializer) ser).createContextual(this, property); } return (JsonSerializer) ser; } /* /********************************************************** /* Internal methods /********************************************************** */ protected final DateFormat _dateFormat() { if (_dateFormat != null) { return _dateFormat; } /* 24-Feb-2012, tatu: At this point, all timezone configuration * should have occured, with respect to default dateformat * and timezone configuration. But we still better clone * an instance as formatters may be stateful. */ DateFormat df = _config.getDateFormat(); _dateFormat = df = (DateFormat) df.clone(); return df; } }