• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / mybatis-3 / 2695

12 Feb 2025 06:57PM UTC coverage: 87.212% (-0.005%) from 87.217%
2695

Pull #3379

github

web-flow
Merge 1261a3400 into 12d286ea2
Pull Request #3379: Resolve type handler based on `java.lang.reflect.Type` instead of `Class` and respect runtime JDBC type

3820 of 4639 branches covered (82.35%)

525 of 591 new or added lines in 42 files covered. (88.83%)

13 existing lines in 4 files now uncovered.

9882 of 11331 relevant lines covered (87.21%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.63
/src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java
1
/*
2
 *    Copyright 2009-2025 the original author or authors.
3
 *
4
 *    Licensed under the Apache License, Version 2.0 (the "License");
5
 *    you may not use this file except in compliance with the License.
6
 *    You may obtain a copy of the License at
7
 *
8
 *       https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *    Unless required by applicable law or agreed to in writing, software
11
 *    distributed under the License is distributed on an "AS IS" BASIS,
12
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *    See the License for the specific language governing permissions and
14
 *    limitations under the License.
15
 */
16
package org.apache.ibatis.type;
17

18
import java.io.InputStream;
19
import java.io.Reader;
20
import java.lang.reflect.Constructor;
21
import java.lang.reflect.Modifier;
22
import java.lang.reflect.ParameterizedType;
23
import java.lang.reflect.Type;
24
import java.math.BigDecimal;
25
import java.math.BigInteger;
26
import java.sql.Time;
27
import java.sql.Timestamp;
28
import java.time.Instant;
29
import java.time.LocalDate;
30
import java.time.LocalDateTime;
31
import java.time.LocalTime;
32
import java.time.Month;
33
import java.time.OffsetDateTime;
34
import java.time.OffsetTime;
35
import java.time.Year;
36
import java.time.YearMonth;
37
import java.time.ZonedDateTime;
38
import java.time.chrono.JapaneseDate;
39
import java.util.Arrays;
40
import java.util.Collection;
41
import java.util.Collections;
42
import java.util.Date;
43
import java.util.EnumMap;
44
import java.util.HashMap;
45
import java.util.Map;
46
import java.util.Map.Entry;
47
import java.util.Set;
48
import java.util.concurrent.ConcurrentHashMap;
49

50
import org.apache.ibatis.binding.MapperMethod.ParamMap;
51
import org.apache.ibatis.io.ResolverUtil;
52
import org.apache.ibatis.io.Resources;
53
import org.apache.ibatis.reflection.TypeParameterResolver;
54
import org.apache.ibatis.session.Configuration;
55

56
/**
57
 * @author Clinton Begin
58
 * @author Kazuki Shimizu
59
 */
60
public final class TypeHandlerRegistry {
61

62
  private final Map<JdbcType, TypeHandler<?>> jdbcTypeHandlerMap = new EnumMap<>(JdbcType.class);
1✔
63
  private final Map<Type, Map<JdbcType, TypeHandler<?>>> typeHandlerMap = new ConcurrentHashMap<>();
1✔
64
  private final ConcurrentHashMap<Type, Constructor<?>> smartHandlers = new ConcurrentHashMap<>();
1✔
65
  private final Map<Class<?>, TypeHandler<?>> allTypeHandlersMap = new HashMap<>();
1✔
66

67
  private static final Map<JdbcType, TypeHandler<?>> NULL_TYPE_HANDLER_MAP = Collections.emptyMap();
1✔
68

69
  @SuppressWarnings("rawtypes")
1✔
70
  private Class<? extends TypeHandler> defaultEnumTypeHandler = EnumTypeHandler.class;
71

72
  /**
73
   * The default constructor.
74
   */
75
  public TypeHandlerRegistry() {
76
    this(new Configuration());
1✔
77
  }
1✔
78

79
  /**
80
   * The constructor that pass the MyBatis configuration.
81
   *
82
   * @param configuration
83
   *          a MyBatis configuration
84
   *
85
   * @since 3.5.4
86
   */
87
  public TypeHandlerRegistry(Configuration configuration) {
1✔
88
    register(Boolean.class, new BooleanTypeHandler());
1✔
89
    register(boolean.class, new BooleanTypeHandler());
1✔
90
    register(JdbcType.BOOLEAN, new BooleanTypeHandler());
1✔
91
    register(JdbcType.BIT, new BooleanTypeHandler());
1✔
92

93
    register(Byte.class, new ByteTypeHandler());
1✔
94
    register(byte.class, new ByteTypeHandler());
1✔
95
    register(JdbcType.TINYINT, new ByteTypeHandler());
1✔
96

97
    register(Short.class, new ShortTypeHandler());
1✔
98
    register(short.class, new ShortTypeHandler());
1✔
99
    register(JdbcType.SMALLINT, new ShortTypeHandler());
1✔
100

101
    register(Integer.class, new IntegerTypeHandler());
1✔
102
    register(int.class, new IntegerTypeHandler());
1✔
103
    register(JdbcType.INTEGER, new IntegerTypeHandler());
1✔
104

105
    register(Long.class, new LongTypeHandler());
1✔
106
    register(long.class, new LongTypeHandler());
1✔
107

108
    register(Float.class, new FloatTypeHandler());
1✔
109
    register(float.class, new FloatTypeHandler());
1✔
110
    register(JdbcType.FLOAT, new FloatTypeHandler());
1✔
111

112
    register(Double.class, new DoubleTypeHandler());
1✔
113
    register(double.class, new DoubleTypeHandler());
1✔
114
    register(JdbcType.DOUBLE, new DoubleTypeHandler());
1✔
115

116
    register(Reader.class, new ClobReaderTypeHandler());
1✔
117
    register(String.class, new StringTypeHandler());
1✔
118
    register(String.class, JdbcType.CHAR, new StringTypeHandler());
1✔
119
    register(String.class, JdbcType.CLOB, new ClobTypeHandler());
1✔
120
    register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
1✔
121
    register(String.class, JdbcType.LONGVARCHAR, new StringTypeHandler());
1✔
122
    register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
1✔
123
    register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
1✔
124
    register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
1✔
125
    register(JdbcType.CHAR, new StringTypeHandler());
1✔
126
    register(JdbcType.VARCHAR, new StringTypeHandler());
1✔
127
    register(JdbcType.CLOB, new ClobTypeHandler());
1✔
128
    register(JdbcType.LONGVARCHAR, new StringTypeHandler());
1✔
129
    register(JdbcType.NVARCHAR, new NStringTypeHandler());
1✔
130
    register(JdbcType.NCHAR, new NStringTypeHandler());
1✔
131
    register(JdbcType.NCLOB, new NClobTypeHandler());
1✔
132

133
    register(JdbcType.ARRAY, new ArrayTypeHandler());
1✔
134

135
    register(BigInteger.class, new BigIntegerTypeHandler());
1✔
136
    register(JdbcType.BIGINT, new LongTypeHandler());
1✔
137

138
    register(BigDecimal.class, new BigDecimalTypeHandler());
1✔
139
    register(JdbcType.REAL, new BigDecimalTypeHandler());
1✔
140
    register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
1✔
141
    register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
1✔
142

143
    register(InputStream.class, new BlobInputStreamTypeHandler());
1✔
144
    register(Byte[].class, new ByteObjectArrayTypeHandler());
1✔
145
    register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
1✔
146
    register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
1✔
147
    register(byte[].class, new ByteArrayTypeHandler());
1✔
148
    register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
1✔
149
    register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
1✔
150
    register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
1✔
151
    register(JdbcType.BLOB, new BlobTypeHandler());
1✔
152

153
    register(Date.class, new DateTypeHandler());
1✔
154
    register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
1✔
155
    register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
1✔
156
    register(JdbcType.TIMESTAMP, new DateTypeHandler());
1✔
157
    register(JdbcType.DATE, new DateOnlyTypeHandler());
1✔
158
    register(JdbcType.TIME, new TimeOnlyTypeHandler());
1✔
159

160
    register(java.sql.Date.class, new SqlDateTypeHandler());
1✔
161
    register(Time.class, new SqlTimeTypeHandler());
1✔
162
    register(Timestamp.class, new SqlTimestampTypeHandler());
1✔
163

164
    register(String.class, JdbcType.SQLXML, new SqlxmlTypeHandler());
1✔
165

166
    register(Instant.class, new InstantTypeHandler());
1✔
167
    register(LocalDateTime.class, new LocalDateTimeTypeHandler());
1✔
168
    register(LocalDate.class, new LocalDateTypeHandler());
1✔
169
    register(LocalTime.class, new LocalTimeTypeHandler());
1✔
170
    register(OffsetDateTime.class, new OffsetDateTimeTypeHandler());
1✔
171
    register(OffsetTime.class, new OffsetTimeTypeHandler());
1✔
172
    register(ZonedDateTime.class, new ZonedDateTimeTypeHandler());
1✔
173
    register(Month.class, new MonthTypeHandler());
1✔
174
    register(Year.class, new YearTypeHandler());
1✔
175
    register(YearMonth.class, new YearMonthTypeHandler());
1✔
176
    register(JapaneseDate.class, new JapaneseDateTypeHandler());
1✔
177

178
    // issue #273
179
    register(Character.class, new CharacterTypeHandler());
1✔
180
    register(char.class, new CharacterTypeHandler());
1✔
181
  }
1✔
182

183
  /**
184
   * Set a default {@link TypeHandler} class for {@link Enum}. A default {@link TypeHandler} is
185
   * {@link org.apache.ibatis.type.EnumTypeHandler}.
186
   *
187
   * @param typeHandler
188
   *          a type handler class for {@link Enum}
189
   *
190
   * @since 3.4.5
191
   */
192
  public void setDefaultEnumTypeHandler(@SuppressWarnings("rawtypes") Class<? extends TypeHandler> typeHandler) {
193
    this.defaultEnumTypeHandler = typeHandler;
×
194
  }
×
195

196
  public boolean hasTypeHandler(Type javaType) {
197
    return hasTypeHandler(javaType, null);
1✔
198
  }
199

200
  @Deprecated
201
  public boolean hasTypeHandler(TypeReference<?> javaTypeReference) {
202
    return hasTypeHandler(javaTypeReference, null);
×
203
  }
204

205
  public boolean hasTypeHandler(Type javaType, JdbcType jdbcType) {
206
    return javaType != null && getTypeHandler(javaType, jdbcType) != null;
1!
207
  }
208

209
  @Deprecated
210
  public boolean hasTypeHandler(TypeReference<?> javaTypeReference, JdbcType jdbcType) {
211
    return javaTypeReference != null && getTypeHandler(javaTypeReference, jdbcType) != null;
×
212
  }
213

214
  @Deprecated
215
  public TypeHandler<?> getMappingTypeHandler(Class<? extends TypeHandler<?>> handlerType) {
216
    return allTypeHandlersMap.get(handlerType);
1✔
217
  }
218

219
  public TypeHandler<?> getTypeHandler(Type type) {
220
    return getTypeHandler(type, null);
1✔
221
  }
222

223
  @Deprecated
224
  public <T> TypeHandler<T> getTypeHandler(TypeReference<T> javaTypeReference) {
225
    return getTypeHandler(javaTypeReference, null);
1✔
226
  }
227

228
  public TypeHandler<?> getTypeHandler(JdbcType jdbcType) {
229
    return jdbcTypeHandlerMap.get(jdbcType);
1✔
230
  }
231

232
  @SuppressWarnings("unchecked")
233
  @Deprecated
234
  public <T> TypeHandler<T> getTypeHandler(TypeReference<T> javaTypeReference, JdbcType jdbcType) {
235
    return (TypeHandler<T>) getTypeHandler(javaTypeReference.getRawType(), jdbcType);
1✔
236
  }
237

238
  public TypeHandler<?> getTypeHandler(Type type, JdbcType jdbcType, Class<? extends TypeHandler<?>> typeHandlerClass) {
239
    TypeHandler<?> typeHandler = getTypeHandler(type, jdbcType);
1✔
240
    if (typeHandler != null && (typeHandlerClass == null || typeHandler.getClass().equals(typeHandlerClass))) {
1✔
241
      return typeHandler;
1✔
242
    }
243
    if (typeHandlerClass == null) {
1✔
244
      typeHandler = getSmartHandler(type, jdbcType);
1✔
245
    } else {
246
      typeHandler = getMappingTypeHandler(typeHandlerClass);
1✔
247
      if (typeHandler == null) {
1✔
248
        typeHandler = getInstance(type, typeHandlerClass);
1✔
249
      }
250
    }
251
    return typeHandler;
1✔
252
  }
253

254
  public TypeHandler<?> getTypeHandler(Type type, JdbcType jdbcType) {
255
    if (ParamMap.class.equals(type)) {
1✔
256
      return null;
1✔
257
    } else if (type == null) {
1✔
258
      return getTypeHandler(jdbcType);
1✔
259
    }
260

261
    TypeHandler<?> handler = null;
1✔
262
    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = getJdbcHandlerMap(type);
1✔
263

264
    if (Object.class.equals(type)) {
1✔
265
      if (jdbcHandlerMap != null) {
1✔
266
        handler = jdbcHandlerMap.get(jdbcType);
1✔
267
      }
268
      return handler;
1✔
269
    }
270

271
    if (jdbcHandlerMap != null) {
1✔
272
      handler = jdbcHandlerMap.get(jdbcType);
1✔
273
      if (handler == null) {
1✔
274
        handler = jdbcHandlerMap.get(null);
1✔
275
      }
276
      if (handler == null) {
1✔
277
        // #591
278
        handler = pickSoleHandler(jdbcHandlerMap);
1✔
279
      }
280
    }
281
    if (handler == null) {
1✔
282
      handler = getSmartHandler(type, jdbcType);
1✔
283
    }
284
    if (handler == null && type instanceof ParameterizedType) {
1✔
285
      handler = getTypeHandler((Class<?>) ((ParameterizedType) type).getRawType(), jdbcType);
1✔
286
    }
287
    return handler;
1✔
288
  }
289

290
  private TypeHandler<?> getSmartHandler(Type type, JdbcType jdbcType) {
291
    Constructor<?> candidate = null;
1✔
292

293
    for (Entry<Type, Constructor<?>> entry : smartHandlers.entrySet()) {
1✔
294
      Type registeredType = entry.getKey();
1✔
295
      if (registeredType.equals(type)) {
1✔
296
        candidate = entry.getValue();
1✔
297
        break;
1✔
298
      }
299
      if (registeredType instanceof Class) {
1✔
300
        if (type instanceof Class && ((Class<?>) registeredType).isAssignableFrom((Class<?>) type)) {
1!
301
          candidate = entry.getValue();
1✔
302
        }
303
      } else if (registeredType instanceof ParameterizedType) {
1!
304
        Class<?> registeredClass = (Class<?>) ((ParameterizedType) registeredType).getRawType();
1✔
305
        if (type instanceof ParameterizedType) {
1✔
306
          Class<?> clazz = (Class<?>) ((ParameterizedType) type).getRawType();
1✔
307
          if (registeredClass.isAssignableFrom(clazz)) {
1✔
308
            candidate = entry.getValue();
1✔
309
          }
310
        }
311
      }
312
    }
1✔
313

314
    if (candidate == null) {
1✔
315
      if (type instanceof Class) {
1✔
316
        Class<?> clazz = (Class<?>) type;
1✔
317
        if (Enum.class.isAssignableFrom(clazz)) {
1✔
318
          Class<?> enumClass = clazz.isAnonymousClass() ? clazz.getSuperclass() : clazz;
1!
319
          TypeHandler<?> enumHandler = getInstance(enumClass, defaultEnumTypeHandler);
1✔
320
          register(new Type[] { enumClass }, new JdbcType[] { jdbcType }, enumHandler);
1✔
321
          return enumHandler;
1✔
322
        }
323
      }
324
      return null;
1✔
325
    }
326

327
    try {
328
      TypeHandler<?> typeHandler = (TypeHandler<?>) candidate.newInstance(type);
1✔
329
      register(type, jdbcType, typeHandler);
1✔
330
      return typeHandler;
1✔
NEW
331
    } catch (ReflectiveOperationException e) {
×
NEW
332
      throw new TypeException("Failed to invoke constructor " + candidate.toString(), e);
×
333
    }
334
  }
335

336
  private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMap(Type type) {
337
    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = typeHandlerMap.get(type);
1✔
338
    if (jdbcHandlerMap != null) {
1✔
339
      return NULL_TYPE_HANDLER_MAP.equals(jdbcHandlerMap) ? null : jdbcHandlerMap;
1✔
340
    }
341
    if (type instanceof Class) {
1✔
342
      Class<?> clazz = (Class<?>) type;
1✔
343
      if (!Enum.class.isAssignableFrom(clazz)) {
1✔
344
        jdbcHandlerMap = getJdbcHandlerMapForSuperclass(clazz);
1✔
345
      }
346
    }
347
    typeHandlerMap.put(type, jdbcHandlerMap == null ? NULL_TYPE_HANDLER_MAP : jdbcHandlerMap);
1✔
348
    return jdbcHandlerMap;
1✔
349
  }
350

351
  private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMapForSuperclass(Class<?> clazz) {
352
    Class<?> superclass = clazz.getSuperclass();
1✔
353
    if (superclass == null || Object.class.equals(superclass)) {
1✔
354
      return null;
1✔
355
    }
356
    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = typeHandlerMap.get(superclass);
1✔
357
    if (jdbcHandlerMap != null) {
1✔
358
      return jdbcHandlerMap;
1✔
359
    }
360
    return getJdbcHandlerMapForSuperclass(superclass);
1✔
361
  }
362

363
  private TypeHandler<?> pickSoleHandler(Map<JdbcType, TypeHandler<?>> jdbcHandlerMap) {
364
    TypeHandler<?> soleHandler = null;
1✔
365
    for (TypeHandler<?> handler : jdbcHandlerMap.values()) {
1✔
366
      if (soleHandler == null) {
1!
367
        soleHandler = handler;
1✔
UNCOV
368
      } else if (!handler.getClass().equals(soleHandler.getClass())) {
×
369
        // More than one type handlers registered.
UNCOV
370
        return null;
×
371
      }
372
    }
1✔
373
    return soleHandler;
1✔
374
  }
375

376
  public void register(JdbcType mappedJdbcType, TypeHandler<?> handler) {
377
    jdbcTypeHandlerMap.put(mappedJdbcType, handler);
1✔
378
  }
1✔
379

380
  //
381
  // REGISTER INSTANCE
382
  //
383

384
  // Only handler
385

386
  public <T> void register(TypeHandler<T> handler) {
387
    register(mappedJavaTypes(handler.getClass()), mappedJdbcTypes(handler.getClass()), handler);
1✔
388
  }
1✔
389

390
  // java type + handler
391

392
  public void register(Class<?> mappedJavaType, TypeHandler<?> handler) {
393
    register((Type) mappedJavaType, handler);
1✔
394
  }
1✔
395

396
  private void register(Type mappedJavaType, TypeHandler<?> handler) {
397
    register(new Type[] { mappedJavaType }, mappedJdbcTypes(handler.getClass()), handler);
1✔
398
  }
1✔
399

400
  @Deprecated
401
  public <T> void register(TypeReference<T> javaTypeReference, TypeHandler<? extends T> handler) {
402
    register(javaTypeReference.getRawType(), handler);
1✔
403
  }
1✔
404

405
  // java type + jdbc type + handler
406

407
  public void register(Type mappedJavaType, JdbcType mappedJdbcType, TypeHandler<?> handler) {
408
    register(new Type[] { mappedJavaType }, new JdbcType[] { mappedJdbcType }, handler);
1✔
409
  }
1✔
410

411
  private void register(Type[] mappedJavaTypes, JdbcType[] mappedJdbcTypes, TypeHandler<?> handler) {
412
    for (Type javaType : mappedJavaTypes) {
1✔
413
      if (javaType == null) {
1!
NEW
414
        continue;
×
415
      }
416

417
      typeHandlerMap.compute(javaType, (k, v) -> {
1✔
418
        Map<JdbcType, TypeHandler<?>> map = (v == null || v == NULL_TYPE_HANDLER_MAP ? new HashMap<>() : v);
1✔
419
        for (JdbcType jdbcType : mappedJdbcTypes) {
1✔
420
          map.put(jdbcType, handler);
1✔
421
        }
422
        return map;
1✔
423
      });
424

425
      if (javaType instanceof ParameterizedType) {
1✔
426
        // MEMO: add annotation to skip this?
427
        Type rawType = ((ParameterizedType) javaType).getRawType();
1✔
428
        typeHandlerMap.compute(rawType, (k, v) -> {
1✔
429
          Map<JdbcType, TypeHandler<?>> map = (v == null || v == NULL_TYPE_HANDLER_MAP ? new HashMap<>() : v);
1!
430
          for (JdbcType jdbcType : mappedJdbcTypes) {
1✔
431
            map.merge(jdbcType, handler, (handler1, handler2) -> handler1.equals(handler2) ? handler1
1!
432
                : new ConflictedTypeHandler((Class<?>) rawType, jdbcType, handler1, handler2));
1✔
433
          }
434
          return map;
1✔
435
        });
436
      }
437
    }
438

439
    allTypeHandlersMap.put(handler.getClass(), handler);
1✔
440
  }
1✔
441

442
  //
443
  // REGISTER CLASS
444
  //
445

446
  // Only handler type
447

448
  public void register(Class<?> handlerClass) {
449
    register(mappedJavaTypes(handlerClass), mappedJdbcTypes(handlerClass), handlerClass);
1✔
450
  }
1✔
451

452
  // java type + handler type
453

454
  @Deprecated
455
  public void register(String javaTypeClassName, String typeHandlerClassName) throws ClassNotFoundException {
456
    register(Resources.classForName(javaTypeClassName), Resources.classForName(typeHandlerClassName));
×
457
  }
×
458

459
  public void register(Type mappedJavaType, Class<?> handlerClass) {
460
    register(new Type[] { mappedJavaType }, mappedJdbcTypes(handlerClass), handlerClass);
1✔
461
  }
1✔
462

463
  // java type + jdbc type + handler type
464

465
  public void register(Type mappedJavaType, JdbcType mappedJdbcType, Class<?> handlerClass) {
466
    register(new Type[] { mappedJavaType }, new JdbcType[] { mappedJdbcType }, handlerClass);
1✔
467
  }
1✔
468

469
  private void register(Type[] mappedJavaTypes, JdbcType[] mappedJdbcTypes, Class<?> handlerClass) {
470
    if (!TypeHandler.class.isAssignableFrom(handlerClass)) {
1!
NEW
471
      throw new IllegalArgumentException(String.format("'%s' does not implement TypeHandler.", handlerClass.getName()));
×
472
    }
473
    for (Constructor<?> constructor : handlerClass.getConstructors()) {
1✔
474
      if (constructor.getParameterCount() != 1) {
1✔
475
        continue;
1✔
476
      }
477
      Class<?> argType = constructor.getParameterTypes()[0];
1✔
478
      if (Type.class.equals(argType) || Class.class.equals(argType)) {
1!
479
        for (Type javaType : mappedJavaTypes) {
1✔
480
          smartHandlers.computeIfAbsent(javaType, k -> constructor);
1✔
481
        }
482
        return;
1✔
483
      }
484
    }
485
    // It is not a smart handler
486
    register(mappedJavaTypes, mappedJdbcTypes, getInstance(null, handlerClass));
1✔
487
  }
1✔
488

489
  private Type[] mappedJavaTypes(Class<?> clazz) {
490
    MappedTypes mappedTypesAnno = clazz.getAnnotation(MappedTypes.class);
1✔
491
    if (mappedTypesAnno != null) {
1✔
492
      return mappedTypesAnno.value();
1✔
493
    }
494
    return TypeParameterResolver.resolveClassTypeParams(TypeHandler.class, clazz);
1✔
495
  }
496

497
  private JdbcType[] mappedJdbcTypes(Class<?> clazz) {
498
    MappedJdbcTypes mappedJdbcTypesAnno = clazz.getAnnotation(MappedJdbcTypes.class);
1✔
499
    if (mappedJdbcTypesAnno != null) {
1✔
500
      JdbcType[] jdbcTypes = mappedJdbcTypesAnno.value();
1✔
501
      if (mappedJdbcTypesAnno.includeNullJdbcType()) {
1✔
502
        int newLength = jdbcTypes.length + 1;
1✔
503
        jdbcTypes = Arrays.copyOf(jdbcTypes, newLength);
1✔
504
        jdbcTypes[newLength - 1] = null;
1✔
505
      }
506
      return jdbcTypes;
1✔
507
    }
508
    return new JdbcType[] { null };
1✔
509
  }
510

511
  // Construct a handler (used also from Builders)
512

513
  @SuppressWarnings("unchecked")
514
  public <T> TypeHandler<T> getInstance(Type javaType, Class<?> handlerClass) {
515
    Constructor<?> c;
516
    try {
517
      if (javaType != null) {
1✔
518
        try {
519
          c = handlerClass.getConstructor(Type.class);
1✔
520
          return (TypeHandler<T>) c.newInstance(javaType);
1✔
521
        } catch (NoSuchMethodException ignored) {
1✔
522
        }
523
        if (javaType instanceof Class) {
1!
524
          try {
525
            c = handlerClass.getConstructor(Class.class);
1✔
526
            return (TypeHandler<T>) c.newInstance(javaType);
1✔
527
          } catch (NoSuchMethodException ignored) {
1✔
528
          }
529
        }
530
      }
531
      try {
532
        c = handlerClass.getConstructor();
1✔
533
        return (TypeHandler<T>) c.newInstance();
1✔
NEW
534
      } catch (NoSuchMethodException e) {
×
NEW
535
        throw new TypeException("Unable to find a usable constructor for " + handlerClass, e);
×
536
      }
NEW
537
    } catch (ReflectiveOperationException e) {
×
NEW
538
      throw new TypeException("Failed to invoke constructor for handler " + handlerClass, e);
×
539
    }
540
  }
541

542
  // scan
543

544
  public void register(String packageName) {
545
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
1✔
546
    resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
1✔
547
    Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
1✔
548
    for (Class<?> type : handlerSet) {
1✔
549
      // Ignore inner classes and interfaces (including package-info.java) and abstract classes
550
      if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
1!
551
        register(type);
1✔
552
      }
553
    }
1✔
554
  }
1✔
555

556
  // get information
557

558
  /**
559
   * Gets the type handlers. Used by mybatis-guice.
560
   *
561
   * @return the type handlers
562
   *
563
   * @since 3.2.2
564
   */
565
  public Collection<TypeHandler<?>> getTypeHandlers() {
566
    return Collections.unmodifiableCollection(allTypeHandlersMap.values());
×
567
  }
568

569
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc