目录
序言
Setter-Getter方法的坑
问题发现
解决
原因
Mybatis(3.4.6版本)解析get-set方法获取属性名字的源码:
Mybatis解析get-set方法为属性名字测试
解决方案
@Accessor(chain = true)注解的问题
首页 Java Java基础 认识Lombok的坑

认识Lombok的坑

Oct 09, 2020 pm 05:00 PM
lombok

java基础教程栏目为大家介绍认识Lombok的坑,好用。

认识Lombok的坑

序言

去年在项目当中引入了Lombok插件,着实解放了双手,代替了一些重复的简单工作(Getter,Setter,toString等方法的编写),但是,在使用的过程当中,也发现了一些坑,开始的时候并没有察觉到是Lombok的问题,后来跟踪了对应的其他组件的源码,才发现是Lombok的问题!

Setter-Getter方法的坑

问题发现

我们在项目当中主要使用Lombok的Setter-Getter方法的注解,也就是组合注解@Data,但是在一次使用Mybatis插入数据的过程当中,出现了一个问题,问题描述如下:

我们有个实体类:
@Data
public class NMetaVerify{
    private NMetaType nMetaType;
    private Long id;
    ....其他属性
}复制代码
登录后复制

当我们使用Mybatis插入数据的时候,发现,其他属性都能正常的插入,但是就是nMetaType属性在数据库一直是null.

解决

当我debug项目代码到调用Mybatis的插入SQL对应的方法的时候,我看到NMetaVerify对象的nMetaType属性还是有数据的,但是执行插入之后,数据库的nMetaType字段就是一直是null,原先我以为是我的枚举类型写法不正确,看了下别的同样具有枚举类型的字段,也是正常能插入到数据库当中的,这更让我感觉到疑惑了.于是,我就跟踪Mybatis的源码,发现Mybatis在获取这个nMetaType属性的时候使用了反射,使用的是getxxxx方法来获取的,但是我发现nMetaType的get方法好像有点和Mybatis需要的getxxxx方法长的好像不一样.问题找到了!

原因

Lombok对于第一个字母小写,第二个字母大写的属性生成的get-set方法和Mybatis以及idea或者说是Java官方认可的get-set方法生成的不一样:

#Lombok生成的Get-Set方法
@Data
public class NMetaVerify {
    private Long id;
    private NMetaType nMetaType;
    private Date createTime;
    
    public void lombokFound(){
        NMetaVerify nMetaVerify = new NMetaVerify();
        nMetaVerify.setNMetaType(NMetaType.TWO); //注意:nMetaType的set方法为setNMetaType,第一个n字母大写了,
        nMetaVerify.getNMetaType();                                  //getxxxx方法也是大写
    }
}复制代码
登录后复制
#idea,Mybatis,Java官方默认的行为为:
public class NMetaVerify {
    private Long id;
    private NMetaType nMetaType;
    private Date createTime;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public NMetaType getnMetaType() {//注意:nMetaType属性的第一个字母小写
        return nMetaType;
    }

    public void setnMetaType(NMetaType nMetaType) {//注意:nMetaType属性的第一个字母小写
        this.nMetaType = nMetaType;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}复制代码
登录后复制

Mybatis(3.4.6版本)解析get-set方法获取属性名字的源码:

package org.apache.ibatis.reflection.property;

import java.util.Locale;

import org.apache.ibatis.reflection.ReflectionException;

/**
 * @author Clinton Begin
 */
public final class PropertyNamer {

        private PropertyNamer() {
            // Prevent Instantiation of Static Class
        }

        public static String methodToProperty(String name) {
            if (name.startsWith("is")) {//is开头的一般是bool类型,直接从第二个(索引)开始截取(简单粗暴)
                    name = name.substring(2);
            } else if (name.startsWith("get") || name.startsWith("set")) {//set-get的就从第三个(索引)开始截取
                    name = name.substring(3);
            } else {
                    throw new ReflectionException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
            }
            //下面这个判断很重要,可以分成两句话开始解释,解释如下
            //第一句话:name.length()==1
            //                      对于属性只有一个字母的,例如private int x;
            //                      对应的get-set方法是getX();setX(int x);
            //第二句话:name.length() > 1 && !Character.isUpperCase(name.charAt(1)))
            //                      属性名字长度大于1,并且第二个(代码中的charAt(1),这个1是数组下标)字母是小写的
            //                      如果第二个char是大写的,那就直接返回name
            if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
                    name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);//让属性名第一个字母小写,然后加上后面的内容
            }

