亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解Lombok的坑

 更新時(shí)間:2020年11月04日 10:18:46   作者:liuxuzxx  
這篇文章主要介紹了詳解Lombok的坑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

序言

去年在項(xiàng)目當(dāng)中引入了Lombok插件,著實(shí)解放了雙手,代替了一些重復(fù)的簡單工作(Getter,Setter,toString等方法的編寫),但是,在使用的過程當(dāng)中,也發(fā)現(xiàn)了一些坑,開始的時(shí)候并沒有察覺到是Lombok的問題,后來跟蹤了對應(yīng)的其他組件的源碼,才發(fā)現(xiàn)是Lombok的問題!

Setter-Getter方法的坑

問題發(fā)現(xiàn)

我們在項(xiàng)目當(dāng)中主要使用Lombok的Setter-Getter方法的注解,也就是組合注解@Data,但是在一次使用Mybatis插入數(shù)據(jù)的過程當(dāng)中,出現(xiàn)了一個(gè)問題,問題描述如下:

我們有個(gè)實(shí)體類:

@Data
public class NMetaVerify{
  private NMetaType nMetaType;
  private Long id;
  ....其他屬性
}

當(dāng)我們使用Mybatis插入數(shù)據(jù)的時(shí)候,發(fā)現(xiàn),其他屬性都能正常的插入,但是就是nMetaType屬性在數(shù)據(jù)庫一直是null.

解決

當(dāng)我debug項(xiàng)目代碼到調(diào)用Mybatis的插入SQL對應(yīng)的方法的時(shí)候,我看到NMetaVerify對象的nMetaType屬性還是有數(shù)據(jù)的,但是執(zhí)行插入之后,數(shù)據(jù)庫的nMetaType字段就是一直是null,原先我以為是我的枚舉類型寫法不正確,看了下別的同樣具有枚舉類型的字段,也是正常能插入到數(shù)據(jù)庫當(dāng)中的,這更讓我感覺到疑惑了.于是,我就跟蹤Mybatis的源碼,發(fā)現(xiàn)Mybatis在獲取這個(gè)nMetaType屬性的時(shí)候使用了反射,使用的是getxxxx方法來獲取的,但是我發(fā)現(xiàn)nMetaType的get方法好像有點(diǎn)和Mybatis需要的getxxxx方法長的好像不一樣.問題找到了!

原因

Lombok對于第一個(gè)字母小寫,第二個(gè)字母大寫的屬性生成的get-set方法和Mybatis以及idea或者說是Java官方認(rèn)可的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,第一個(gè)n字母大寫了,
    nMetaVerify.getNMetaType();                 //getxxxx方法也是大寫
  }
}

#idea,Mybatis,Java官方默認(rèn)的行為為:
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屬性的第一個(gè)字母小寫
    return nMetaType;
  }

  public void setnMetaType(NMetaType nMetaType) {//注意:nMetaType屬性的第一個(gè)字母小寫
    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類型,直接從第二個(gè)(索引)開始截取(簡單粗暴)
     name = name.substring(2);
   } else if (name.startsWith("get") || name.startsWith("set")) {//set-get的就從第三個(gè)(索引)開始截取
     name = name.substring(3);
   } else {
     throw new ReflectionException("Error parsing property name '" + name + "'. Didn't start with 'is', 'get' or 'set'.");
   }
      //下面這個(gè)判斷很重要,可以分成兩句話開始解釋,解釋如下
      //第一句話:name.length()==1
      //    對于屬性只有一個(gè)字母的,例如private int x;
      //     對應(yīng)的get-set方法是getX();setX(int x);
      //第二句話:name.length() > 1 && !Character.isUpperCase(name.charAt(1)))
      //   屬性名字長度大于1,并且第二個(gè)(代碼中的charAt(1),這個(gè)1是數(shù)組下標(biāo))字母是小寫的
      //   如果第二個(gè)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);//讓屬性名第一個(gè)字母小寫,然后加上后面的內(nèi)容
   }

   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)));
  }
  
  #輸出結(jié)果如下:
  方法名字是:isName 屬性名字:name 
  方法名字是:getName 屬性名字:name 
  方法名字是:getnMetaType 屬性名字:nMetaType //這個(gè)以及下面的屬性第二個(gè)字母都是大寫,所以直接返回name
  方法名字是:getNMetaType 屬性名字:NMetaType

