Type
TypeHandlerRegistry是在Mybatis源码中type包下,该包下主要的类主要都是用来进行类型转换(数据库查询出来结果后,将数据库类型转换成Java类型,原生JDBC时是PareparedStatement.setXXX),其中TypeHandler接口定义了规范。
package org.apache.ibatis.type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 类型转换器的根接口
* @author Clinton Begin
*/
public interface TypeHandler<T> {
//设置参数
// 在通过PreparedStatement为SQL语句绑定参数时,会将数据由Java类型转换成JdbcType类型
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
/**
* 从ResultSet中获取数据时会调用此方法,会将数据由JdbcType类型转换成Java类型
*/
//获取结果
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
package org.apache.ibatis.type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Clinton Begin
*/
public class DoubleTypeHandler extends BaseTypeHandler<Double> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Double parameter, JdbcType jdbcType)
throws SQLException {
ps.setDouble(i, parameter);
}
@Override
public Double getNullableResult(ResultSet rs, String columnName)
throws SQLException {
double result = rs.getDouble(columnName);
return result == 0 && rs.wasNull() ? null : result;
}
@Override
public Double getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
double result = rs.getDouble(columnIndex);
return result == 0 && rs.wasNull() ? null : result;
}
@Override
public Double getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
double result = cs.getDouble(columnIndex);
return result == 0 && cs.wasNull() ? null : result;
}
}
TypeHandlerRegistry
因为包中需要映射的类型太多,使用时并不能明确知道需要什么类型,所以会将类都放到TypeHandlerRegistry进行管理,TypeHandlerRegistry
则会在Configuration类初始化时进行初始化操作,TypeHandlerRegistry的初始化操作会为各个TypeHandler赋值。
/**
* 类型处理器注册机
* @author Clinton Begin
* @author Kazuki Shimizu
*/
public final class TypeHandlerRegistry {
// 记录JdbcType与TypeHandler之间的对应关系,其中JdbcType是一个枚举类型,它对应对应的JDBC类型
// 该集合主要用于从结果集读取数据时,将数据从Jdbc类型转换成Java类型
private final Map<JdbcType, TypeHandler<?>> jdbcTypeHandlerMap = new EnumMap<>(JdbcType.class);
// 记录了Java类型向指定JdbcType转换时,需要使用TypeHandler对象
private final Map<Type, Map<JdbcType, TypeHandler<?>>> typeHandlerMap = new ConcurrentHashMap<>();
private final TypeHandler<Object> unknownTypeHandler;
// 记录了全部TypeHandler的类型以及该类型相关的TypeHandler对象
private final Map<Class<?>, TypeHandler<?>> allTypeHandlersMap = new HashMap<>();
// 空TypeHandler集合的标识
private static final Map<JdbcType, TypeHandler<?>> NULL_TYPE_HANDLER_MAP = Collections.emptyMap();
private Class<? extends TypeHandler> defaultEnumTypeHandler = EnumTypeHandler.class;
/**
* The default constructor.
*/
public TypeHandlerRegistry() {
this(new Configuration());
}
public TypeHandlerRegistry(Configuration configuration) {
//构造函数里注册系统内置的类型处理器
//以下是为多个类型注册到同一个handler
this.unknownTypeHandler = new UnknownTypeHandler(configuration);
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler());
register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler());
//以下是为同一个类型的多种变种注册到多个不同的handler
register(Reader.class, new ClobReaderTypeHandler());
// StringTypeHandler能够将数据从String类型转换成null类型,所以向typeHandlerMap集合注册该对象,并向allTypeHandlersMap集合注册StringTypeHandler
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new StringTypeHandler());
// NStringTypeHandler能够将数据从String类型转换成NVARCHAR,所以向typeHandlerMap集合注册该对象,并向allTypeHandlersMap集合注册NStringTypeHandler
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new StringTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler());
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler());
register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler());
register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
register(InputStream.class, new BlobInputStreamTypeHandler());
register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler());
register(Object.class, unknownTypeHandler);
register(Object.class, JdbcType.OTHER, unknownTypeHandler);
register(JdbcType.OTHER, unknownTypeHandler);
register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler());
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());
register(String.class, JdbcType.SQLXML, new SqlxmlTypeHandler());
register(Instant.class, new InstantTypeHandler());
register(LocalDateTime.class, new LocalDateTimeTypeHandler());
register(LocalDate.class, new LocalDateTypeHandler());
register(LocalTime.class, new LocalTimeTypeHandler());
register(OffsetDateTime.class, new OffsetDateTimeTypeHandler());
register(OffsetTime.class, new OffsetTimeTypeHandler());
register(ZonedDateTime.class, new ZonedDateTimeTypeHandler());
register(Month.class, new MonthTypeHandler());
register(Year.class, new YearTypeHandler());
register(YearMonth.class, new YearMonthTypeHandler());
register(JapaneseDate.class, new JapaneseDateTypeHandler());
// issue #273
register(Character.class, new CharacterTypeHandler());
register(char.class, new CharacterTypeHandler());
}
//省略部分代码。。。
}
Alias
type包下,不仅有typeHandler的处理,还有关于Alias(别名)的处理。因为Java下的数据类型非常多,所以如果使用别名会很方便,而TypeAliasRegistry就是用来进行别名的映射处理。同样,也是在Configuration类加载时进行初始化。如果typeAliases(Map<String, Class<?>>)集合中,找不到对应的alias类型,则也会使用(Class) Resources.classForName(string);进行加载。
如果在mybatis-config.xml配置文件中,配置了Alias标签,则会在加载mybatis-config.xml文件中进行解析,并注册到TypeAliasRegistry中。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Alias {
/**
* Return the alias name.
*
* @return the alias name
*/
String value();
}
public class TypeAliasRegistry {
private final Map<String, Class<?>> typeAliases = new HashMap<>();
public TypeAliasRegistry() {
//构造函数里注册系统内置的类型别名
registerAlias("string", String.class);
//基本包装类型
registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);
//基本数组包装类型
registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);
//加个下划线,就变成了基本类型
registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);
//加个下划线,就变成了基本数组类型
registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);
//日期数字型
registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);
registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);
//集合型
registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);
//还有个ResultSet型
registerAlias("ResultSet", ResultSet.class);
}
@SuppressWarnings("unchecked")
// throws class cast exception as well if types cannot be assigned
//解析类型别名
public <T> Class<T> resolveAlias(String string) {
try {
if (string == null) {
return null;
}
// issue #748
// 先转成小写再解析
String key = string.toLowerCase(Locale.ENGLISH);
Class<T> value;
//从HashMap里找对应的键值,找到则返回类型别名对应的Class
if (typeAliases.containsKey(key)) {
value = (Class<T>) typeAliases.get(key);
} else {
//找不到,再试着将String直接转成Class(这样怪不得我们也可以直接用java.lang.Integer的方式定义,也可以就int这么定义)
value = (Class<T>) Resources.classForName(string);
}
return value;
} catch (ClassNotFoundException e) {
throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + e, e);
}
}
public void registerAliases(String packageName) {
registerAliases(packageName, Object.class);
}
//扫描并注册包下所有继承于superType的类型别名
public void registerAliases(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
// 查找指定包下的superType类型类
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
for (Class<?> type : typeSet) {
// 过滤掉内部类、接口以及抽象类
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
registerAlias(type);
}
}
}
//注册类型别名
public void registerAlias(Class<?> type) {
// 类的简单名称(不包含包名)
String alias = type.getSimpleName();
// 读取@Alias注解
Alias aliasAnnotation = type.getAnnotation(Alias.class);
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
// 检测此别名不存在后,会将其记录到typeAlias集合中
registerAlias(alias, type);
}
//注册类型别名
public void registerAlias(String alias, Class<?> value) {
// 检测alias为null,则直接抛出异常
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
}
// issue #748
// 将别名转换为小写
String key = alias.toLowerCase(Locale.ENGLISH);
// 检测别名是否已经存在
if (typeAliases.containsKey(key) && typeAliases.get(key) != null && !typeAliases.get(key).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + typeAliases.get(key).getName() + "'.");
}
// 注册别名
typeAliases.put(key, value);
}
public void registerAlias(String alias, String value) {
try {
registerAlias(alias, Resources.classForName(value));
} catch (ClassNotFoundException e) {
throw new TypeException("Error registering type alias " + alias + " for " + value + ". Cause: " + e, e);
}
}
/**
* Gets the type aliases.
*
* @return the type aliases
* @since 3.2.2
*/
public Map<String, Class<?>> getTypeAliases() {
return Collections.unmodifiableMap(typeAliases);
}
}