Mybatis枚举类型转换源码分析
作者:__如风__
在Mybatis的TypeHandlerRegistry中,添加了常用的类转换器,其中默认的枚举类型转换器是EnumTypeHandler,这篇文章主要介绍了Mybatis枚举类型转换源码分析,需要的朋友可以参考下
Mybatis枚举类型转换
类型转换器源码分析
在Mybatis的TypeHandlerRegistry中,添加了常用的类转换器,其中默认的枚举类型转换器是EnumTypeHandler。
public final class TypeHandlerRegistry { .... public TypeHandlerRegistry(Configuration configuration) { 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()); ...
EnumTypeHandler.java,默认使用的是枚举的名称设置参数和转换枚举类型。
public EnumTypeHandler(Class<E> type) { if (type == null) { throw new IllegalArgumentException("Type argument cannot be null"); } this.type = type; } @Override public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { if (jdbcType == null) { ps.setString(i, parameter.name()); } else { ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589 } } @Override public E getNullableResult(ResultSet rs, String columnName) throws SQLException { String s = rs.getString(columnName); return s == null ? null : Enum.valueOf(type, s); ...
以下代码展示了如何为确定枚举类型的类型转换器。
- 首先直接获取对应类型的类型型转换器,包括原始类型,包括raw type(原始类型,对应Class),parameterized types(参数化类型), array types(数组类型),这是最精确的匹配。
- 如果是Class类型且枚举类型是其接口或父类,如果是匿名类,寻找其父类的类型转换器,否则再不断递归寻找该枚举类的接口类型转换器,如果没有找到,直接利用反射获defaultEnumHandler的的对象,专门用于处理该枚举类型,在图中是GroupStatusEnum。
- 如果不是枚举类型,则再尝试其父类。
getInstance方法如下
public <T> TypeHandler<T> getInstance(Class<?> javaTypeClass, Class<?> typeHandlerClass) { if (javaTypeClass != null) { try { Constructor<?> c = typeHandlerClass.getConstructor(Class.class); return (TypeHandler<T>) c.newInstance(javaTypeClass); } catch (NoSuchMethodException ignored) { // ignored } catch (Exception e) { throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e); } } try { Constructor<?> c = typeHandlerClass.getConstructor(); return (TypeHandler<T>) c.newInstance(); } catch (Exception e) { throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e); } }
自定义通用枚举类型
为项目中所有枚举类型定一个接口
public interface BaseEnum { Integer getValue(); }
枚举类实现该接口
@AllArgsConstructor @Getter public enum GroupStatusEnum implements BaseEnum { DISBANDED("已解散", 0), NORMAL("正常", 1); private final String desc; private final Integer value; }
定义通用枚举类型转换器
public class GenericEnumHandler<E extends BaseEnum> implements TypeHandler<E> { private final Map<Integer, E> map = new HashMap<>(); public GenericEnumHandler(Class<E> clazz) { E[] constants = clazz.getEnumConstants(); for (E constant : constants) { map.put(constant.getValue(), constant); } } @Override public void setParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { ps.setInt(i, parameter.getValue()); } @Override public E getResult(ResultSet rs, String columnName) throws SQLException { return map.get(rs.getInt(columnName)); } @Override public E getResult(ResultSet rs, int columnIndex) throws SQLException { return map.get(rs.getInt(columnIndex)); } @Override public E getResult(CallableStatement cs, int columnIndex) throws SQLException { return map.get(cs.getInt(columnIndex)); } }
按照上述源码分析流程,当GroupStatusEnum第一次需要转化数据库的int时,mybatis去寻找类型转换器。
- 我们没有为这种类型定义专门的类型转换器(TypeHandler<GroupStatusEnum>)。
- 该类不是内部类。
- 该类实现了BaseEnum接口,但是我们没有为BaseEnum定义类型转换器。
- 使用该类和默认的枚举类利用反射构造一个对象处理该枚举,即new GenericEnumTypeHandler(GroupStatusEnum.class)。
使用方法
mybatis: configuration: local-cache-scope: statement jdbc-type-for-null: null use-generated-keys: true cache-enabled: false map-underscore-to-camel-case: true default-enum-type-handler: com.windcf.easychatjava.typehandler.GenericEnumHandler mapper-locations: classpath:/mappers/**/*.xml # type-handlers-package: com.windcf.easychatjava.typehandler
到此这篇关于Mybatis枚举类型转换的文章就介绍到这了,更多相关Mybatis枚举类型转换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!