当前位置: 首页 > news >正文

@Builder注解导致mybatis类型匹配错误 Cannot determine value type from string

@Builder注解

@Builder 注解是 Lombok 提供的一个非常强大的功能,它用于自动生成构建器模式的代码,使得对象的创建和初始化变得清晰、灵活且易于阅读。其核心原理可以概括为:在编译时,通过注解处理器(Annotation Processor)分析源代码的抽象语法树(AST),并自动生成新的Java代码。

比如,实体类加@Builder注解:

@Builder
public class CcsZprkCallback extends BaseEntity
{private static final long serialVersionUID = 1L;/** 主键,自增id */@TableId(value = "id", type = IdType.AUTO)private Long id;/** ccslogid */@Excel(name = "ccslogid")private Long ccsLogId;...
}

编译之后,通过Idea的反编译功能,查看CcsZprkCallback.class文件,可以发现一下几点变化:

  • 增加了一个全参构造器
    CcsZprkCallback(Long id, Long ccsLogId, String taskId, String orderId, String oppSys, String fromOrTo, String clientId, String reqUrl, Date reqTime, String method, BigDecimal quantity, String stockNo, Integer respCode, String respMsg, Date respTime, Long status) {this.id = id;this.ccsLogId = ccsLogId;this.taskId = taskId;this.orderId = orderId;this.oppSys = oppSys;this.fromOrTo = fromOrTo;this.clientId = clientId;this.reqUrl = reqUrl;this.reqTime = reqTime;this.method = method;this.quantity = quantity;this.stockNo = stockNo;this.respCode = respCode;this.respMsg = respMsg;this.respTime = respTime;this.status = status;}
    
  • 没有无参构造器,所以你不能通过new CcsZprkCallback()方式创建对象了,而且他的全参构造器也不是public的,不在同一个包下的话你也不能通过全参构造器创建实例对象。
  • 提供了一个内部类CcsZprkCallbackBuilder,是构建器模式中的构建器,可以说是唯一可以提供示例创建的方式,我们只能通过这个构建器、给这个构建器传递参数,然后在通过这个构建器的build方法来实例化对象。
  • 提供了一个静态的builder方法来获取上面提到的构建器:
public static CcsZprkCallback.CcsZprkCallbackBuilder builder() {return new CcsZprkCallback.CcsZprkCallbackBuilder();}
  • 构建器的包含了原类(例子中的CcsZprkCallback)的所有属性,并且可以支持通过链式调用的方式给构建起的属性赋值。
  • 构建器提供一个build方法,调用原类的全参构造器创建原类的实例对象
 public CcsZprkCallback build() {return new CcsZprkCallback(this.id, this.ccsLogId, this.taskId, this.orderId, this.oppSys, this.fromOrTo, this.clientId, this.reqUrl, this.reqTime, this.method, this.quantity, this.stockNo, this.respCode, this.respMsg, this.respTime, this.status);}
  • 如果你的类中没有equals和hashcode方法,会提供一个极其复杂的equals方法,判断所有属性都相等的情况下,两个实体相等,也会提供一个hashcode方法。

@Builder注解实现的功能其实就这么多,非常简单,个人感觉也没提供什么强大的功能,类似于语法糖,可以让喜欢的人写出来看起来比较高大上的链式调用代码。

但是,我们需要特别注意的是,由于@Builder注解去掉了缺省无参构造器,如果你在Mybatis的实体类加了@Builder注解,会导致mybatis在执行sql查询之后匹配字段的时候出现bug,而且非常诡异,不容易排查。

@Builder注解导致的mybatis字段匹配问题

mybatis实体类如果没有写无参构造器、使用了@Builder注解的话,会导致mybatis执行完sql查询后,匹配ResultSet中的字段到实体类属性的时候发生错配,导致诡异的bug:sql查询报错 Cannot determine value type from string …但是你不论是检查xml中ResultMap的字段 - 属性匹配关系,还是检查数据库中的字段类型、实体类中的属性类型,发现一切正常都没有问题、不应该报错。但是实际情况就是会报错。

