目錄
序言
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.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
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