0
# Type Handling
1
2
Comprehensive type conversion system between Java types and JDBC types. MyBatis includes extensive built-in type handlers and supports custom type handlers for specialized conversions.
3
4
## Capabilities
5
6
### TypeHandler Interface
7
8
Core interface for handling conversions between Java types and JDBC types.
9
10
```java { .api }
11
/**
12
* Handles conversion between Java types and JDBC types
13
*/
14
interface TypeHandler<T> {
15
/** Set parameter value in PreparedStatement */
16
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
17
18
/** Get result by column name */
19
T getResult(ResultSet rs, String columnName) throws SQLException;
20
21
/** Get result by column index */
22
T getResult(ResultSet rs, int columnIndex) throws SQLException;
23
24
/** Get result from CallableStatement */
25
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
26
}
27
```
28
29
### BaseTypeHandler
30
31
Abstract base class that simplifies creating custom type handlers by handling null values automatically.
32
33
```java { .api }
34
/**
35
* Base implementation for type handlers with automatic null handling
36
*/
37
abstract class BaseTypeHandler<T> implements TypeHandler<T> {
38
/** Set non-null parameter value */
39
public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
40
41
/** Get nullable result by column name */
42
public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;
43
44
/** Get nullable result by column index */
45
public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;
46
47
/** Get nullable result from CallableStatement */
48
public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;
49
}
50
```
51
52
**Usage Examples:**
53
54
```java
55
// Custom type handler for converting between String and custom enum
56
public class StatusTypeHandler extends BaseTypeHandler<UserStatus> {
57
@Override
58
public void setNonNullParameter(PreparedStatement ps, int i, UserStatus parameter, JdbcType jdbcType) throws SQLException {
59
ps.setString(i, parameter.getCode());
60
}
61
62
@Override
63
public UserStatus getNullableResult(ResultSet rs, String columnName) throws SQLException {
64
String code = rs.getString(columnName);
65
return code == null ? null : UserStatus.fromCode(code);
66
}
67
68
@Override
69
public UserStatus getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
70
String code = rs.getString(columnIndex);
71
return code == null ? null : UserStatus.fromCode(code);
72
}
73
74
@Override
75
public UserStatus getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
76
String code = cs.getString(columnIndex);
77
return code == null ? null : UserStatus.fromCode(code);
78
}
79
}
80
81
// Register custom type handler
82
@MappedTypes(UserStatus.class)
83
@MappedJdbcTypes(JdbcType.VARCHAR)
84
public class StatusTypeHandler extends BaseTypeHandler<UserStatus> {
85
// implementation...
86
}
87
```
88
89
### TypeHandlerRegistry
90
91
Registry for managing type handlers and their associations with Java and JDBC types.
92
93
```java { .api }
94
/**
95
* Registry for type handlers
96
*/
97
class TypeHandlerRegistry {
98
/** Register type handler for Java type */
99
public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler);
100
101
/** Register type handler for JDBC type */
102
public void register(JdbcType jdbcType, TypeHandler<?> handler);
103
104
/** Register type handler for Java type and JDBC type combination */
105
public <T> void register(Class<T> javaType, JdbcType jdbcType, TypeHandler<? extends T> typeHandler);
106
107
/** Register type handler by scanning annotations */
108
public void register(Class<?> typeHandlerClass);
109
110
/** Register type handler instance */
111
public <T> void register(TypeHandler<T> typeHandler);
112
113
/** Get type handler for Java type */
114
public <T> TypeHandler<T> getTypeHandler(Class<T> type);
115
116
/** Get type handler for Java type and JDBC type */
117
public <T> TypeHandler<T> getTypeHandler(Class<T> type, JdbcType jdbcType);
118
119
/** Get type handler for JDBC type */
120
public TypeHandler<?> getTypeHandler(JdbcType jdbcType);
121
122
/** Get unknown type handler */
123
public TypeHandler<Object> getUnknownTypeHandler();
124
}
125
```
126
127
### Built-in Type Handlers
128
129
MyBatis includes comprehensive built-in type handlers for standard Java types.
130
131
#### String Type Handlers
132
133
```java { .api }
134
// String ↔ VARCHAR
135
class StringTypeHandler extends BaseTypeHandler<String>;
136
137
// String ↔ CLOB
138
class ClobTypeHandler extends BaseTypeHandler<String>;
139
140
// String ↔ NCLOB
141
class NClobTypeHandler extends BaseTypeHandler<String>;
142
```
143
144
#### Numeric Type Handlers
145
146
```java { .api }
147
// Boolean ↔ BOOLEAN
148
class BooleanTypeHandler extends BaseTypeHandler<Boolean>;
149
150
// Byte ↔ TINYINT
151
class ByteTypeHandler extends BaseTypeHandler<Byte>;
152
153
// Short ↔ SMALLINT
154
class ShortTypeHandler extends BaseTypeHandler<Short>;
155
156
// Integer ↔ INTEGER
157
class IntegerTypeHandler extends BaseTypeHandler<Integer>;
158
159
// Long ↔ BIGINT
160
class LongTypeHandler extends BaseTypeHandler<Long>;
161
162
// Float ↔ FLOAT
163
class FloatTypeHandler extends BaseTypeHandler<Float>;
164
165
// Double ↔ DOUBLE
166
class DoubleTypeHandler extends BaseTypeHandler<Double>;
167
168
// BigDecimal ↔ DECIMAL
169
class BigDecimalTypeHandler extends BaseTypeHandler<BigDecimal>;
170
171
// BigInteger ↔ BIGINT
172
class BigIntegerTypeHandler extends BaseTypeHandler<BigInteger>;
173
```
174
175
#### Date/Time Type Handlers
176
177
```java { .api }
178
// java.util.Date ↔ DATE
179
class DateTypeHandler extends BaseTypeHandler<Date>;
180
181
// java.util.Date ↔ TIME
182
class TimeTypeHandler extends BaseTypeHandler<Date>;
183
184
// java.util.Date ↔ TIMESTAMP
185
class TimestampTypeHandler extends BaseTypeHandler<Date>;
186
187
// java.sql.Date ↔ DATE
188
class SqlDateTypeHandler extends BaseTypeHandler<java.sql.Date>;
189
190
// java.sql.Time ↔ TIME
191
class SqlTimeTypeHandler extends BaseTypeHandler<java.sql.Time>;
192
193
// java.sql.Timestamp ↔ TIMESTAMP
194
class SqlTimestampTypeHandler extends BaseTypeHandler<java.sql.Timestamp>;
195
```
196
197
#### Java 8 Time API Handlers
198
199
```java { .api }
200
// LocalDate ↔ DATE
201
class LocalDateTypeHandler extends BaseTypeHandler<LocalDate>;
202
203
// LocalTime ↔ TIME
204
class LocalTimeTypeHandler extends BaseTypeHandler<LocalTime>;
205
206
// LocalDateTime ↔ TIMESTAMP
207
class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime>;
208
209
// OffsetDateTime ↔ TIMESTAMP
210
class OffsetDateTimeTypeHandler extends BaseTypeHandler<OffsetDateTime>;
211
212
// ZonedDateTime ↔ TIMESTAMP
213
class ZonedDateTimeTypeHandler extends BaseTypeHandler<ZonedDateTime>;
214
215
// Instant ↔ TIMESTAMP
216
class InstantTypeHandler extends BaseTypeHandler<Instant>;
217
218
// Month ↔ INTEGER
219
class MonthTypeHandler extends BaseTypeHandler<Month>;
220
221
// Year ↔ INTEGER
222
class YearTypeHandler extends BaseTypeHandler<Year>;
223
224
// YearMonth ↔ VARCHAR
225
class YearMonthTypeHandler extends BaseTypeHandler<YearMonth>;
226
```
227
228
#### Binary Type Handlers
229
230
```java { .api }
231
// byte[] ↔ BLOB
232
class ByteArrayTypeHandler extends BaseTypeHandler<byte[]>;
233
234
// Blob ↔ BLOB
235
class BlobTypeHandler extends BaseTypeHandler<Blob>;
236
237
// InputStream ↔ BLOB
238
class BlobInputStreamTypeHandler extends BaseTypeHandler<InputStream>;
239
```
240
241
#### Enum Type Handlers
242
243
```java { .api }
244
// Enum ↔ VARCHAR (using enum name)
245
class EnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E>;
246
247
// Enum ↔ INTEGER (using enum ordinal)
248
class EnumOrdinalTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E>;
249
```
250
251
**Usage Examples:**
252
253
```java
254
// Enum type handlers in mapper configuration
255
public interface UserMapper {
256
@Select("SELECT * FROM users WHERE status = #{status}")
257
@Results({
258
@Result(property = "status", column = "status",
259
javaType = UserStatus.class,
260
typeHandler = EnumTypeHandler.class)
261
})
262
List<User> findByStatus(@Param("status") UserStatus status);
263
}
264
265
// Using custom type handler
266
public interface OrderMapper {
267
@Select("SELECT * FROM orders WHERE id = #{id}")
268
@Results({
269
@Result(property = "amount", column = "amount_cents",
270
javaType = BigDecimal.class,
271
typeHandler = CentsToDecimalTypeHandler.class)
272
})
273
Order findById(@Param("id") Long id);
274
}
275
```
276
277
### Type Handler Configuration Annotations
278
279
#### @MappedTypes
280
281
Specifies which Java types a type handler can process.
282
283
```java { .api }
284
/**
285
* Specifies Java types handled by this type handler
286
*/
287
@interface MappedTypes {
288
/** Java types this handler supports */
289
Class<?>[] value();
290
}
291
```
292
293
#### @MappedJdbcTypes
294
295
Specifies which JDBC types a type handler can process.
296
297
```java { .api }
298
/**
299
* Specifies JDBC types handled by this type handler
300
*/
301
@interface MappedJdbcTypes {
302
/** JDBC types this handler supports */
303
JdbcType[] value();
304
305
/** Whether to include null handling */
306
boolean includeNullJdbcType() default false;
307
}
308
```
309
310
**Usage Examples:**
311
312
```java
313
@MappedTypes(UserStatus.class)
314
@MappedJdbcTypes(JdbcType.VARCHAR)
315
public class UserStatusTypeHandler extends BaseTypeHandler<UserStatus> {
316
// Custom enum type handler implementation
317
318
@Override
319
public void setNonNullParameter(PreparedStatement ps, int i, UserStatus parameter, JdbcType jdbcType) throws SQLException {
320
ps.setString(i, parameter.name());
321
}
322
323
@Override
324
public UserStatus getNullableResult(ResultSet rs, String columnName) throws SQLException {
325
String value = rs.getString(columnName);
326
return value == null ? null : UserStatus.valueOf(value);
327
}
328
329
// ... other methods
330
}
331
332
// Multiple type mapping
333
@MappedTypes({Address.class, ContactInfo.class})
334
@MappedJdbcTypes({JdbcType.VARCHAR, JdbcType.CLOB})
335
public class JsonTypeHandler extends BaseTypeHandler<Object> {
336
// JSON serialization type handler
337
}
338
```
339
340
### JdbcType Enumeration
341
342
Comprehensive enumeration of JDBC types for type handler mapping.
343
344
```java { .api }
345
/**
346
* JDBC type constants for type handler mapping
347
*/
348
enum JdbcType {
349
// Numeric types
350
TINYINT, SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC,
351
352
// Character types
353
CHAR, VARCHAR, LONGVARCHAR, NCHAR, NVARCHAR, LONGNVARCHAR,
354
355
// Binary types
356
BINARY, VARBINARY, LONGVARBINARY, BLOB,
357
358
// Date/time types
359
DATE, TIME, TIMESTAMP, TIME_WITH_TIMEZONE, TIMESTAMP_WITH_TIMEZONE,
360
361
// Other types
362
BOOLEAN, BIT, NULL, OTHER, UNDEFINED, CURSOR, ARRAY, STRUCT, REF,
363
CLOB, NCLOB, SQLXML, DATETIMEOFFSET;
364
}
365
```
366
367
### Custom Type Handler Examples
368
369
#### JSON Type Handler
370
371
```java
372
@MappedTypes(Object.class)
373
@MappedJdbcTypes(JdbcType.VARCHAR)
374
public class JsonTypeHandler extends BaseTypeHandler<Object> {
375
private static final ObjectMapper objectMapper = new ObjectMapper();
376
377
@Override
378
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
379
try {
380
ps.setString(i, objectMapper.writeValueAsString(parameter));
381
} catch (JsonProcessingException e) {
382
throw new SQLException("Error converting object to JSON", e);
383
}
384
}
385
386
@Override
387
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
388
String json = rs.getString(columnName);
389
return parseJson(json);
390
}
391
392
private Object parseJson(String json) throws SQLException {
393
if (json == null || json.trim().isEmpty()) {
394
return null;
395
}
396
try {
397
return objectMapper.readValue(json, Object.class);
398
} catch (JsonProcessingException e) {
399
throw new SQLException("Error parsing JSON", e);
400
}
401
}
402
403
// ... other methods
404
}
405
```
406
407
#### Encrypted String Type Handler
408
409
```java
410
@MappedTypes(String.class)
411
@MappedJdbcTypes(JdbcType.VARCHAR)
412
public class EncryptedStringTypeHandler extends BaseTypeHandler<String> {
413
private final EncryptionService encryptionService;
414
415
public EncryptedStringTypeHandler() {
416
this.encryptionService = new EncryptionService();
417
}
418
419
@Override
420
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
421
String encrypted = encryptionService.encrypt(parameter);
422
ps.setString(i, encrypted);
423
}
424
425
@Override
426
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
427
String encrypted = rs.getString(columnName);
428
return encrypted == null ? null : encryptionService.decrypt(encrypted);
429
}
430
431
// ... other methods
432
}
433
```
434
435
## Types
436
437
```java { .api }
438
/**
439
* Type alias registry for mapping short names to full class names
440
*/
441
class TypeAliasRegistry {
442
/** Register type alias */
443
public void registerAlias(String alias, Class<?> value);
444
445
/** Register type alias with class name */
446
public void registerAlias(String alias, String value);
447
448
/** Register aliases for a package */
449
public void registerAliases(String packageName);
450
451
/** Resolve type alias to class */
452
public <T> Class<T> resolveAlias(String string);
453
}
454
455
/**
456
* Exception thrown during type handling operations
457
*/
458
class TypeException extends PersistenceException {
459
public TypeException(String message);
460
public TypeException(String message, Throwable cause);
461
}
462
```