1 package com.fasterxml.jackson.databind.module;
2
3 import java.util.*;
4
5
6 import com.fasterxml.jackson.databind.*;
7 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
8 import com.fasterxml.jackson.databind.ser.Serializers;
9 import com.fasterxml.jackson.databind.type.ArrayType;
10 import com.fasterxml.jackson.databind.type.ClassKey;
11 import com.fasterxml.jackson.databind.type.CollectionLikeType;
12 import com.fasterxml.jackson.databind.type.CollectionType;
13 import com.fasterxml.jackson.databind.type.MapLikeType;
14 import com.fasterxml.jackson.databind.type.MapType;
15
16 /**
17  * Simple implementation {@link Serializers} which allows registration of
18  * serializers based on raw (type erased class).
19  * It can work well for basic bean and scalar type serializers, but is not
20  * a good fit for handling generic types (like {@link Map}s and {@link Collection}s).
21  *<p>
22  * Type registrations are assumed to be general; meaning that registration of serializer
23  * for a super type will also be used for handling subtypes, unless an exact match
24  * is found first. As an example, handler for {@link CharSequence} would also be used
25  * serializing {@link StringBuilder} instances, unless a direct mapping was found.
26  */

27 public class SimpleSerializers
28     extends Serializers.Base
29     implements java.io.Serializable
30 {
31     private static final long serialVersionUID = 3L;
32
33     /**
34      * Class-based mappings that are used both for exact and
35      * sub-class matches.
36      */

37     protected HashMap<ClassKey,JsonSerializer<?>> _classMappings = null;
38
39     /**
40      * Interface-based matches.
41      */

42     protected HashMap<ClassKey,JsonSerializer<?>> _interfaceMappings = null;
43
44     /**
45      * Flag to help find "generic" enum serializer, if one has been registered.
46      * 
47      * @since 2.3
48      */

49     protected boolean _hasEnumSerializer = false;
50     
51     /*
52     /**********************************************************
53     /* Life-cycle, construction and configuring
54     /**********************************************************
55      */

56     
57     public SimpleSerializers() { }
58
59     /**
60      * @since 2.1
61      */

62     public SimpleSerializers(List<JsonSerializer<?>> sers) {
63         addSerializers(sers);
64     }
65     
66     /**
67      * Method for adding given serializer for type that {@link JsonSerializer#handledType}
68      * specifies (which MUST return a non-null class; and can NOT be {@link Object}, as a
69      * sanity check).
70      * For serializers that do not declare handled type, use the variant that takes
71      * two arguments.
72      * 
73      * @param ser
74      */

75     public void addSerializer(JsonSerializer<?> ser)
76     {
77         // Interface to match?
78         Class<?> cls = ser.handledType();
79         if (cls == null || cls == Object.class) {
80             throw new IllegalArgumentException("JsonSerializer of type "+ser.getClass().getName()
81                     +" does not define valid handledType() -- must either register with method that takes type argument "
82                     +" or make serializer extend 'com.fasterxml.jackson.databind.ser.std.StdSerializer'"); 
83         }
84         _addSerializer(cls, ser);
85     }
86
87     public <T> void addSerializer(Class<? extends T> type, JsonSerializer<T> ser)
88     {
89         _addSerializer(type, ser);
90     }
91
92     /**
93      * @since 2.1
94      */

95     public void addSerializers(List<JsonSerializer<?>> sers) {
96         for (JsonSerializer<?> ser : sers) {
97             addSerializer(ser);
98         }
99     }
100     
101     /*
102     /**********************************************************
103     /* Serializers implementation
104     /**********************************************************
105      */

106     
107     @Override
108     public JsonSerializer<?> findSerializer(SerializationConfig config,
109             JavaType type, BeanDescription beanDesc)
110     {
111         Class<?> cls = type.getRawClass();
112         ClassKey key = new ClassKey(cls);
113         JsonSerializer<?> ser = null;
114         
115         // First: direct match?
116         if (cls.isInterface()) {
117             if (_interfaceMappings != null) {
118                 ser = _interfaceMappings.get(key);
119                 if (ser != null) {
120                     return ser;
121                 }
122             }
123         } else {
124             if (_classMappings != null) {
125                 ser = _classMappings.get(key);
126                 if (ser != null) {
127                     return ser;
128                 }
129
130                 // [Issue#227]: Handle registration of plain `Enum` serializer
131                 if (_hasEnumSerializer && type.isEnumType()) {
132                     key.reset(Enum.class);
133                     ser = _classMappings.get(key);
134                     if (ser != null) {
135                         return ser;
136                     }
137                 }
138                 
139                 // If not direct match, maybe super-class match?
140                 for (Class<?> curr = cls; (curr != null); curr = curr.getSuperclass()) {
141                     key.reset(curr);
142                     ser = _classMappings.get(key);
143                     if (ser != null) {
144                         return ser;
145                     }
146                 }
147             }
148         }
149         // No direct match? How about super-interfaces?
150         if (_interfaceMappings != null) {
151             ser = _findInterfaceMapping(cls, key);
152             if (ser != null) {
153                 return ser;
154             }
155             // still no matches? Maybe interfaces of super classes
156             if (!cls.isInterface()) {
157                 while ((cls = cls.getSuperclass()) != null) {
158                     ser = _findInterfaceMapping(cls, key);
159                     if (ser != null) {
160                         return ser;
161                     }
162                 }
163             }
164         }
165         return null;
166     }
167
168     @Override
169     public JsonSerializer<?> findArraySerializer(SerializationConfig config,
170             ArrayType type, BeanDescription beanDesc,
171             TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer) {
172         return findSerializer(config, type, beanDesc);
173     }
174
175     @Override
176     public JsonSerializer<?> findCollectionSerializer(SerializationConfig config,
177             CollectionType type, BeanDescription beanDesc,
178             TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer) {
179         return findSerializer(config, type, beanDesc);
180     }
181
182     @Override
183     public JsonSerializer<?> findCollectionLikeSerializer(SerializationConfig config,
184             CollectionLikeType type, BeanDescription beanDesc,
185             TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer) {
186         return findSerializer(config, type, beanDesc);
187     }
188         
189     @Override
190     public JsonSerializer<?> findMapSerializer(SerializationConfig config,
191             MapType type, BeanDescription beanDesc,
192             JsonSerializer<Object> keySerializer,
193             TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer) {
194         return findSerializer(config, type, beanDesc);
195     }
196
197     @Override
198     public JsonSerializer<?> findMapLikeSerializer(SerializationConfig config,
199             MapLikeType type, BeanDescription beanDesc,
200             JsonSerializer<Object> keySerializer,
201             TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer) {
202         return findSerializer(config, type, beanDesc);
203     }
204     
205     /*
206     /**********************************************************
207     /* Internal methods
208     /**********************************************************
209      */

210     
211     protected JsonSerializer<?> _findInterfaceMapping(Class<?> cls, ClassKey key)
212     {
213         for (Class<?> iface : cls.getInterfaces()) {
214             key.reset(iface);
215             JsonSerializer<?> ser = _interfaceMappings.get(key);
216             if (ser != null) {
217                 return ser;
218             }
219             ser = _findInterfaceMapping(iface, key);
220             if (ser != null) {
221                 return ser;
222             }
223         }
224         return null;
225     }
226
227     protected void _addSerializer(Class<?> cls, JsonSerializer<?> ser)
228     {
229         ClassKey key = new ClassKey(cls);
230         // Interface or class type?
231         if (cls.isInterface()) {
232             if (_interfaceMappings == null) {
233                 _interfaceMappings = new HashMap<ClassKey,JsonSerializer<?>>();
234             }
235             _interfaceMappings.put(key, ser);
236         } else { // nope, class:
237             if (_classMappings == null) {
238                 _classMappings = new HashMap<ClassKey,JsonSerializer<?>>();
239             }
240             _classMappings.put(key, ser);
241             if (cls == Enum.class) {
242                 _hasEnumSerializer = true;
243             }
244         }
245     }
246 }
247