Java泛型在MyBatis中因类型擦除无法直接作为TypeHandler泛型参数保留,需通过泛型基类+运行时Class传入方式解决,核心是绕过擦除限制并显式传递实际类型。

Java 泛型在 MyBatis 映射中不能直接作为 TypeHandler 的泛型参数被保留(因类型擦除),但可通过“泛型基类 + 运行时 Class 传入”方式安全支持,核心是绕过擦除限制、显式传递实际类型。
为什么泛型字段映射会出问题
MyBatis 在解析 @TableField(typeHandler = XxxHandler.class) 或 XML 中的 typeHandler 时,只拿到 Handler 类字节码,无法获知泛型实参(如 List<User> 中的 User)。JVM 擦除后,List<User> 和 List<Order> 都变成裸类型 List,导致反序列化时无法构造正确对象。
用泛型基类 + 构造器传 Class 解决
不写死具体类型,而是定义一个可接收 Class<T> 的抽象 Handler 基类,子类在初始化时传入目标类型:
- 定义基类继承
BaseTypeHandler<T>,构造器接收Class<T>并保存为字段 - 子类如
JsonListTypeHandler<ReportUser>写成new JsonListTypeHandler<>(ReportUser.class) - 在
getNullableResult中用该Class实例化ObjectMapper.readValue(json, typeReference)
注册和使用要匹配方式
两种注册路径必须与泛型处理逻辑一致:
立即学习“Java免费学习笔记(深入)”;
-
注解方式:在字段上用
@TableField(typeHandler = ReportUserListTypeHandler.class),此时需让ReportUserListTypeHandler是一个“已绑定ReportUser.class的具体实现”,通常通过静态内部类或 Spring Bean 初始化完成 -
全局注册方式:在 MyBatis 配置中注册
JsonListTypeHandler.class并指定javaType="java.util.List",同时在 handler 内部通过反射或上下文推断泛型元素类型(需配合字段元数据)
JSON List 映射的典型写法
以数据库存 JSON 字符串、Java 字段为 List<ReportUser> 为例:
- 实体字段加注解:
@TableField(typeHandler = ReportUserListTypeHandler.class) -
ReportUserListTypeHandler继承BaseTypeHandler<List<ReportUser>>,重写方法时用ObjectMapper的TypeReference<List<ReportUser>>解析 - 为避免每个 List 类型都写一个 handler,可抽象为
GenericJsonListHandler<T>,再由 Spring 管理具体 Bean(如@Bean public TypeHandler<List<ReportUser>> reportUserListHandler() { return new GenericJsonListHandler<>(ReportUser.class); })


















