typeHandlers
Whenever MyBatis sets a parameter on a PreparedStatement or retrieves a value from a ResultSet, a TypeHandler is used to retrieve the value in a means appropriate to the Java type. The following table describes the default TypeHandlers.
NOTE Since version 3.4.5, MyBatis supports JSR-310 (Date and Time API) by default.
Type Handler | Java Types | JDBC Types |
---|---|---|
BooleanTypeHandler | java.lang.Boolean , boolean | Any compatible BOOLEAN |
ByteTypeHandler | java.lang.Byte , byte | Any compatible NUMERIC or BYTE |
ShortTypeHandler | java.lang.Short , short | Any compatible NUMERIC or SMALLINT |
IntegerTypeHandler | java.lang.Integer , int | Any compatible NUMERIC or INTEGER |
LongTypeHandler | java.lang.Long , long | Any compatible NUMERIC or BIGINT |
FloatTypeHandler | java.lang.Float , float | Any compatible NUMERIC or FLOAT |
DoubleTypeHandler | java.lang.Double , double | Any compatible NUMERIC or DOUBLE |
BigDecimalTypeHandler | java.math.BigDecimal | Any compatible NUMERIC or DECIMAL |
StringTypeHandler | java.lang.String | CHAR , VARCHAR |
ClobReaderTypeHandler | java.io.Reader | - |
ClobTypeHandler | java.lang.String | CLOB , LONGVARCHAR |
NStringTypeHandler | java.lang.String | NVARCHAR , NCHAR |
NClobTypeHandler | java.lang.String | NCLOB |
BlobInputStreamTypeHandler | java.io.InputStream | - |
ByteArrayTypeHandler | byte[] | Any compatible byte stream type |
BlobTypeHandler | byte[] | BLOB , LONGVARBINARY |
DateTypeHandler | java.util.Date | TIMESTAMP |
DateOnlyTypeHandler | java.util.Date | DATE |
TimeOnlyTypeHandler | java.util.Date | TIME |
SqlTimestampTypeHandler | java.sql.Timestamp | TIMESTAMP |
SqlDateTypeHandler | java.sql.Date | DATE |
SqlTimeTypeHandler | java.sql.Time | TIME |
ObjectTypeHandler | Any | OTHER , or unspecified |
EnumTypeHandler | Enumeration Type | VARCHAR any string compatible type, as the code is stored (not index). |
EnumOrdinalTypeHandler | Enumeration Type | Any compatible NUMERIC or DOUBLE , as the position is stored (not the code itself). |
SqlxmlTypeHandler | java.lang.String | SQLXML |
InstantTypeHandler | java.time.Instant | TIMESTAMP |
LocalDateTimeTypeHandler | java.time.LocalDateTime | TIMESTAMP |
LocalDateTypeHandler | java.time.LocalDate | DATE |
LocalTimeTypeHandler | java.time.LocalTime | TIME |
OffsetDateTimeTypeHandler | java.time.OffsetDateTime | TIMESTAMP |
OffsetTimeTypeHandler | java.time.OffsetTime | TIME |
ZonedDateTimeTypeHandler | java.time.ZonedDateTime | TIMESTAMP |
YearTypeHandler | java.time.Year | INTEGER |
MonthTypeHandler | java.time.Month | INTEGER |
YearMonthTypeHandler | java.time.YearMonth | VARCHAR or LONGVARCHAR |
JapaneseDateTypeHandler | java.time.chrono.JapaneseDate | DATE |
You can override the type handlers or create your own to deal with unsupported or non-standard types. To do so, implement the interface org.apache.ibatis.type.TypeHandler
or extend the convenience class org.apache.ibatis.type.BaseTypeHandler
and optionally map it to a JDBC type. For example:
// ExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName)
throws SQLException {
return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
return cs.getString(columnIndex);
}
}
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>
Using such a TypeHandler would override the existing type handler for Java String properties and VARCHAR parameters and results. Note that MyBatis does not introspect upon the database metadata to determine the type, so you must specify that it’s a VARCHAR field in the parameter and result mappings to hook in the correct type handler. This is due to the fact that MyBatis is unaware of the data type until the statement is executed.
MyBatis will know the Java type that you want to handle with this TypeHandler by introspecting its generic type, but you can override this behavior by two means:
- Adding a
javaType
attribute to the typeHandler element (for example:javaType="String"
) - Adding a
@MappedTypes
annotation to your TypeHandler class specifying the list of java types to associate it with. This annotation will be ignored if thejavaType
attribute as also been specified.
The associated JDBC type can be specified by two means:
- Adding a
jdbcType
attribute to the typeHandler element (for example:jdbcType="VARCHAR"
). - Adding a
@MappedJdbcTypes
annotation to your TypeHandler class specifying the list of JDBC types to associate it with. This annotation will be ignored if thejdbcType
attribute as also been specified.
When deciding which TypeHandler to use in a ResultMap
, the Java type is known (from the result type), but the JDBC type is unknown. MyBatis therefore uses the combination javaType=[TheJavaType], jdbcType=null
to choose a TypeHandler. This means that using a @MappedJdbcTypes
annotation restricts the scope of a TypeHandler and makes it unavailable for use in ResultMap
s unless explicity set. To make a TypeHandler available for use in a ResultMap
, set includeNullJdbcType=true
on the @MappedJdbcTypes
annotation. Since Mybatis 3.4.0 however, if a single TypeHandler is registered to handle a Java type, it will be used by default in ResultMap
s using this Java type (i.e. even without includeNullJdbcType=true
).
And finally you can let MyBatis search for your TypeHandlers:
<!-- mybatis-config.xml -->
<typeHandlers>
<package name="org.mybatis.example"/>
</typeHandlers>
Note that when using the autodiscovery feature JDBC types can only be specified with annotations.
You can create a generic TypeHandler that is able to handle more than one class. For that purpose add a constructor that receives the class as a parameter and MyBatis will pass the actual class when constructing the TypeHandler.
//GenericTypeHandler.java
public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> {
private Class<E> type;
public GenericTypeHandler(Class<E> type) {
if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
this.type = type;
}
...
EnumTypeHandler
and EnumOrdinalTypeHandler
are generic TypeHandlers. We will learn about them in the following section.