            return name;
        }

        public static boolean isProperty(String name) {
                return name.startsWith("get") || name.startsWith("set") || name.startsWith("is");
        }

        public static boolean isGetter(String name) {
                return name.startsWith("get") || name.startsWith("is");
        }

        public static boolean isSetter(String name) {
                return name.startsWith("set");
        }

}复制代码
登录后复制

Mybatis解析get-set方法为属性名字测试

    @Test
    public void foundPropertyNamer() {
        String isName = "isName";
        String getName = "getName";
        String getnMetaType = "getnMetaType";
        String getNMetaType = "getNMetaType";

        Stream.of(isName,getName,getnMetaType,getNMetaType)
                .forEach(methodName->System.out.println("方法名字是:"+methodName+" 属性名字:"+ PropertyNamer.methodToProperty(methodName)));
    }
    
    #输出结果如下:
    方法名字是:isName 属性名字:name 
    方法名字是:getName 属性名字:name 
    方法名字是:getnMetaType 属性名字:nMetaType //这个以及下面的属性第二个字母都是大写,所以直接返回name
    方法名字是:getNMetaType 属性名字:NMetaType复制代码
登录后复制

解决方案

1.修改属性名字,让第二个字母小写,或者说是规定所有的属性的前两个字母必须小写
2.如果数据库已经设计好,并且前后端接口对接好了,不想修改,那就专门为这种特殊的属性使用idea生成get-set方法复制代码
登录后复制

@Accessor(chain = true)注解的问题

问题发现

在使用easyexcel(github.com/alibaba/eas…) 导出的时候,发现以前的实体类导出都很正常,但是现在新加的实体类不正常了,比对了发现,新加的实体类增加了@Accessor(chain = true)注解,我们的目的主要是方便我们链式调用set方法:

new UserDto()
.setUserName("")
.setAge(10)
........
.setBirthday(new Date());复制代码
登录后复制

原因

easyexcel底层使用的是cglib来做反射工具包的:

com.alibaba.excel.read.listener.ModelBuildEventListener 类的第130行
BeanMap.create(resultModel).putAll(map);

最底层的是cglib的BeanMap的这个方法调用

abstract public Object put(Object bean, Object key, Object value);复制代码
登录后复制

但是cglib使用的是Java的rt.jar里面的一个Introspector这个类的方法:

