SQL mapping framework that eliminates JDBC boilerplate and couples objects with stored procedures or SQL statements using XML descriptors or annotations.
—
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.
Core interface for handling conversions between Java types and JDBC types.
/**
* Handles conversion between Java types and JDBC types
*/
interface TypeHandler<T> {
/** Set parameter value in PreparedStatement */
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
/** Get result by column name */
T getResult(ResultSet rs, String columnName) throws SQLException;
/** Get result by column index */
T getResult(ResultSet rs, int columnIndex) throws SQLException;
/** Get result from CallableStatement */
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}Abstract base class that simplifies creating custom type handlers by handling null values automatically.
/**
* Base implementation for type handlers with automatic null handling
*/
abstract class BaseTypeHandler<T> implements TypeHandler<T> {
/** Set non-null parameter value */
public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
/** Get nullable result by column name */
public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;
/** Get nullable result by column index */
public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;
/** Get nullable result from CallableStatement */
public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;
}Usage Examples:
// Custom type handler for converting between String and custom enum
public class StatusTypeHandler extends BaseTypeHandler<UserStatus> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, UserStatus parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.getCode());
}
@Override
public UserStatus getNullableResult(ResultSet rs, String columnName) throws SQLException {
String code = rs.getString(columnName);
return code == null ? null : UserStatus.fromCode(code);
}
@Override
public UserStatus getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String code = rs.getString(columnIndex);
return code == null ? null : UserStatus.fromCode(code);
}
@Override
public UserStatus getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String code = cs.getString(columnIndex);
return code == null ? null : UserStatus.fromCode(code);
}
}
// Register custom type handler
@MappedTypes(UserStatus.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class StatusTypeHandler extends BaseTypeHandler<UserStatus> {
// implementation...
}Registry for managing type handlers and their associations with Java and JDBC types.
/**
* Registry for type handlers
*/
class TypeHandlerRegistry {
/** Register type handler for Java type */
public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler);
/** Register type handler for JDBC type */
public void register(JdbcType jdbcType, TypeHandler<?> handler);
/** Register type handler for Java type and JDBC type combination */
public <T> void register(Class<T> javaType, JdbcType jdbcType, TypeHandler<? extends T> typeHandler);
/** Register type handler by scanning annotations */
public void register(Class<?> typeHandlerClass);
/** Register type handler instance */
public <T> void register(TypeHandler<T> typeHandler);
/** Get type handler for Java type */
public <T> TypeHandler<T> getTypeHandler(Class<T> type);
/** Get type handler for Java type and JDBC type */
public <T> TypeHandler<T> getTypeHandler(Class<T> type, JdbcType jdbcType);
/** Get type handler for JDBC type */
public TypeHandler<?> getTypeHandler(JdbcType jdbcType);
/** Get unknown type handler */
public TypeHandler<Object> getUnknownTypeHandler();
}MyBatis includes comprehensive built-in type handlers for standard Java types.
// String ↔ VARCHAR
class StringTypeHandler extends BaseTypeHandler<String>;
// String ↔ CLOB
class ClobTypeHandler extends BaseTypeHandler<String>;
// String ↔ NCLOB
class NClobTypeHandler extends BaseTypeHandler<String>;// Boolean ↔ BOOLEAN
class BooleanTypeHandler extends BaseTypeHandler<Boolean>;
// Byte ↔ TINYINT
class ByteTypeHandler extends BaseTypeHandler<Byte>;
// Short ↔ SMALLINT
class ShortTypeHandler extends BaseTypeHandler<Short>;
// Integer ↔ INTEGER
class IntegerTypeHandler extends BaseTypeHandler<Integer>;
// Long ↔ BIGINT
class LongTypeHandler extends BaseTypeHandler<Long>;
// Float ↔ FLOAT
class FloatTypeHandler extends BaseTypeHandler<Float>;
// Double ↔ DOUBLE
class DoubleTypeHandler extends BaseTypeHandler<Double>;
// BigDecimal ↔ DECIMAL
class BigDecimalTypeHandler extends BaseTypeHandler<BigDecimal>;
// BigInteger ↔ BIGINT
class BigIntegerTypeHandler extends BaseTypeHandler<BigInteger>;// java.util.Date ↔ DATE
class DateTypeHandler extends BaseTypeHandler<Date>;
// java.util.Date ↔ TIME
class TimeTypeHandler extends BaseTypeHandler<Date>;
// java.util.Date ↔ TIMESTAMP
class TimestampTypeHandler extends BaseTypeHandler<Date>;
// java.sql.Date ↔ DATE
class SqlDateTypeHandler extends BaseTypeHandler<java.sql.Date>;
// java.sql.Time ↔ TIME
class SqlTimeTypeHandler extends BaseTypeHandler<java.sql.Time>;
// java.sql.Timestamp ↔ TIMESTAMP
class SqlTimestampTypeHandler extends BaseTypeHandler<java.sql.Timestamp>;// LocalDate ↔ DATE
class LocalDateTypeHandler extends BaseTypeHandler<LocalDate>;
// LocalTime ↔ TIME
class LocalTimeTypeHandler extends BaseTypeHandler<LocalTime>;
// LocalDateTime ↔ TIMESTAMP
class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime>;
// OffsetDateTime ↔ TIMESTAMP
class OffsetDateTimeTypeHandler extends BaseTypeHandler<OffsetDateTime>;
// ZonedDateTime ↔ TIMESTAMP
class ZonedDateTimeTypeHandler extends BaseTypeHandler<ZonedDateTime>;
// Instant ↔ TIMESTAMP
class InstantTypeHandler extends BaseTypeHandler<Instant>;
// Month ↔ INTEGER
class MonthTypeHandler extends BaseTypeHandler<Month>;
// Year ↔ INTEGER
class YearTypeHandler extends BaseTypeHandler<Year>;
// YearMonth ↔ VARCHAR
class YearMonthTypeHandler extends BaseTypeHandler<YearMonth>;// byte[] ↔ BLOB
class ByteArrayTypeHandler extends BaseTypeHandler<byte[]>;
// Blob ↔ BLOB
class BlobTypeHandler extends BaseTypeHandler<Blob>;
// InputStream ↔ BLOB
class BlobInputStreamTypeHandler extends BaseTypeHandler<InputStream>;// Enum ↔ VARCHAR (using enum name)
class EnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E>;
// Enum ↔ INTEGER (using enum ordinal)
class EnumOrdinalTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E>;Usage Examples:
// Enum type handlers in mapper configuration
public interface UserMapper {
@Select("SELECT * FROM users WHERE status = #{status}")
@Results({
@Result(property = "status", column = "status",
javaType = UserStatus.class,
typeHandler = EnumTypeHandler.class)
})
List<User> findByStatus(@Param("status") UserStatus status);
}
// Using custom type handler
public interface OrderMapper {
@Select("SELECT * FROM orders WHERE id = #{id}")
@Results({
@Result(property = "amount", column = "amount_cents",
javaType = BigDecimal.class,
typeHandler = CentsToDecimalTypeHandler.class)
})
Order findById(@Param("id") Long id);
}Specifies which Java types a type handler can process.
/**
* Specifies Java types handled by this type handler
*/
@interface MappedTypes {
/** Java types this handler supports */
Class<?>[] value();
}Specifies which JDBC types a type handler can process.
/**
* Specifies JDBC types handled by this type handler
*/
@interface MappedJdbcTypes {
/** JDBC types this handler supports */
JdbcType[] value();
/** Whether to include null handling */
boolean includeNullJdbcType() default false;
}Usage Examples:
@MappedTypes(UserStatus.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class UserStatusTypeHandler extends BaseTypeHandler<UserStatus> {
// Custom enum type handler implementation
@Override
public void setNonNullParameter(PreparedStatement ps, int i, UserStatus parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.name());
}
@Override
public UserStatus getNullableResult(ResultSet rs, String columnName) throws SQLException {
String value = rs.getString(columnName);
return value == null ? null : UserStatus.valueOf(value);
}
// ... other methods
}
// Multiple type mapping
@MappedTypes({Address.class, ContactInfo.class})
@MappedJdbcTypes({JdbcType.VARCHAR, JdbcType.CLOB})
public class JsonTypeHandler extends BaseTypeHandler<Object> {
// JSON serialization type handler
}Comprehensive enumeration of JDBC types for type handler mapping.
/**
* JDBC type constants for type handler mapping
*/
enum JdbcType {
// Numeric types
TINYINT, SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC,
// Character types
CHAR, VARCHAR, LONGVARCHAR, NCHAR, NVARCHAR, LONGNVARCHAR,
// Binary types
BINARY, VARBINARY, LONGVARBINARY, BLOB,
// Date/time types
DATE, TIME, TIMESTAMP, TIME_WITH_TIMEZONE, TIMESTAMP_WITH_TIMEZONE,
// Other types
BOOLEAN, BIT, NULL, OTHER, UNDEFINED, CURSOR, ARRAY, STRUCT, REF,
CLOB, NCLOB, SQLXML, DATETIMEOFFSET;
}@MappedTypes(Object.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class JsonTypeHandler extends BaseTypeHandler<Object> {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
try {
ps.setString(i, objectMapper.writeValueAsString(parameter));
} catch (JsonProcessingException e) {
throw new SQLException("Error converting object to JSON", e);
}
}
@Override
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
return parseJson(json);
}
private Object parseJson(String json) throws SQLException {
if (json == null || json.trim().isEmpty()) {
return null;
}
try {
return objectMapper.readValue(json, Object.class);
} catch (JsonProcessingException e) {
throw new SQLException("Error parsing JSON", e);
}
}
// ... other methods
}@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class EncryptedStringTypeHandler extends BaseTypeHandler<String> {
private final EncryptionService encryptionService;
public EncryptedStringTypeHandler() {
this.encryptionService = new EncryptionService();
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
String encrypted = encryptionService.encrypt(parameter);
ps.setString(i, encrypted);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
String encrypted = rs.getString(columnName);
return encrypted == null ? null : encryptionService.decrypt(encrypted);
}
// ... other methods
}/**
* Type alias registry for mapping short names to full class names
*/
class TypeAliasRegistry {
/** Register type alias */
public void registerAlias(String alias, Class<?> value);
/** Register type alias with class name */
public void registerAlias(String alias, String value);
/** Register aliases for a package */
public void registerAliases(String packageName);
/** Resolve type alias to class */
public <T> Class<T> resolveAlias(String string);
}
/**
* Exception thrown during type handling operations
*/
class TypeException extends PersistenceException {
public TypeException(String message);
public TypeException(String message, Throwable cause);
}Install with Tessl CLI
npx tessl i tessl/maven-org-mybatis--mybatis