导致错误的原因,其实@Builder就是罪魁祸首,我们可以从Mybatis源码大概找一下原因。Mybatis负责解析查询结果的类是DefaultResultSetHandler,在xml中配置的对应实体类没有无参构造器的情况下,会调用applyColumnOrderBasedConstructorAutomapping方法:

private boolean applyColumnOrderBasedConstructorAutomapping(ResultSetWrapper rsw, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor, boolean foundValues) throws SQLException {for(int i = 0; i < constructor.getParameterTypes().length; ++i) {Class<?> parameterType = constructor.getParameterTypes()[i];String columnName = (String)rsw.getColumnNames().get(i);TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);Object value = typeHandler.getResult(rsw.getResultSet(), columnName);constructorArgTypes.add(parameterType);constructorArgs.add(value);foundValues = value != null || foundValues;}return foundValues;}

最终会从resultSet中获取数据,然后调用实体类的全参构造器,也就是@Builder注解加入进来的构造器,然后,按照resultSet中的顺序、对应全参构造器中的参数顺序进行赋值。这样的话,就要求resultSet中从数据库获取到的字段顺序,和全参构造器中的参数顺序完全匹配。但是我们知道,这个匹配绝大部分情况下是不可能的,因为resultSet的字段顺序是sql语句中写的、全参构造器的顺序大概是实体类中属性定义的顺序,很难碰巧能对应。

如果不能对应的话,就会出现错配,最终在将resultSet中的数据赋值给实体类的实例时发生类型转换错误,你就会看到这个 Cannot determine value type from string错误:

    public T getResult(ResultSet rs, String columnName) throws SQLException {try {return this.getNullableResult(rs, columnName);} catch (Exception var4) {throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + var4, var4);}}

怎么解决

一个办法是,尽可能不在mybatis实体类中用@Builder注解。

第二,如果你特别喜欢@Builder注解的话,必须保证实体类有无参构造器,要么手写一个,要么加@NoArgsConstructor注解。

http://www.dtcms.com/a/560812.html

相关文章:

  • AI模型开发 | 从零部署Deepseek OCR模型,零门槛开发PDF文档解析工具
  • Linux INPUT 子系统实验
  • 1000套实习报告模板大合集+多行业多专业实习总结实践报告素材
  • 百度网站快速优化国内flask做的网站
  • Spring AI--Prompt、多轮对话实现方案
  • 网页模板免费下载网站广州页面制作公司
  • Java:继承与多态
  • 10. 从0到上线:.NET 8 + ML.NET LTR 智能类目匹配实战--Web API 接口与前端集成:部署与生产运维:稳定性、可观测与成本
  • 网站开发招标网网站免费注册会员怎么做
  • linux系统中网络编程的实现
  • Vue-github 用户搜索案例
  • GD32F407VE天空星开发板的电压电流检测
  • 网站优化文章怎么做蔡甸城乡建设局网站
  • 中小企业网站开发韵茵全屋定制家具品牌排行榜前十名
  • 分库分表MyCat 架构迁移 OceanBase | 百丽核心财务系统迁移经验总结与问题汇总
  • joomla 企业网站模板沈阳网站优化 唐朝网络
  • Flink 优化-反压处理
  • AI代码开发宝库系列:LangChain 工具链:从LCEL到实际应用
  • 泉州网站排名优化十大免费论文网站
  • 高校招生网站建设做网站一定要效果图吗
  • 学习笔记四:性能度量
  • 使用JavaScript和Node.js构建简单的RESTful API
  • 【生活】做蛋糕
  • (论文速读)EgoLife:走向自我中心的生活助手
  • 大模型时代,我们该如何学习?从“知识存储器”到“思维策展人”的蜕变
  • vc_redist.x64.exe安装方法,解决软件游戏缺少运行库问题
  • 【C++】继承(1):深入理解和使用
  • C语言内功强化之修饰关键字
  • 未来已来:AI 如何在 3 年内重塑工作、教育与生活
  • 追波设计网站wordpress如何去除页眉部分