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);</code>
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 */
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 */
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 */
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 */
140 public SimpleModule(String name, Version version) {
141 _name = name;
142 _version = version;
143 }
144
145 /**
146 * @since 2.1
147 */
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 */
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 */
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
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 */
200 public void setSerializers(SimpleSerializers s) {
201 _serializers = s;
202 }
203
204 /**
205 * Resets all currently configured deserializers.
206 */
207 public void setDeserializers(SimpleDeserializers d) {
208 _deserializers = d;
209 }
210
211 /**
212 * Resets all currently configured key serializers.
213 */
214 public void setKeySerializers(SimpleSerializers ks) {
215 _keySerializers = ks;
216 }
217
218 /**
219 * Resets all currently configured key deserializers.
220 */
221 public void setKeyDeserializers(SimpleKeyDeserializers kd) {
222 _keyDeserializers = kd;
223 }
224
225 /**
226 * Resets currently configured abstract type mappings
227 */
228 public void setAbstractTypes(SimpleAbstractTypeResolver atr) {
229 _abstractTypes = atr;
230 }
231
232 /**
233 * Resets all currently configured value instantiators
234 */
235 public void setValueInstantiators(SimpleValueInstantiators svi) {
236 _valueInstantiators = svi;
237 }
238
239 /**
240 * @since 2.2
241 */
242 public SimpleModule setDeserializerModifier(BeanDeserializerModifier mod) {
243 _deserializerModifier = mod;
244 return this;
245 }
246
247 /**
248 * @since 2.2
249 */
250 public SimpleModule setSerializerModifier(BeanSerializerModifier mod) {
251 _serializerModifier = mod;
252 return this;
253 }
254
255 /**
256 * @since 2.3
257 */
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 */
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 */
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
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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
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
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
530 public Version version() { return _version; }
531
532 /*
533 /**********************************************************
534 /* Helper methods
535 /**********************************************************
536 */
537
538 /**
539 * @since 2.9
540 */
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