1 package com.fasterxml.jackson.databind.cfg; 2 3 import java.text.DateFormat; 4 import java.util.Locale; 5 import java.util.TimeZone; 6 7 import com.fasterxml.jackson.core.Base64Variant; 8 import com.fasterxml.jackson.databind.*; 9 import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; 10 import com.fasterxml.jackson.databind.introspect.ClassIntrospector; 11 import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; 12 import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; 13 import com.fasterxml.jackson.databind.type.TypeFactory; 14 import com.fasterxml.jackson.databind.util.StdDateFormat; 15 16 /** 17 * Immutable container class used to store simple configuration 18 * settings for both serialization and deserialization. 19 * Since instances are fully immutable, instances can 20 * be freely shared and used without synchronization. 21 */ 22 public final class BaseSettings 23 implements java.io.Serializable 24 { 25 private static final long serialVersionUID = 1L; 26 27 /** 28 * We will use a default TimeZone as the baseline. 29 */ 30 private static final TimeZone DEFAULT_TIMEZONE = 31 // TimeZone.getDefault() 32 /* [databind#915] 05-Nov-2015, tatu: Changed to UTC, from earlier 33 * baseline of GMT (up to 2.6) 34 */ 35 TimeZone.getTimeZone("UTC"); 36 37 /* 38 /********************************************************** 39 /* Configuration settings; introspection, related 40 /********************************************************** 41 */ 42 43 /** 44 * Introspector used to figure out Bean properties needed for bean serialization 45 * and deserialization. Overridable so that it is possible to change low-level 46 * details of introspection, like adding new annotation types. 47 */ 48 protected final ClassIntrospector _classIntrospector; 49 50 /** 51 * Introspector used for accessing annotation value based configuration. 52 */ 53 protected final AnnotationIntrospector _annotationIntrospector; 54 55 /** 56 * Custom property naming strategy in use, if any. 57 */ 58 protected final PropertyNamingStrategy _propertyNamingStrategy; 59 60 /** 61 * Specific factory used for creating {@link JavaType} instances; 62 * needed to allow modules to add more custom type handling 63 * (mostly to support types of non-Java JVM languages) 64 */ 65 protected final TypeFactory _typeFactory; 66 67 /* 68 /********************************************************** 69 /* Configuration settings; poly type resolution 70 /********************************************************** 71 */ 72 73 /** 74 * Builder used to create type resolver for serializing and deserializing 75 * values for which polymorphic type handling is needed. 76 */ 77 protected final TypeResolverBuilder<?> _typeResolverBuilder; 78 79 /** 80 * Validator that is used to limit allowed polymorphic subtypes, mostly 81 * for security reasons when dealing with untrusted content. 82 * 83 * @since 2.10 84 */ 85 protected final PolymorphicTypeValidator _typeValidator; 86 87 /* 88 /********************************************************** 89 /* Configuration settings; other 90 /********************************************************** 91 */ 92 93 /** 94 * Custom date format to use for deserialization. If specified, will be 95 * used instead of {@link com.fasterxml.jackson.databind.util.StdDateFormat}. 96 *<p> 97 * Note that the configured format object will be cloned once per 98 * deserialization process (first time it is needed) 99 */ 100 protected final DateFormat _dateFormat; 101 102 /** 103 * Object used for creating instances of handlers (serializers, deserializers, 104 * type and type id resolvers), given class to instantiate. This is typically 105 * used to do additional configuration (with dependency injection, for example) 106 * beyond simply construction of instances; or to use alternative constructors. 107 */ 108 protected final HandlerInstantiator _handlerInstantiator; 109 110 /** 111 * Default {@link java.util.Locale} used with serialization formats. 112 * Default value is {@link Locale#getDefault()}. 113 */ 114 protected final Locale _locale; 115 116 /** 117 * Default {@link java.util.TimeZone} used with serialization formats, 118 * if (and only if!) explicitly set by use; otherwise `null` to indicate 119 * "use default", which means "UTC" (from Jackson 2.7); earlier versions 120 * (up to 2.6) used "GMT". 121 *<p> 122 * Note that if a new value is set, timezone is also assigned to 123 * {@link #_dateFormat} of this object. 124 */ 125 protected final TimeZone _timeZone; 126 127 /** 128 * Explicitly default {@link Base64Variant} to use for handling 129 * binary data (<code>byte[]</code>), used with data formats 130 * that use base64 encoding (like JSON, CSV). 131 * 132 * @since 2.1 133 */ 134 protected final Base64Variant _defaultBase64; 135 136 /* 137 /********************************************************** 138 /* Construction 139 /********************************************************** 140 */ 141 142 /** 143 * @since 2.10 144 */ BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, PropertyNamingStrategy pns, TypeFactory tf, TypeResolverBuilder<?> typer, DateFormat dateFormat, HandlerInstantiator hi, Locale locale, TimeZone tz, Base64Variant defaultBase64, PolymorphicTypeValidator ptv)145 public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, 146 PropertyNamingStrategy pns, TypeFactory tf, 147 TypeResolverBuilder<?> typer, DateFormat dateFormat, HandlerInstantiator hi, 148 Locale locale, TimeZone tz, Base64Variant defaultBase64, 149 PolymorphicTypeValidator ptv) 150 { 151 _classIntrospector = ci; 152 _annotationIntrospector = ai; 153 _propertyNamingStrategy = pns; 154 _typeFactory = tf; 155 _typeResolverBuilder = typer; 156 _dateFormat = dateFormat; 157 _handlerInstantiator = hi; 158 _locale = locale; 159 _timeZone = tz; 160 _defaultBase64 = defaultBase64; 161 _typeValidator = ptv; 162 } 163 164 @Deprecated // since 2.10 BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, PropertyNamingStrategy pns, TypeFactory tf, TypeResolverBuilder<?> typer, DateFormat dateFormat, HandlerInstantiator hi, Locale locale, TimeZone tz, Base64Variant defaultBase64)165 public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, 166 PropertyNamingStrategy pns, TypeFactory tf, 167 TypeResolverBuilder<?> typer, DateFormat dateFormat, HandlerInstantiator hi, 168 Locale locale, TimeZone tz, Base64Variant defaultBase64) 169 { 170 this(ci, ai, pns, tf, typer, dateFormat, hi, locale, tz, defaultBase64, null); 171 } 172 173 /** 174 * Turns out we are not necessarily 100% stateless, alas, since {@link ClassIntrospector} 175 * typically has a cache. So this method is needed for deep copy() of Mapper. 176 * 177 * @since 2.9.6 178 */ copy()179 public BaseSettings copy() { 180 return new BaseSettings(_classIntrospector.copy(), 181 _annotationIntrospector, 182 _propertyNamingStrategy, 183 _typeFactory, 184 _typeResolverBuilder, 185 _dateFormat, 186 _handlerInstantiator, 187 _locale, 188 _timeZone, 189 _defaultBase64, 190 _typeValidator); 191 192 } 193 194 /* 195 /********************************************************** 196 /* Factory methods 197 /********************************************************** 198 */ 199 withClassIntrospector(ClassIntrospector ci)200 public BaseSettings withClassIntrospector(ClassIntrospector ci) { 201 if (_classIntrospector == ci) { 202 return this; 203 } 204 return new BaseSettings(ci, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, 205 _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, 206 _timeZone, _defaultBase64, _typeValidator); 207 } 208 withAnnotationIntrospector(AnnotationIntrospector ai)209 public BaseSettings withAnnotationIntrospector(AnnotationIntrospector ai) { 210 if (_annotationIntrospector == ai) { 211 return this; 212 } 213 return new BaseSettings(_classIntrospector, ai, _propertyNamingStrategy, _typeFactory, 214 _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, 215 _timeZone, _defaultBase64, _typeValidator); 216 } 217 withInsertedAnnotationIntrospector(AnnotationIntrospector ai)218 public BaseSettings withInsertedAnnotationIntrospector(AnnotationIntrospector ai) { 219 return withAnnotationIntrospector(AnnotationIntrospectorPair.create(ai, _annotationIntrospector)); 220 } 221 withAppendedAnnotationIntrospector(AnnotationIntrospector ai)222 public BaseSettings withAppendedAnnotationIntrospector(AnnotationIntrospector ai) { 223 return withAnnotationIntrospector(AnnotationIntrospectorPair.create(_annotationIntrospector, ai)); 224 } 225 226 /* 227 public BaseSettings withVisibility(PropertyAccessor forMethod, JsonAutoDetect.Visibility visibility) { 228 return new BaseSettings(_classIntrospector, _annotationIntrospector, 229 _visibilityChecker.withVisibility(forMethod, visibility), 230 _propertyNamingStrategy, _typeFactory, 231 _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, 232 _timeZone, _defaultBase64, _typeValidator); 233 } 234 */ 235 withPropertyNamingStrategy(PropertyNamingStrategy pns)236 public BaseSettings withPropertyNamingStrategy(PropertyNamingStrategy pns) { 237 if (_propertyNamingStrategy == pns) { 238 return this; 239 } 240 return new BaseSettings(_classIntrospector, _annotationIntrospector, pns, _typeFactory, 241 _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, 242 _timeZone, _defaultBase64, _typeValidator); 243 } 244 withTypeFactory(TypeFactory tf)245 public BaseSettings withTypeFactory(TypeFactory tf) { 246 if (_typeFactory == tf) { 247 return this; 248 } 249 return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, tf, 250 _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, 251 _timeZone, _defaultBase64, _typeValidator); 252 } 253 withTypeResolverBuilder(TypeResolverBuilder<?> typer)254 public BaseSettings withTypeResolverBuilder(TypeResolverBuilder<?> typer) { 255 if (_typeResolverBuilder == typer) { 256 return this; 257 } 258 return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, 259 typer, _dateFormat, _handlerInstantiator, _locale, 260 _timeZone, _defaultBase64, _typeValidator); 261 } 262 withDateFormat(DateFormat df)263 public BaseSettings withDateFormat(DateFormat df) { 264 if (_dateFormat == df) { 265 return this; 266 } 267 // 26-Sep-2015, tatu: Related to [databind#939], let's try to force TimeZone if 268 // (but only if!) it has been set explicitly. 269 if ((df != null) && hasExplicitTimeZone()) { 270 df = _force(df, _timeZone); 271 } 272 return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, 273 _typeResolverBuilder, df, _handlerInstantiator, _locale, 274 _timeZone, _defaultBase64, _typeValidator); 275 } 276 withHandlerInstantiator(HandlerInstantiator hi)277 public BaseSettings withHandlerInstantiator(HandlerInstantiator hi) { 278 if (_handlerInstantiator == hi) { 279 return this; 280 } 281 return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, 282 _typeResolverBuilder, _dateFormat, hi, _locale, 283 _timeZone, _defaultBase64, _typeValidator); 284 } 285 with(Locale l)286 public BaseSettings with(Locale l) { 287 if (_locale == l) { 288 return this; 289 } 290 return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, 291 _typeResolverBuilder, _dateFormat, _handlerInstantiator, l, 292 _timeZone, _defaultBase64, _typeValidator); 293 } 294 295 /** 296 * Fluent factory for constructing a new instance that uses specified TimeZone. 297 * Note that timezone used with also be assigned to configured {@link DateFormat}, 298 * changing time formatting defaults. 299 */ with(TimeZone tz)300 public BaseSettings with(TimeZone tz) 301 { 302 if (tz == null) { 303 throw new IllegalArgumentException(); 304 } 305 if (tz == _timeZone) { 306 return this; 307 } 308 309 DateFormat df = _force(_dateFormat, tz); 310 return new BaseSettings(_classIntrospector, _annotationIntrospector, 311 _propertyNamingStrategy, _typeFactory, 312 _typeResolverBuilder, df, _handlerInstantiator, _locale, 313 tz, _defaultBase64, _typeValidator); 314 } 315 316 /** 317 * @since 2.1 318 */ with(Base64Variant base64)319 public BaseSettings with(Base64Variant base64) { 320 if (base64 == _defaultBase64) { 321 return this; 322 } 323 return new BaseSettings(_classIntrospector, _annotationIntrospector, 324 _propertyNamingStrategy, _typeFactory, 325 _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, 326 _timeZone, base64, _typeValidator); 327 } 328 329 /** 330 * @since 2.10 331 */ with(PolymorphicTypeValidator v)332 public BaseSettings with(PolymorphicTypeValidator v) { 333 if (v == _typeValidator) { 334 return this; 335 } 336 return new BaseSettings(_classIntrospector, _annotationIntrospector, 337 _propertyNamingStrategy, _typeFactory, 338 _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, 339 _timeZone, _defaultBase64, v); 340 } 341 342 /* 343 /********************************************************** 344 /* API 345 /********************************************************** 346 */ 347 getClassIntrospector()348 public ClassIntrospector getClassIntrospector() { 349 return _classIntrospector; 350 } 351 getAnnotationIntrospector()352 public AnnotationIntrospector getAnnotationIntrospector() { 353 return _annotationIntrospector; 354 } 355 getPropertyNamingStrategy()356 public PropertyNamingStrategy getPropertyNamingStrategy() { 357 return _propertyNamingStrategy; 358 } 359 getTypeFactory()360 public TypeFactory getTypeFactory() { 361 return _typeFactory; 362 } 363 getTypeResolverBuilder()364 public TypeResolverBuilder<?> getTypeResolverBuilder() { 365 return _typeResolverBuilder; 366 } 367 368 /** 369 * @since 2.10 370 */ getPolymorphicTypeValidator()371 public PolymorphicTypeValidator getPolymorphicTypeValidator() { 372 return _typeValidator; 373 } 374 getDateFormat()375 public DateFormat getDateFormat() { 376 return _dateFormat; 377 } 378 getHandlerInstantiator()379 public HandlerInstantiator getHandlerInstantiator() { 380 return _handlerInstantiator; 381 } 382 getLocale()383 public Locale getLocale() { 384 return _locale; 385 } 386 getTimeZone()387 public TimeZone getTimeZone() { 388 TimeZone tz = _timeZone; 389 return (tz == null) ? DEFAULT_TIMEZONE : tz; 390 } 391 392 /** 393 * Accessor that may be called to determine whether this settings object 394 * has been explicitly configured with a TimeZone (true), or is still 395 * relying on the default settings (false). 396 * 397 * @since 2.7 398 */ hasExplicitTimeZone()399 public boolean hasExplicitTimeZone() { 400 return (_timeZone != null); 401 } 402 getBase64Variant()403 public Base64Variant getBase64Variant() { 404 return _defaultBase64; 405 } 406 407 /* 408 /********************************************************** 409 /* Helper methods 410 /********************************************************** 411 */ 412 _force(DateFormat df, TimeZone tz)413 private DateFormat _force(DateFormat df, TimeZone tz) 414 { 415 if (df instanceof StdDateFormat) { 416 return ((StdDateFormat) df).withTimeZone(tz); 417 } 418 // we don't know if original format might be shared; better create a clone: 419 df = (DateFormat) df.clone(); 420 df.setTimeZone(tz); 421 return df; 422 } 423 } 424