为什么不推荐使用Lombok?@Data不香吗?


一、前言

之前写项目遇到的一个Bug,下面是模拟代码。

新建一个springboot的项目,Person一个实体类,定义一个方法传一个JSON数据

typescript 复制代码
@Data
public class Person {
    private String name;
    private String aName;
    private String aaName;
}
less 复制代码
@SpringBootApplication
@RestController
public class LombokTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(LombokTestApplication.class, args);
    }

    @PostMapping("/user")
    public String userSearch(@RequestBody Person person){
        System.out.println(person);
        return "okk~";
    }

}

springboot启动之后postman发送一次请求。

请求路径:http://localhost:8080/user

JSON数据:

json 复制代码
{
    "name": "aaa",
    "aName": "bbb",
    "aaName": "ccc"
}

后台输出结果

编辑

我们会发现,aName字段为null?居然接收不了,而aaName可以接受,这是为什么呢?

二、源码跟踪

分析这个源码要对SpringMVC框架有一定的理解,它的最基础的请求处理也是基于原生的servlet去进行了一个扩展,它扩展的一个核心叫做 DispatcherServlet ,它的所有的http请求都会去走 doDispatch 这个方法。

编辑

在大概540行左右的handle,这里在调用,我们关注的是 为什么那个aName参数它没有解析出来,后面执行会调用 InvocableHandlerMethod 里面的 getMethodArgumentValues 方法。

编辑

在方法的return部分我们打了个断点,看看会返回啥?

编辑

发现这个方法返回就使aName变成了null(这里就已经完成了参数解析了,说明问题出在这一块)。

然后进过一系列的操作,我们最终来到了 POJOPropertiesCollector 的 collectAll 这个方法,我们在 _addFields 与 _addMethods 打个断点。

编辑

跑一下,在_addFields他的size为0,我们再来看看_addMethods,它的size为3。

编辑

我们点击下一步(不是下一个断点)发现他的长度变成了4了,而且还多了个aname的字段

编辑

按住ctrl键点击_addMethods我们进去看看,这个方法填加了一个字段。

ini 复制代码
protected void _addMethods(Map<String, POJOPropertyBuilder> props) {
        Iterator var2 = this._classDef.memberMethods().iterator();

        while(var2.hasNext()) {
            AnnotatedMethod m = (AnnotatedMethod)var2.next();
            int argCount = m.getParameterCount();
            if (argCount == 0) {
                this._addGetterMethod(props, m, this._annotationIntrospector);
            } else if (argCount == 1) {
                this._addSetterMethod(props, m, this._annotationIntrospector);
            } else if (argCount == 2 && Boolean.TRUE.equals(this._annotationIntrospector.hasAnySetter(m))) {
                if (this._anySetters == null) {
                    this._anySetters = new LinkedList();
                }

                this._anySetters.add(m);
            }
        }

    }

我们再点击下一步,一直到_removeUnwantedAccessor这个,发现size变成3了,这里就删除了我们的aName字段,保留了aname,这就是问题的关键了。

编辑

这里我们要看看这个@Data到底生成了什么东西,我们在终端敲入命令:mvn clean package

编辑

我们看看反编译出来的到底是个啥?

编辑

左边是手动生成的get set 方法,右边是@Data 生成的,我们发现了自己生成的 getaName 它的a是小写的,而@Data生成的getAName的A是大写的。

编辑

而getAName可能反推出aName和aname两个可能,所以在_removeUnwantedAccessor这里就删除了aName这个字段,就后台接受不到了。

三、总结

这个bug虽然不算什么,但是这也是个细节,虽然像aName这种不规范的命名字段很少用,但是这里模拟当初项目的出错,这里还是建议大家使用手动或者快捷键生成的实体类的方法(当然不是Lombok不好用,它也有它的优点)

相关推荐
码界奇点14 分钟前
基于Spring Boot与Vue的校园后台管理系统设计与实现
vue.js·spring boot·后端·毕业设计·源代码管理
爱编程的小庄16 分钟前
Rust 发行版本及工具介绍
开发语言·后端·rust
Apifox.2 小时前
测试用例越堆越多?用 Apifox 测试套件让自动化回归更易维护
运维·前端·后端·测试工具·单元测试·自动化·测试用例
sunnyday04262 小时前
Nginx与Spring Cloud Gateway QPS统计全攻略
java·spring boot·后端·nginx
康王有点困2 小时前
Link入门
后端·flink
海南java第二人2 小时前
Spring Boot全局异常处理终极指南:打造优雅的API错误响应体系
java·spring boot·后端
小楼v3 小时前
消息队列的核心概念与应用(RabbitMQ快速入门)
java·后端·消息队列·rabbitmq·死信队列·交换机·安装步骤
小北方城市网3 小时前
接口性能优化实战:从秒级到毫秒级
java·spring boot·redis·后端·python·性能优化
鸡蛋豆腐仙子3 小时前
Spring的AOP失效场景
java·后端·spring
小北方城市网3 小时前
SpringBoot 全局异常处理最佳实践:从混乱到规范
java·spring boot·后端·spring·rabbitmq·mybatis·java-rabbitmq