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