解決方案
1.修改屬性名字,讓第二個(gè)字母小寫,或者說是規(guī)定所有的屬性的前兩個(gè)字母必須小寫
2.如果數(shù)據(jù)庫已經(jīng)設(shè)計(jì)好,并且前后端接口對接好了,不想修改,那就專門為這種特殊的屬性使用idea生成get-set方法

@Accessor(chain = true)注解的問題

問題發(fā)現(xiàn)

在使用easyexcel(https://github.com/alibaba/easyexcel) 導(dǎo)出的時(shí)候,發(fā)現(xiàn)以前的實(shí)體類導(dǎo)出都很正常,但是現(xiàn)在新加的實(shí)體類不正常了,比對了發(fā)現(xiàn),新加的實(shí)體類增加了@Accessor(chain = true)注解,我們的目的主要是方便我們鏈?zhǔn)秸{(diào)用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的這個(gè)方法調(diào)用

abstract public Object put(Object bean, Object key, Object value);

但是cglib使用的是Java的rt.jar里面的一個(gè)Introspector這個(gè)類的方法:

# 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.要么就等待easye

到此這篇關(guān)于詳解Lombok的坑的文章就介紹到這了,更多相關(guān)Lombok 坑內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java基于rest assured實(shí)現(xiàn)接口測試過程解析

    Java基于rest assured實(shí)現(xiàn)接口測試過程解析

    這篇文章主要介紹了Java基于rest assured實(shí)現(xiàn)接口測試過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 深入理解 Java注解及實(shí)例

    深入理解 Java注解及實(shí)例

    這篇文章主要介紹了深入理解 Java注解及實(shí)例的相關(guān)資料,希望通過本文大家能夠掌握java注解的知識,需要的朋友可以參考下
    2017-09-09
  • java 中死鎖問題的實(shí)例詳解

    java 中死鎖問題的實(shí)例詳解

    這篇文章主要介紹了java 中死鎖問題的實(shí)例詳解的相關(guān)資料,希望通過本文大家能夠理解掌握死鎖的問題,需要的朋友可以參考下
    2017-09-09
  • Spring之@DependsOn注解詳細(xì)解析

    Spring之@DependsOn注解詳細(xì)解析

    這篇文章主要介紹了Spring之@DependsOn注解詳細(xì)解析,@DependsOn注解是Spring中提供的一個(gè)指定Spring創(chuàng)建Bean的依賴順序的注解,需要的朋友可以參考下
    2024-01-01
  • SpringBoot整合mybatis結(jié)合pageHelper插件實(shí)現(xiàn)分頁

    SpringBoot整合mybatis結(jié)合pageHelper插件實(shí)現(xiàn)分頁

    在本篇文章里小編給大家整理的是關(guān)于SpringBoot整合mybatis使用pageHelper插件進(jìn)行分頁操作相關(guān)知識點(diǎn),需要的朋友們學(xué)習(xí)下。
    2020-02-02
  • Java和Redis實(shí)現(xiàn)熱搜功能

    Java和Redis實(shí)現(xiàn)熱搜功能

    這篇文章主要介紹了Java和Redis實(shí)現(xiàn)熱搜功能,在存儲和傳輸用戶搜索數(shù)據(jù)時(shí),考慮到數(shù)據(jù)的機(jī)密性和隱私保護(hù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • flink?RichFunction之坑及解決

    flink?RichFunction之坑及解決

    這篇文章主要介紹了flink?RichFunction之坑及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 一個(gè)JAVA小項(xiàng)目--Web應(yīng)用自動(dòng)生成Word

    一個(gè)JAVA小項(xiàng)目--Web應(yīng)用自動(dòng)生成Word

    前段時(shí)間接到一個(gè)Web應(yīng)用自動(dòng)生成Word的需求,現(xiàn)整理了下一些關(guān)鍵步驟拿來分享一下。
    2014-05-05
  • 關(guān)于@Component注解下的類無法@Autowired問題

    關(guān)于@Component注解下的類無法@Autowired問題

    這篇文章主要介紹了關(guān)于@Component注解下的類無法@Autowired問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • idea2023設(shè)置啟動(dòng)參數(shù)、單元測試啟動(dòng)參數(shù)

    idea2023設(shè)置啟動(dòng)參數(shù)、單元測試啟動(dòng)參數(shù)

    在使用IDEA進(jìn)行開發(fā)時(shí),我們可以通過設(shè)置一些啟動(dòng)參數(shù)來優(yōu)化開發(fā)環(huán)境的性能和體驗(yàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-11-11

最新評論