最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Lombok的坑

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

序言

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

Setter-Getter方法的坑

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

我們?cè)陧?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ù)庫(kù)一直是null.

解決

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

原因

Lombok對(duì)于第一個(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è)(索引)開始截取(簡(jiǎn)單粗暴)
     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
      //    對(duì)于屬性只有一個(gè)字母的,例如private int x;
      //     對(duì)應(yīng)的get-set方法是getX();setX(int x);
      //第二句話:name.length() > 1 && !Character.isUpperCase(name.charAt(1)))
      //   屬性名字長(zhǎng)度大于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方法為屬性名字測(cè)試

  @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ù)庫(kù)已經(jīng)設(shè)計(jì)好,并且前后端接口對(duì)接好了,不想修改,那就專門為這種特殊的屬性使用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í)體類不正常了,比對(duì)了發(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

南江县| 衡水市| 汶上县| 吴江市| 页游| 青州市| 双城市| 太原市| 石景山区| 东阳市| 松阳县| 特克斯县| 剑河县| 来凤县| 家居| 正蓝旗| 广昌县| 左云县| 六盘水市| 勐海县| 万载县| 鹤峰县| 灵川县| 阿鲁科尔沁旗| 汉寿县| 梁山县| 乌审旗| 曲靖市| 祁连县| 杂多县| 从化市| 武宣县| 合阳县| 无棣县| 綦江县| 黔西| 广平县| 房山区| 太仆寺旗| 梅河口市| 丽江市|