为什么不推荐使用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不好用,它也有它的优点)

相关推荐
一个处女座的程序猿O(∩_∩)O9 分钟前
Go语言Map值不可寻址深度解析:原理、影响与解决方案
开发语言·后端·golang
用户579854769711 小时前
01:系统架构全景:CountBot 多层模块化设计解析
后端
yhyyht1 小时前
Apache Camel 框架入门记录(一)
后端
rfidunion2 小时前
springboot+VUE+部署(13。创建多表查询)
vue.js·spring boot·后端
今心上3 小时前
spring中的@Autowired到底是什么
java·后端·spring
无心水3 小时前
【任务调度:数据库锁 + 线程池实战】4、架构实战:用线程池 + SKIP LOCKED 构建高可用分布式调度引擎
人工智能·分布式·后端·spring·架构
bugcome_com4 小时前
【C# 数组详解】Array 定义、初始化、遍历、内存原理与面试高频问题
后端·c#·asp.net
艾醒4 小时前
打破信息差——2月21日AI全域热点全复盘
后端·算法
golang学习记5 小时前
Go 1.26 新特性速览:更安全、更快、更聪明的 Go
后端·go
Cache技术分享5 小时前
331. Java Stream API - Java Stream 实战案例:找出合作最多的作者对
前端·后端