| package com.fasterxml.jackson.databind.cfg; |
| |
| import java.text.DateFormat; |
| import java.util.Locale; |
| import java.util.TimeZone; |
| |
| import com.fasterxml.jackson.core.Base64Variant; |
| import com.fasterxml.jackson.databind.*; |
| import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; |
| import com.fasterxml.jackson.databind.introspect.ClassIntrospector; |
| import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; |
| import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; |
| import com.fasterxml.jackson.databind.type.TypeFactory; |
| import com.fasterxml.jackson.databind.util.StdDateFormat; |
| |
| /** |
| * Immutable container class used to store simple configuration |
| * settings. Since instances are fully immutable, instances can |
| * be freely shared and used without synchronization. |
| */ |
| public final class BaseSettings |
| implements java.io.Serializable |
| { |
| // for 2.6 |
| private static final long serialVersionUID = 1L; |
| |
| /** |
| * We will use a default TimeZone as the baseline. |
| */ |
| private static final TimeZone DEFAULT_TIMEZONE = |
| // TimeZone.getDefault() |
| /* [databind#915] 05-Nov-2015, tatu: Changed to UTC, from earlier |
| * baseline of GMT (up to 2.6) |
| */ |
| TimeZone.getTimeZone("UTC"); |
| |
| /* |
| /********************************************************** |
| /* Configuration settings; introspection, related |
| /********************************************************** |
| */ |
| |
| /** |
| * Introspector used to figure out Bean properties needed for bean serialization |
| * and deserialization. Overridable so that it is possible to change low-level |
| * details of introspection, like adding new annotation types. |
| */ |
| protected final ClassIntrospector _classIntrospector; |
| |
| /** |
| * Introspector used for accessing annotation value based configuration. |
| */ |
| protected final AnnotationIntrospector _annotationIntrospector; |
| |
| /** |
| * Custom property naming strategy in use, if any. |
| */ |
| protected final PropertyNamingStrategy _propertyNamingStrategy; |
| |
| /** |
| * Specific factory used for creating {@link JavaType} instances; |
| * needed to allow modules to add more custom type handling |
| * (mostly to support types of non-Java JVM languages) |
| */ |
| protected final TypeFactory _typeFactory; |
| |
| /* |
| /********************************************************** |
| /* Configuration settings; poly type resolution |
| /********************************************************** |
| */ |
| |
| /** |
| * Builder used to create type resolver for serializing and deserializing |
| * values for which polymorphic type handling is needed. |
| */ |
| protected final TypeResolverBuilder<?> _typeResolverBuilder; |
| |
| /** |
| * Validator that is used to limit allowed polymorphic subtypes, mostly |
| * for security reasons when dealing with untrusted content. |
| * |
| * @since 2.10 |
| */ |
| protected final PolymorphicTypeValidator _typeValidator; |
| |
| /* |
| /********************************************************** |
| /* Configuration settings; other |
| /********************************************************** |
| */ |
| |
| /** |
| * Custom date format to use for de-serialization. If specified, will be |
| * used instead of {@link com.fasterxml.jackson.databind.util.StdDateFormat}. |
| *<p> |
| * Note that the configured format object will be cloned once per |
| * deserialization process (first time it is needed) |
| */ |
| protected final DateFormat _dateFormat; |
| |
| /** |
| * Object used for creating instances of handlers (serializers, deserializers, |
| * type and type id resolvers), given class to instantiate. This is typically |
| * used to do additional configuration (with dependency injection, for example) |
| * beyond simply construction of instances; or to use alternative constructors. |
| */ |
| protected final HandlerInstantiator _handlerInstantiator; |
| |
| /** |
| * Default {@link java.util.Locale} used with serialization formats. |
| * Default value is {@link Locale#getDefault()}. |
| */ |
| protected final Locale _locale; |
| |
| /** |
| * Default {@link java.util.TimeZone} used with serialization formats, |
| * if (and only if!) explicitly set by use; otherwise `null` to indicate |
| * "use default", which means "UTC" (from Jackson 2.7); earlier versions |
| * (up to 2.6) used "GMT". |
| *<p> |
| * Note that if a new value is set, timezone is also assigned to |
| * {@link #_dateFormat} of this object. |
| */ |
| protected final TimeZone _timeZone; |
| |
| /** |
| * Explicitly default {@link Base64Variant} to use for handling |
| * binary data (<code>byte[]</code>), used with data formats |
| * that use base64 encoding (like JSON, CSV). |
| * |
| * @since 2.1 |
| */ |
| protected final Base64Variant _defaultBase64; |
| |
| /* |
| /********************************************************** |
| /* Construction |
| /********************************************************** |
| */ |
| |
| /** |
| * @since 2.10 |
| */ |
| public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, |
| PropertyNamingStrategy pns, TypeFactory tf, |
| TypeResolverBuilder<?> typer, DateFormat dateFormat, HandlerInstantiator hi, |
| Locale locale, TimeZone tz, Base64Variant defaultBase64, |
| PolymorphicTypeValidator ptv) |
| { |
| _classIntrospector = ci; |
| _annotationIntrospector = ai; |
| _propertyNamingStrategy = pns; |
| _typeFactory = tf; |
| _typeResolverBuilder = typer; |
| _dateFormat = dateFormat; |
| _handlerInstantiator = hi; |
| _locale = locale; |
| _timeZone = tz; |
| _defaultBase64 = defaultBase64; |
| _typeValidator = ptv; |
| } |
| |
| @Deprecated // since 2.10 |
| public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, |
| PropertyNamingStrategy pns, TypeFactory tf, |
| TypeResolverBuilder<?> typer, DateFormat dateFormat, HandlerInstantiator hi, |
| Locale locale, TimeZone tz, Base64Variant defaultBase64) |
| { |
| this(ci, ai, pns, tf, typer, dateFormat, hi, locale, tz, defaultBase64, null); |
| } |
| |
| /** |
| * Turns out we are not necessarily 100% stateless, alas, since {@link ClassIntrospector} |
| * typically has a cache. So this method is needed for deep copy() of Mapper. |
| * |
| * @since 2.9.6 |
| */ |
| public BaseSettings copy() { |
| return new BaseSettings(_classIntrospector.copy(), |
| _annotationIntrospector, |
| _propertyNamingStrategy, |
| _typeFactory, |
| _typeResolverBuilder, |
| _dateFormat, |
| _handlerInstantiator, |
| _locale, |
| _timeZone, |
| _defaultBase64, |
| _typeValidator); |
| |
| } |
| |
| /* |
| /********************************************************** |
| /* Factory methods |
| /********************************************************** |
| */ |
| |
| public BaseSettings withClassIntrospector(ClassIntrospector ci) { |
| if (_classIntrospector == ci) { |
| return this; |
| } |
| return new BaseSettings(ci, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, |
| _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, |
| _timeZone, _defaultBase64, _typeValidator); |
| } |
| |
| public BaseSettings withAnnotationIntrospector(AnnotationIntrospector ai) { |
| if (_annotationIntrospector == ai) { |
| return this; |
| } |
| return new BaseSettings(_classIntrospector, ai, _propertyNamingStrategy, _typeFactory, |
| _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, |
| _timeZone, _defaultBase64, _typeValidator); |
| } |
| |
| public BaseSettings withInsertedAnnotationIntrospector(AnnotationIntrospector ai) { |
| return withAnnotationIntrospector(AnnotationIntrospectorPair.create(ai, _annotationIntrospector)); |
| } |
| |
| public BaseSettings withAppendedAnnotationIntrospector(AnnotationIntrospector ai) { |
| return withAnnotationIntrospector(AnnotationIntrospectorPair.create(_annotationIntrospector, ai)); |
| } |
| |
| /* |
| public BaseSettings withVisibility(PropertyAccessor forMethod, JsonAutoDetect.Visibility visibility) { |
| return new BaseSettings(_classIntrospector, _annotationIntrospector, |
| _visibilityChecker.withVisibility(forMethod, visibility), |
| _propertyNamingStrategy, _typeFactory, |
| _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, |
| _timeZone, _defaultBase64, _typeValidator); |
| } |
| */ |
| |
| public BaseSettings withPropertyNamingStrategy(PropertyNamingStrategy pns) { |
| if (_propertyNamingStrategy == pns) { |
| return this; |
| } |
| return new BaseSettings(_classIntrospector, _annotationIntrospector, pns, _typeFactory, |
| _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, |
| _timeZone, _defaultBase64, _typeValidator); |
| } |
| |
| public BaseSettings withTypeFactory(TypeFactory tf) { |
| if (_typeFactory == tf) { |
| return this; |
| } |
| return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, tf, |
| _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, |
| _timeZone, _defaultBase64, _typeValidator); |
| } |
| |
| public BaseSettings withTypeResolverBuilder(TypeResolverBuilder<?> typer) { |
| if (_typeResolverBuilder == typer) { |
| return this; |
| } |
| return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, |
| typer, _dateFormat, _handlerInstantiator, _locale, |
| _timeZone, _defaultBase64, _typeValidator); |
| } |
| |
| public BaseSettings withDateFormat(DateFormat df) { |
| if (_dateFormat == df) { |
| return this; |
| } |
| // 26-Sep-2015, tatu: Related to [databind#939], let's try to force TimeZone if |
| // (but only if!) it has been set explicitly. |
| if ((df != null) && hasExplicitTimeZone()) { |
| df = _force(df, _timeZone); |
| } |
| return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, |
| _typeResolverBuilder, df, _handlerInstantiator, _locale, |
| _timeZone, _defaultBase64, _typeValidator); |
| } |
| |
| public BaseSettings withHandlerInstantiator(HandlerInstantiator hi) { |
| if (_handlerInstantiator == hi) { |
| return this; |
| } |
| return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, |
| _typeResolverBuilder, _dateFormat, hi, _locale, |
| _timeZone, _defaultBase64, _typeValidator); |
| } |
| |
| public BaseSettings with(Locale l) { |
| if (_locale == l) { |
| return this; |
| } |
| return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, |
| _typeResolverBuilder, _dateFormat, _handlerInstantiator, l, |
| _timeZone, _defaultBase64, _typeValidator); |
| } |
| |
| /** |
| * Fluent factory for constructing a new instance that uses specified TimeZone. |
| * Note that timezone used with also be assigned to configured {@link DateFormat}, |
| * changing time formatting defaults. |
| */ |
| public BaseSettings with(TimeZone tz) |
| { |
| if (tz == null) { |
| throw new IllegalArgumentException(); |
| } |
| if (tz == _timeZone) { |
| return this; |
| } |
| |
| DateFormat df = _force(_dateFormat, tz); |
| return new BaseSettings(_classIntrospector, _annotationIntrospector, |
| _propertyNamingStrategy, _typeFactory, |
| _typeResolverBuilder, df, _handlerInstantiator, _locale, |
| tz, _defaultBase64, _typeValidator); |
| } |
| |
| /** |
| * @since 2.1 |
| */ |
| public BaseSettings with(Base64Variant base64) { |
| if (base64 == _defaultBase64) { |
| return this; |
| } |
| return new BaseSettings(_classIntrospector, _annotationIntrospector, |
| _propertyNamingStrategy, _typeFactory, |
| _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, |
| _timeZone, base64, _typeValidator); |
| } |
| |
| /** |
| * @since 2.10 |
| */ |
| public BaseSettings with(PolymorphicTypeValidator v) { |
| if (v == _typeValidator) { |
| return this; |
| } |
| return new BaseSettings(_classIntrospector, _annotationIntrospector, |
| _propertyNamingStrategy, _typeFactory, |
| _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, |
| _timeZone, _defaultBase64, v); |
| } |
| |
| /* |
| /********************************************************** |
| /* API |
| /********************************************************** |
| */ |
| |
| public ClassIntrospector getClassIntrospector() { |
| return _classIntrospector; |
| } |
| |
| public AnnotationIntrospector getAnnotationIntrospector() { |
| return _annotationIntrospector; |
| } |
| |
| public PropertyNamingStrategy getPropertyNamingStrategy() { |
| return _propertyNamingStrategy; |
| } |
| |
| public TypeFactory getTypeFactory() { |
| return _typeFactory; |
| } |
| |
| public TypeResolverBuilder<?> getTypeResolverBuilder() { |
| return _typeResolverBuilder; |
| } |
| |
| /** |
| * @since 2.10 |
| */ |
| public PolymorphicTypeValidator getPolymorphicTypeValidator() { |
| return _typeValidator; |
| } |
| |
| public DateFormat getDateFormat() { |
| return _dateFormat; |
| } |
| |
| public HandlerInstantiator getHandlerInstantiator() { |
| return _handlerInstantiator; |
| } |
| |
| public Locale getLocale() { |
| return _locale; |
| } |
| |
| public TimeZone getTimeZone() { |
| TimeZone tz = _timeZone; |
| return (tz == null) ? DEFAULT_TIMEZONE : tz; |
| } |
| |
| /** |
| * Accessor that may be called to determine whether this settings object |
| * has been explicitly configured with a TimeZone (true), or is still |
| * relying on the default settings (false). |
| * |
| * @since 2.7 |
| */ |
| public boolean hasExplicitTimeZone() { |
| return (_timeZone != null); |
| } |
| |
| public Base64Variant getBase64Variant() { |
| return _defaultBase64; |
| } |
| |
| /* |
| /********************************************************** |
| /* Helper methods |
| /********************************************************** |
| */ |
| |
| private DateFormat _force(DateFormat df, TimeZone tz) |
| { |
| if (df instanceof StdDateFormat) { |
| return ((StdDateFormat) df).withTimeZone(tz); |
| } |
| // we don't know if original format might be shared; better create a clone: |
| df = (DateFormat) df.clone(); |
| df.setTimeZone(tz); |
| return df; |
| } |
| } |