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