1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.type;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.Modifier;
20 import java.lang.reflect.Type;
21 import java.math.BigDecimal;
22 import java.math.BigInteger;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Date;
26 import java.util.EnumMap;
27 import java.util.HashMap;
28 import java.util.Map;
29 import java.util.Set;
30
31 import org.apache.ibatis.io.ResolverUtil;
32
33
34
35
36 public final class TypeHandlerRegistry {
37
38 private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);
39 private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();
40 private final TypeHandler<Object> UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);
41 private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();
42
43 public TypeHandlerRegistry() {
44 register(Boolean.class, new BooleanTypeHandler());
45 register(boolean.class, new BooleanTypeHandler());
46 register(JdbcType.BOOLEAN, new BooleanTypeHandler());
47 register(JdbcType.BIT, new BooleanTypeHandler());
48
49 register(Byte.class, new ByteTypeHandler());
50 register(byte.class, new ByteTypeHandler());
51 register(JdbcType.TINYINT, new ByteTypeHandler());
52
53 register(Short.class, new ShortTypeHandler());
54 register(short.class, new ShortTypeHandler());
55 register(JdbcType.SMALLINT, new ShortTypeHandler());
56
57 register(Integer.class, new IntegerTypeHandler());
58 register(int.class, new IntegerTypeHandler());
59 register(JdbcType.INTEGER, new IntegerTypeHandler());
60
61 register(Long.class, new LongTypeHandler());
62 register(long.class, new LongTypeHandler());
63
64 register(Float.class, new FloatTypeHandler());
65 register(float.class, new FloatTypeHandler());
66 register(JdbcType.FLOAT, new FloatTypeHandler());
67
68 register(Double.class, new DoubleTypeHandler());
69 register(double.class, new DoubleTypeHandler());
70 register(JdbcType.DOUBLE, new DoubleTypeHandler());
71
72 register(String.class, new StringTypeHandler());
73 register(String.class, JdbcType.CHAR, new StringTypeHandler());
74 register(String.class, JdbcType.CLOB, new ClobTypeHandler());
75 register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
76 register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
77 register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
78 register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
79 register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
80 register(JdbcType.CHAR, new StringTypeHandler());
81 register(JdbcType.VARCHAR, new StringTypeHandler());
82 register(JdbcType.CLOB, new ClobTypeHandler());
83 register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
84 register(JdbcType.NVARCHAR, new NStringTypeHandler());
85 register(JdbcType.NCHAR, new NStringTypeHandler());
86 register(JdbcType.NCLOB, new NClobTypeHandler());
87
88 register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
89 register(JdbcType.ARRAY, new ArrayTypeHandler());
90
91 register(BigInteger.class, new BigIntegerTypeHandler());
92 register(JdbcType.BIGINT, new LongTypeHandler());
93
94 register(BigDecimal.class, new BigDecimalTypeHandler());
95 register(JdbcType.REAL, new BigDecimalTypeHandler());
96 register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
97 register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
98
99 register(Byte[].class, new ByteObjectArrayTypeHandler());
100 register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
101 register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
102 register(byte[].class, new ByteArrayTypeHandler());
103 register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
104 register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
105 register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
106 register(JdbcType.BLOB, new BlobTypeHandler());
107
108 register(Object.class, UNKNOWN_TYPE_HANDLER);
109 register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
110 register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
111
112 register(Date.class, new DateTypeHandler());
113 register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
114 register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
115 register(JdbcType.TIMESTAMP, new DateTypeHandler());
116 register(JdbcType.DATE, new DateOnlyTypeHandler());
117 register(JdbcType.TIME, new TimeOnlyTypeHandler());
118
119 register(java.sql.Date.class, new SqlDateTypeHandler());
120 register(java.sql.Time.class, new SqlTimeTypeHandler());
121 register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());
122
123
124 register(Character.class, new CharacterTypeHandler());
125 register(char.class, new CharacterTypeHandler());
126 }
127
128 public boolean hasTypeHandler(Class<?> javaType) {
129 return hasTypeHandler(javaType, null);
130 }
131
132 public boolean hasTypeHandler(TypeReference<?> javaTypeReference) {
133 return hasTypeHandler(javaTypeReference, null);
134 }
135
136 public boolean hasTypeHandler(Class<?> javaType, JdbcType jdbcType) {
137 return javaType != null && getTypeHandler((Type) javaType, jdbcType) != null;
138 }
139
140 public boolean hasTypeHandler(TypeReference<?> javaTypeReference, JdbcType jdbcType) {
141 return javaTypeReference != null && getTypeHandler(javaTypeReference, jdbcType) != null;
142 }
143
144 public TypeHandler<?> getMappingTypeHandler(Class<? extends TypeHandler<?>> handlerType) {
145 return ALL_TYPE_HANDLERS_MAP.get(handlerType);
146 }
147
148 public <T> TypeHandler<T> getTypeHandler(Class<T> type) {
149 return getTypeHandler((Type) type, null);
150 }
151
152 public <T> TypeHandler<T> getTypeHandler(TypeReference<T> javaTypeReference) {
153 return getTypeHandler(javaTypeReference, null);
154 }
155
156 public TypeHandler<?> getTypeHandler(JdbcType jdbcType) {
157 return JDBC_TYPE_HANDLER_MAP.get(jdbcType);
158 }
159
160 public <T> TypeHandler<T> getTypeHandler(Class<T> type, JdbcType jdbcType) {
161 return getTypeHandler((Type) type, jdbcType);
162 }
163
164 public <T> TypeHandler<T> getTypeHandler(TypeReference<T> javaTypeReference, JdbcType jdbcType) {
165 return getTypeHandler(javaTypeReference.getRawType(), jdbcType);
166 }
167
168 @SuppressWarnings("unchecked")
169 private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {
170 Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = TYPE_HANDLER_MAP.get(type);
171 TypeHandler<?> handler = null;
172 if (jdbcHandlerMap != null) {
173 handler = jdbcHandlerMap.get(jdbcType);
174 if (handler == null) {
175 handler = jdbcHandlerMap.get(null);
176 }
177 }
178 if (handler == null && type != null && type instanceof Class && Enum.class.isAssignableFrom((Class<?>) type)) {
179 handler = new EnumTypeHandler((Class<?>) type);
180 }
181
182 return (TypeHandler<T>) handler;
183 }
184
185 public TypeHandler<Object> getUnknownTypeHandler() {
186 return UNKNOWN_TYPE_HANDLER;
187 }
188
189 public void register(JdbcType jdbcType, TypeHandler<?> handler) {
190 JDBC_TYPE_HANDLER_MAP.put(jdbcType, handler);
191 }
192
193
194
195
196
197
198
199 @SuppressWarnings("unchecked")
200 public <T> void register(TypeHandler<T> typeHandler) {
201 boolean mappedTypeFound = false;
202 MappedTypes mappedTypes = typeHandler.getClass().getAnnotation(MappedTypes.class);
203 if (mappedTypes != null) {
204 for (Class<?> handledType : mappedTypes.value()) {
205 register(handledType, typeHandler);
206 mappedTypeFound = true;
207 }
208 }
209
210 if (!mappedTypeFound && typeHandler instanceof TypeReference) {
211 try {
212 TypeReference<T> typeReference = (TypeReference<T>) typeHandler;
213 register(typeReference.getRawType(), typeHandler);
214 mappedTypeFound = true;
215 } catch (Throwable t) {
216
217 }
218 }
219 if (!mappedTypeFound) {
220 register((Class<T>) null, typeHandler);
221 }
222 }
223
224
225
226 public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler) {
227 register((Type) javaType, typeHandler);
228 }
229
230 private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {
231 MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
232 if (mappedJdbcTypes != null) {
233 for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
234 register(javaType, handledJdbcType, typeHandler);
235 }
236 if (mappedJdbcTypes.includeNullJdbcType()) {
237 register(javaType, null, typeHandler);
238 }
239 } else {
240 register(javaType, null, typeHandler);
241 }
242 }
243
244 public <T> void register(TypeReference<T> javaTypeReference, TypeHandler<? extends T> handler) {
245 register(javaTypeReference.getRawType(), handler);
246 }
247
248
249
250 public <T> void register(Class<T> type, JdbcType jdbcType, TypeHandler<? extends T> handler) {
251 register((Type) type, jdbcType, handler);
252 }
253
254 private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
255 if (javaType != null) {
256 Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
257 if (map == null) {
258 map = new HashMap<JdbcType, TypeHandler<?>>();
259 TYPE_HANDLER_MAP.put(javaType, map);
260 }
261 map.put(jdbcType, handler);
262 }
263 ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
264 }
265
266
267
268
269
270
271
272 public void register(Class<?> typeHandlerClass) {
273 boolean mappedTypeFound = false;
274 MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
275 if (mappedTypes != null) {
276 for (Class<?> javaTypeClass : mappedTypes.value()) {
277 register(javaTypeClass, typeHandlerClass);
278 mappedTypeFound = true;
279 }
280 }
281 if (!mappedTypeFound) {
282 register(getInstance(null, typeHandlerClass));
283 }
284 }
285
286
287
288 public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
289 register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
290 }
291
292
293
294 public void register(Class<?> javaTypeClass, JdbcType jdbcType, Class<?> typeHandlerClass) {
295 register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass));
296 }
297
298
299
300 @SuppressWarnings("unchecked")
301 public <T> TypeHandler<T> getInstance(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
302 if (javaTypeClass != null) {
303 try {
304 Constructor<?> c = typeHandlerClass.getConstructor(Class.class);
305 return (TypeHandler<T>) c.newInstance(javaTypeClass);
306 } catch (NoSuchMethodException ignored) {
307
308 } catch (Exception e) {
309 throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
310 }
311 }
312 try {
313 Constructor<?> c = typeHandlerClass.getConstructor();
314 return (TypeHandler<T>) c.newInstance();
315 } catch (Exception e) {
316 throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
317 }
318 }
319
320
321
322 public void register(String packageName) {
323 ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
324 resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
325 Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
326 for (Class<?> type : handlerSet) {
327
328 if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
329 register(type);
330 }
331 }
332 }
333
334
335
336
337
338
339 public Collection<TypeHandler<?>> getTypeHandlers() {
340 return Collections.unmodifiableCollection(ALL_TYPE_HANDLERS_MAP.values());
341 }
342
343 }