1 package com.fasterxml.jackson.databind.module; 2 3 import java.util.Collection; 4 import java.util.HashMap; 5 import java.util.LinkedHashSet; 6 import java.util.List; 7 import java.util.Map; 8 9 import com.fasterxml.jackson.core.Version; 10 import com.fasterxml.jackson.databind.*; 11 import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; 12 import com.fasterxml.jackson.databind.deser.ValueInstantiator; 13 import com.fasterxml.jackson.databind.jsontype.NamedType; 14 import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; 15 16 /** 17 * Vanilla {@link Module} implementation that allows registration 18 * of serializers and deserializers, bean serializer 19 * and deserializer modifiers, registration of subtypes and mix-ins 20 * as well as some other commonly 21 * needed aspects (addition of custom {@link AbstractTypeResolver}s, 22 * {@link com.fasterxml.jackson.databind.deser.ValueInstantiator}s). 23 *<p> 24 * NOTE: although it is not expected that sub-types should need to 25 * override {@link #setupModule(SetupContext)} method, if they choose 26 * to do so they MUST call {@code super.setupModule(context);} 27 * to ensure that registration works as expected. 28 *<p> 29 * WARNING: when registering {@link JsonSerializer}s and {@link JsonDeserializer}s, 30 * only type erased {@code Class} is compared: this means that usually you should 31 * NOT use this implementation for registering structured types such as 32 * {@link java.util.Collection}s or {@link java.util.Map}s: this because parametric 33 * type information will not be considered and you may end up having "wrong" handler 34 * for your type. 35 * What you need to do, instead, is to implement {@link com.fasterxml.jackson.databind.deser.Deserializers} 36 * and/or {@link com.fasterxml.jackson.databind.ser.Serializers} callbacks to match full type 37 * signatures (with {@link JavaType}). 38 */ 39 public class SimpleModule 40 extends com.fasterxml.jackson.databind.Module 41 implements java.io.Serializable 42 { 43 private static final long serialVersionUID = 1L; // 2.5.0 44 45 protected final String _name; 46 protected final Version _version; 47 48 protected SimpleSerializers _serializers = null; 49 protected SimpleDeserializers _deserializers = null; 50 51 protected SimpleSerializers _keySerializers = null; 52 protected SimpleKeyDeserializers _keyDeserializers = null; 53 54 /** 55 * Lazily-constructed resolver used for storing mappings from 56 * abstract classes to more specific implementing classes 57 * (which may be abstract or concrete) 58 */ 59 protected SimpleAbstractTypeResolver _abstractTypes = null; 60 61 /** 62 * Lazily-constructed resolver used for storing mappings from 63 * abstract classes to more specific implementing classes 64 * (which may be abstract or concrete) 65 */ 66 protected SimpleValueInstantiators _valueInstantiators = null; 67 68 /** 69 * @since 2.2 70 */ 71 protected BeanDeserializerModifier _deserializerModifier = null; 72 73 /** 74 * @since 2.2 75 */ 76 protected BeanSerializerModifier _serializerModifier = null; 77 78 /** 79 * Lazily-constructed map that contains mix-in definitions, indexed 80 * by target class, value being mix-in to apply. 81 */ 82 protected HashMap<Class<?>, Class<?>> _mixins = null; 83 84 /** 85 * Set of subtypes to register, if any. 86 */ 87 protected LinkedHashSet<NamedType> _subtypes = null; 88 89 /** 90 * @since 2.3 91 */ 92 protected PropertyNamingStrategy _namingStrategy = null; 93 94 /* 95 /********************************************************** 96 /* Life-cycle: creation 97 /********************************************************** 98 */ 99 100 /** 101 * Constructors that should only be used for non-reusable 102 * convenience modules used by app code: "real" modules should 103 * use actual name and version number information. 104 */ SimpleModule()105 public SimpleModule() { 106 // can't chain when making reference to 'this' 107 // note: generate different name for direct instantiation, sub-classing 108 _name = (getClass() == SimpleModule.class) ? 109 "SimpleModule-"+System.identityHashCode(this) 110 : getClass().getName(); 111 _version = Version.unknownVersion(); 112 } 113 114 /** 115 * Convenience constructor that will default version to 116 * {@link Version#unknownVersion()}. 117 */ SimpleModule(String name)118 public SimpleModule(String name) { 119 this(name, Version.unknownVersion()); 120 } 121 122 /** 123 * Convenience constructor that will use specified Version, 124 * including name from {@link Version#getArtifactId()} 125 */ SimpleModule(Version version)126 public SimpleModule(Version version) { 127 _name = version.getArtifactId(); 128 _version = version; 129 } 130 131 /** 132 * Constructor to use for actual reusable modules. 133 * ObjectMapper may use name as identifier to notice attempts 134 * for multiple registrations of the same module (although it 135 * does not have to). 136 * 137 * @param name Unique name of the module 138 * @param version Version of the module 139 */ SimpleModule(String name, Version version)140 public SimpleModule(String name, Version version) { 141 _name = name; 142 _version = version; 143 } 144 145 /** 146 * @since 2.1 147 */ SimpleModule(String name, Version version, Map<Class<?>,JsonDeserializer<?>> deserializers)148 public SimpleModule(String name, Version version, 149 Map<Class<?>,JsonDeserializer<?>> deserializers) { 150 this(name, version, deserializers, null); 151 } 152 153 /** 154 * @since 2.1 155 */ SimpleModule(String name, Version version, List<JsonSerializer<?>> serializers)156 public SimpleModule(String name, Version version, 157 List<JsonSerializer<?>> serializers) { 158 this(name, version, null, serializers); 159 } 160 161 /** 162 * @since 2.1 163 */ SimpleModule(String name, Version version, Map<Class<?>,JsonDeserializer<?>> deserializers, List<JsonSerializer<?>> serializers)164 public SimpleModule(String name, Version version, 165 Map<Class<?>,JsonDeserializer<?>> deserializers, 166 List<JsonSerializer<?>> serializers) 167 { 168 _name = name; 169 _version = version; 170 if (deserializers != null) { 171 _deserializers = new SimpleDeserializers(deserializers); 172 } 173 if (serializers != null) { 174 _serializers = new SimpleSerializers(serializers); 175 } 176 } 177 178 /** 179 * Since instances are likely to be custom, implementation returns 180 * <code>null</code> if (but only if!) this class is directly instantiated; 181 * but class name (default impl) for sub-classes. 182 */ 183 @Override getTypeId()184 public Object getTypeId() { 185 if (getClass() == SimpleModule.class) { 186 return null; 187 } 188 return super.getTypeId(); 189 } 190 191 /* 192 /********************************************************** 193 /* Simple setters to allow overriding 194 /********************************************************** 195 */ 196 197 /** 198 * Resets all currently configured serializers. 199 */ setSerializers(SimpleSerializers s)200 public void setSerializers(SimpleSerializers s) { 201 _serializers = s; 202 } 203 204 /** 205 * Resets all currently configured deserializers. 206 */ setDeserializers(SimpleDeserializers d)207 public void setDeserializers(SimpleDeserializers d) { 208 _deserializers = d; 209 } 210 211 /** 212 * Resets all currently configured key serializers. 213 */ setKeySerializers(SimpleSerializers ks)214 public void setKeySerializers(SimpleSerializers ks) { 215 _keySerializers = ks; 216 } 217 218 /** 219 * Resets all currently configured key deserializers. 220 */ setKeyDeserializers(SimpleKeyDeserializers kd)221 public void setKeyDeserializers(SimpleKeyDeserializers kd) { 222 _keyDeserializers = kd; 223 } 224 225 /** 226 * Resets currently configured abstract type mappings 227 */ setAbstractTypes(SimpleAbstractTypeResolver atr)228 public void setAbstractTypes(SimpleAbstractTypeResolver atr) { 229 _abstractTypes = atr; 230 } 231 232 /** 233 * Resets all currently configured value instantiators 234 */ setValueInstantiators(SimpleValueInstantiators svi)235 public void setValueInstantiators(SimpleValueInstantiators svi) { 236 _valueInstantiators = svi; 237 } 238 239 /** 240 * @since 2.2 241 */ setDeserializerModifier(BeanDeserializerModifier mod)242 public SimpleModule setDeserializerModifier(BeanDeserializerModifier mod) { 243 _deserializerModifier = mod; 244 return this; 245 } 246 247 /** 248 * @since 2.2 249 */ setSerializerModifier(BeanSerializerModifier mod)250 public SimpleModule setSerializerModifier(BeanSerializerModifier mod) { 251 _serializerModifier = mod; 252 return this; 253 } 254 255 /** 256 * @since 2.3 257 */ setNamingStrategy(PropertyNamingStrategy naming)258 protected SimpleModule setNamingStrategy(PropertyNamingStrategy naming) { 259 _namingStrategy = naming; 260 return this; 261 } 262 263 /* 264 /********************************************************** 265 /* Configuration methods, adding serializers 266 /********************************************************** 267 */ 268 269 /** 270 * Method for adding serializer to handle type that the serializer claims to handle 271 * (see {@link JsonSerializer#handledType()}). 272 *<p> 273 * WARNING! Type matching only uses type-erased {@code Class} and should NOT 274 * be used when registering serializers for generic types like 275 * {@link java.util.Collection} and {@link java.util.Map}. 276 */ addSerializer(JsonSerializer<?> ser)277 public SimpleModule addSerializer(JsonSerializer<?> ser) 278 { 279 _checkNotNull(ser, "serializer"); 280 if (_serializers == null) { 281 _serializers = new SimpleSerializers(); 282 } 283 _serializers.addSerializer(ser); 284 return this; 285 } 286 287 /** 288 * Method for adding serializer to handle values of specific type. 289 *<p> 290 * WARNING! Type matching only uses type-erased {@code Class} and should NOT 291 * be used when registering serializers for generic types like 292 * {@link java.util.Collection} and {@link java.util.Map}. 293 */ addSerializer(Class<? extends T> type, JsonSerializer<T> ser)294 public <T> SimpleModule addSerializer(Class<? extends T> type, JsonSerializer<T> ser) 295 { 296 _checkNotNull(type, "type to register serializer for"); 297 _checkNotNull(ser, "serializer"); 298 if (_serializers == null) { 299 _serializers = new SimpleSerializers(); 300 } 301 _serializers.addSerializer(type, ser); 302 return this; 303 } 304 addKeySerializer(Class<? extends T> type, JsonSerializer<T> ser)305 public <T> SimpleModule addKeySerializer(Class<? extends T> type, JsonSerializer<T> ser) 306 { 307 _checkNotNull(type, "type to register key serializer for"); 308 _checkNotNull(ser, "key serializer"); 309 if (_keySerializers == null) { 310 _keySerializers = new SimpleSerializers(); 311 } 312 _keySerializers.addSerializer(type, ser); 313 return this; 314 } 315 316 /* 317 /********************************************************** 318 /* Configuration methods, adding deserializers 319 /********************************************************** 320 */ 321 322 /** 323 * Method for adding deserializer to handle specified type. 324 *<p> 325 * WARNING! Type matching only uses type-erased {@code Class} and should NOT 326 * be used when registering serializers for generic types like 327 * {@link java.util.Collection} and {@link java.util.Map}. 328 */ addDeserializer(Class<T> type, JsonDeserializer<? extends T> deser)329 public <T> SimpleModule addDeserializer(Class<T> type, JsonDeserializer<? extends T> deser) 330 { 331 _checkNotNull(type, "type to register deserializer for"); 332 _checkNotNull(deser, "deserializer"); 333 if (_deserializers == null) { 334 _deserializers = new SimpleDeserializers(); 335 } 336 _deserializers.addDeserializer(type, deser); 337 return this; 338 } 339 addKeyDeserializer(Class<?> type, KeyDeserializer deser)340 public SimpleModule addKeyDeserializer(Class<?> type, KeyDeserializer deser) 341 { 342 _checkNotNull(type, "type to register key deserializer for"); 343 _checkNotNull(deser, "key deserializer"); 344 if (_keyDeserializers == null) { 345 _keyDeserializers = new SimpleKeyDeserializers(); 346 } 347 _keyDeserializers.addDeserializer(type, deser); 348 return this; 349 } 350 351 /* 352 /********************************************************** 353 /* Configuration methods, type mapping 354 /********************************************************** 355 */ 356 357 /** 358 * Lazily-constructed resolver used for storing mappings from 359 * abstract classes to more specific implementing classes 360 * (which may be abstract or concrete) 361 */ addAbstractTypeMapping(Class<T> superType, Class<? extends T> subType)362 public <T> SimpleModule addAbstractTypeMapping(Class<T> superType, 363 Class<? extends T> subType) 364 { 365 _checkNotNull(superType, "abstract type to map"); 366 _checkNotNull(subType, "concrete type to map to"); 367 if (_abstractTypes == null) { 368 _abstractTypes = new SimpleAbstractTypeResolver(); 369 } 370 // note: addMapping() will verify arguments 371 _abstractTypes = _abstractTypes.addMapping(superType, subType); 372 return this; 373 } 374 375 /** 376 * Method for adding set of subtypes to be registered with 377 * {@link ObjectMapper} 378 * this is an alternative to using annotations in super type to indicate subtypes. 379 */ registerSubtypes(Class<?> .... subtypes)380 public SimpleModule registerSubtypes(Class<?> ... subtypes) 381 { 382 if (_subtypes == null) { 383 _subtypes = new LinkedHashSet<>(); 384 } 385 for (Class<?> subtype : subtypes) { 386 _checkNotNull(subtype, "subtype to register"); 387 _subtypes.add(new NamedType(subtype)); 388 } 389 return this; 390 } 391 392 /** 393 * Method for adding set of subtypes (along with type name to use) to be registered with 394 * {@link ObjectMapper} 395 * this is an alternative to using annotations in super type to indicate subtypes. 396 */ registerSubtypes(NamedType .... subtypes)397 public SimpleModule registerSubtypes(NamedType ... subtypes) 398 { 399 if (_subtypes == null) { 400 _subtypes = new LinkedHashSet<>(); 401 } 402 for (NamedType subtype : subtypes) { 403 _checkNotNull(subtype, "subtype to register"); 404 _subtypes.add(subtype); 405 } 406 return this; 407 } 408 409 /** 410 * Method for adding set of subtypes (along with type name to use) to be registered with 411 * {@link ObjectMapper} 412 * this is an alternative to using annotations in super type to indicate subtypes. 413 * 414 * @since 2.9 415 */ registerSubtypes(Collection<Class<?>> subtypes)416 public SimpleModule registerSubtypes(Collection<Class<?>> subtypes) 417 { 418 if (_subtypes == null) { 419 _subtypes = new LinkedHashSet<>(); 420 } 421 for (Class<?> subtype : subtypes) { 422 _checkNotNull(subtype, "subtype to register"); 423 _subtypes.add(new NamedType(subtype)); 424 } 425 return this; 426 } 427 428 /* 429 /********************************************************** 430 /* Configuration methods, add other handlers 431 /********************************************************** 432 */ 433 434 /** 435 * Method for registering {@link ValueInstantiator} to use when deserializing 436 * instances of type <code>beanType</code>. 437 *<p> 438 * Instantiator is 439 * registered when module is registered for <code>ObjectMapper</code>. 440 */ addValueInstantiator(Class<?> beanType, ValueInstantiator inst)441 public SimpleModule addValueInstantiator(Class<?> beanType, ValueInstantiator inst) 442 { 443 _checkNotNull(beanType, "class to register value instantiator for"); 444 _checkNotNull(inst, "value instantiator"); 445 if (_valueInstantiators == null) { 446 _valueInstantiators = new SimpleValueInstantiators(); 447 } 448 _valueInstantiators = _valueInstantiators.addValueInstantiator(beanType, inst); 449 return this; 450 } 451 452 /** 453 * Method for specifying that annotations define by <code>mixinClass</code> 454 * should be "mixed in" with annotations that <code>targetType</code> 455 * has (as if they were directly included on it!). 456 *<p> 457 * Mix-in annotations are 458 * registered when module is registered for <code>ObjectMapper</code>. 459 */ setMixInAnnotation(Class<?> targetType, Class<?> mixinClass)460 public SimpleModule setMixInAnnotation(Class<?> targetType, Class<?> mixinClass) 461 { 462 _checkNotNull(targetType, "target type"); 463 _checkNotNull(mixinClass, "mixin class"); 464 if (_mixins == null) { 465 _mixins = new HashMap<Class<?>, Class<?>>(); 466 } 467 _mixins.put(targetType, mixinClass); 468 return this; 469 } 470 471 /* 472 /********************************************************** 473 /* Module impl 474 /********************************************************** 475 */ 476 477 @Override getModuleName()478 public String getModuleName() { 479 return _name; 480 } 481 482 /** 483 * Standard implementation handles registration of all configured 484 * customizations: it is important that sub-classes call this 485 * implementation (usually before additional custom logic) 486 * if they choose to override it; otherwise customizations 487 * will not be registered. 488 */ 489 @Override setupModule(SetupContext context)490 public void setupModule(SetupContext context) 491 { 492 if (_serializers != null) { 493 context.addSerializers(_serializers); 494 } 495 if (_deserializers != null) { 496 context.addDeserializers(_deserializers); 497 } 498 if (_keySerializers != null) { 499 context.addKeySerializers(_keySerializers); 500 } 501 if (_keyDeserializers != null) { 502 context.addKeyDeserializers(_keyDeserializers); 503 } 504 if (_abstractTypes != null) { 505 context.addAbstractTypeResolver(_abstractTypes); 506 } 507 if (_valueInstantiators != null) { 508 context.addValueInstantiators(_valueInstantiators); 509 } 510 if (_deserializerModifier != null) { 511 context.addBeanDeserializerModifier(_deserializerModifier); 512 } 513 if (_serializerModifier != null) { 514 context.addBeanSerializerModifier(_serializerModifier); 515 } 516 if (_subtypes != null && _subtypes.size() > 0) { 517 context.registerSubtypes(_subtypes.toArray(new NamedType[_subtypes.size()])); 518 } 519 if (_namingStrategy != null) { 520 context.setNamingStrategy(_namingStrategy); 521 } 522 if (_mixins != null) { 523 for (Map.Entry<Class<?>,Class<?>> entry : _mixins.entrySet()) { 524 context.setMixInAnnotations(entry.getKey(), entry.getValue()); 525 } 526 } 527 } 528 529 @Override version()530 public Version version() { return _version; } 531 532 /* 533 /********************************************************** 534 /* Helper methods 535 /********************************************************** 536 */ 537 538 /** 539 * @since 2.9 540 */ _checkNotNull(Object thingy, String type)541 protected void _checkNotNull(Object thingy, String type) 542 { 543 if (thingy == null) { 544 throw new IllegalArgumentException(String.format( 545 "Cannot pass `null` as %s", type)); 546 } 547 } 548 } 549