• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SimpleSerializers()57     public SimpleSerializers() { }
58 
59     /**
60      * @since 2.1
61      */
SimpleSerializers(List<JsonSerializer<?>> sers)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      */
addSerializer(JsonSerializer<?> ser)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 
addSerializer(Class<? extends T> type, JsonSerializer<T> ser)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      */
addSerializers(List<JsonSerializer<?>> sers)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
findSerializer(SerializationConfig config, JavaType type, BeanDescription beanDesc)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
findArraySerializer(SerializationConfig config, ArrayType type, BeanDescription beanDesc, TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)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
findCollectionSerializer(SerializationConfig config, CollectionType type, BeanDescription beanDesc, TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)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
findCollectionLikeSerializer(SerializationConfig config, CollectionLikeType type, BeanDescription beanDesc, TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)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
findMapSerializer(SerializationConfig config, MapType type, BeanDescription beanDesc, JsonSerializer<Object> keySerializer, TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)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
findMapLikeSerializer(SerializationConfig config, MapLikeType type, BeanDescription beanDesc, JsonSerializer<Object> keySerializer, TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)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 
_findInterfaceMapping(Class<?> cls, ClassKey key)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 
_addSerializer(Class<?> cls, JsonSerializer<?> ser)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