# Introspector.java 第520行
if (int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {
   pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, method, null);
   //下面这行判断,只获取返回值是void类型的setxxxx方法
 } else if (void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {
    // Simple setter
    pd = new PropertyDescriptor(this.beanClass, name.substring(3), null, method);
    if (throwsException(method, PropertyVetoException.class)) {
       pd.setConstrained(true);
    }
}复制代码
登录后复制

解决方案

1.去掉Accessor注解
2.要么就等待easyexcel的作者替换掉底层的cglib或者是其他,反正是支持获取返回值不是void的setxxx方法就行复制代码
登录后复制

相关免费学习推荐:java基础教程

以上是认识Lombok的坑的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

专业指导:如何成功安装Eclipse Lombok插件的专家建议和步骤 专业指导:如何成功安装Eclipse Lombok插件的专家建议和步骤 Jan 28, 2024 am 09:15 AM

专业指导:Eclipse安装Lombok插件的专家建议和步骤,需要具体代码示例摘要:Lombok是一种Java库,能够通过注解的方式简化Java代码的编写,并提供了一些功能强大的工具。本文将向读者介绍如何在Eclipse中安装和配置Lombok插件的步骤,并提供一些具体的代码示例,以便读者能够更好地理解和使用Lombok插件。下载Lombok插件首先,我们需

简单教程:在Eclipse中快速安装Lombok插件 简单教程:在Eclipse中快速安装Lombok插件 Jan 28, 2024 am 08:06 AM

快速入门:Eclipse中安装Lombok插件的简易教程,需要具体代码示例在开发Java项目过程中,常常会使用到Lombok这个实用的插件。Lombok可以帮助我们简化Java代码,减少样板代码的编写,提升开发效率。本文将为你介绍如何在Eclipse中安装和配置Lombok插件,并提供具体的代码示例。步骤一:下载Lombok插件首先,我们需要从Lombok官

SpringBoot整合Lombok及常见问题怎么解决 SpringBoot整合Lombok及常见问题怎么解决 May 20, 2023 pm 12:46 PM

LombokLombok能以简单的注解形式来简化java代码,从而提高开发人员的开发效率。其本身是一个优秀的Java代码库,它采用了一种投机取巧的语法糖,简化了Java的编码,为Java代码的精简提供了一种方式,但Lombok并非一个标准的Java库。在web开发过程中经常需要写的Java类,都需要花时间去添加相应的getter/setter、构造器和equals等方法。当属性多时会出现大量的getter/setter方法,这些显得很冗长也没有太多技术含量,一旦修改属性,容易出现忘记修改对应方法

Eclipse Lombok插件安装的完整指南 Eclipse Lombok插件安装的完整指南 Jan 28, 2024 am 09:58 AM

完全指南:Eclipse如何安装Lombok插件,需要具体代码示例引言:Eclipse是一个广泛使用的集成开发环境(IDE),用于Java开发。Lombok是一个Java库,可以自动化一些繁琐的代码,从而提高开发效率。本文将详细介绍如何在Eclipse中安装Lombok插件,并提供具体的代码示例。第一步:下载Lombok插件打开Eclipse,选择“Help

简便安装:在Eclipse中安装Lombok插件的小技巧 简便安装:在Eclipse中安装Lombok插件的小技巧 Jan 28, 2024 am 09:29 AM

实用技巧:Eclipse如何轻松安装Lombok插件,需要具体代码示例在日常的Java开发中,我们经常会使用到Eclipse作为主要的集成开发环境。而在实际开发中,我们可能会遇到一些繁琐的操作,比如Getter和Setter方法的手动编写。为了简化这些操作,我们可以使用Lombok插件来自动帮助我们生成这些代码。下面将介绍如何在Eclipse中轻松安装和配置

Java库lombok及注解如何使用 Java库lombok及注解如何使用 Jun 03, 2023 pm 09:28 PM

Lombok是什么Lombok是一个旨在减少代码开发工作的Java库。它提供了一些简单的注解,并以此来消除java中臃肿的模版代码,比如pojo中最常见的setter/getter方法,比如toString方法,比如equals方法等等,还可以帮助我们关闭流,即使JDK7中已经有了TWR特性,但这个包很值得一试。通过几个简单的注解,将模版代码在编译时写入程序。使用eclipse可以在Outline窗口看到生成的方法,但是在源码里是干净的.安装首先去lombok官网下载jar包。只是把jar包下载

Java API 开发中使用 Lombok 进行编码简化 Java API 开发中使用 Lombok 进行编码简化 Jun 18, 2023 pm 11:34 PM

Java是一种常用的编程语言,广泛应用于开发各种类型的应用程序。JavaAPI是Java语言的核心部分之一,它为开发人员提供了许多可重用的代码和库,可以加速应用程序的开发和部署过程。在JavaAPI的开发过程中,经常需要使用一些简化编码的工具和技术,以提高代码的可读性和可维护性。Lombok是一款非常实用的Java库,可以在Java

java中Lombok有什么注解 java中Lombok有什么注解 Apr 30, 2023 pm 03:52 PM

注解举例1、@ToString:实现toString()方法2、@Data:注解在类上;提供类所有属性的getting和setting方法,此外还提供了equals、canEqual、hashCode、toString方法3、@Setter:注解在属性上;为属性提供setting方法。@Getter:注解在属性上;为属性提供getting方法@Log4j:注解在类上;为类提供一个属性名为log的log4j日志对象@NoArgsConstructor:注解在类上;为类提供一个无参的构造方法@All

See all articles