序言

去年在项目当中引入了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

解决方案

修改属性名字,让第二个字母小写,或者说是规定所有的属性的前两个字母必须小写

如果数据库已经设计好,并且前后端接口对接好了,不想修改,那就专门为这种特殊的属性使用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);

}

}

解决方案

去掉Accessor注解

要么就等待easyexcel的作者替换掉底层的cglib或者是其他,反正是支持获取返回值不是void的setxxx方法就行复制代码

java if (name!=null name!=),命名不规范,lombok泪两行!相关推荐

  1. 后端技术:命名不规范,lombok泪两行!

    序言 去年在项目当中引入了Lombok插件,着实解放了双手,代替了一些重复的简单工作(Getter,Setter,toString等方法的编写). 但是,在使用的过程当中,也发现了一些坑,开始的时候并 ...

  2. java 返回空数组_避免在Java中检查Null语句

    1.概述 通常,在Java代码中处理null变量.引用和集合很棘手.它们不仅难以识别,而且处理起来也很复杂.事实上,在编译时无法识别处理null的任何错误,会导致运行时NullPointerExcep ...

  3. java编译器代码检查_java 命名代码检查-注解处理器

    命名代码检查 根据 中第6.8节的要求, Java 程序命名应当符合下列格式的书写规范: 类 ( 或接口 ) : 符合驼式命名法, 首字母大写. 方法 : 符合驼式命名法,首字母小写 字段 :类或实例 ...

  4. Java 语法规定之外的命名注释规范

    Java 语法规定之外的命名注释规范 命名规范 1. 项目名 2. 包名 3. 类名 4. 常量名 5. 变量名 6. 方法名 8. 其它命名技巧 9. 应当避免的行为 10. 经典的命名法 11. ...

  5. java 删除二维数组中的null_避免在Java中检查Null语句

    1.概述 通常,在Java代码中处理null变量.引用和集合很棘手.它们不仅难以识别,而且处理起来也很复杂.事实上,在编译时无法识别处理null的任何错误,会导致运行时NullPointerExcep ...

  6. java 字符串转骆驼命名_程序员必知的Java基础:5条命名规范和8种数据类型归纳...

    原标题:程序员必知的Java基础:5条命名规范和8种数据类型归纳 一.Java命名规范 任何一种语言都有一套针对于语言自身的命名的规范,java也不例外.接下来,我就列举一下java对命名的规范. 下 ...

  7. 科学处理java.lang.StackOverflowError: null异常

    java.lang.StackOverflowError: null异常处理 在项目运行中出现StackOverflowError 首先要检查在编码中是否有明显的递归编码,比如死循环或者无限循环调用. ...

  8. Java中有关Null的9件事

    对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常(NPE)的骚扰.连Java的发明者都承认这是他的一项巨大失误.Java为什么要保留null呢?null出现有一段时间了,并且我认 ...

  9. 轻松搞定项目中的空指针异常Caused by: java.lang.NullPointerException: null

    轻松搞定项目中的空指针异常Caused by: java.lang.NullPointerException: null 参考文章: (1)轻松搞定项目中的空指针异常Caused by: java.l ...

最新文章

  1. Excel如何快速将科学计数法数字变成正常形式
  2. 查看安装的react-native和react版本
  3. 微博“异地多活”部署经验谈
  4. 【Virtual DOM】虚拟 DOM 和 Snabbdom 库
  5. 计算机考研专业基础知识视频教程链接
  6. 51 nod 1405 树的距离之和
  7. 去除Vue在WebStorm中报命名空间的错误
  8. pid调节软件_三面大疆惨败,因为不懂PID的积分抗饱和
  9. 路由器防御Dos***方法
  10. 人工智能:模型与算法2搜索求解之启发式搜索
  11. 深入浅出理解输入输出阻抗-音频电路输入输出阻抗
  12. CentOS7 wifi安装配置问题总结
  13. mplayer播放器管道重构版
  14. diy无感无刷电机霍尔安装_无刷直流电机霍尔传感器安装方法研究
  15. rmf 文件如何打开?
  16. 运筹学研究者关注的Github和CSDN账号
  17. iuv_5g组网问题表
  18. 头铁!我就硬钢算法岗!
  19. html中移动端遮罩层,移动端微信分享弹出遮罩层js效果_蓝戒的博客
  20. MinGW基本情况介绍

热门文章

  1. Pytorch nn.init 参数初始化方法
  2. python 列表生成式、lower()和upper()的使用
  3. TVM部署预定义模型
  4. 什么阻碍了人工智能在制造业的应用?
  5. CVPR2020:三维实例分割与目标检测
  6. 2021年大数据Flink(三十八):​​​​​​​Table与SQL ​​​​​​案例五 FlinkSQL整合Hive
  7. Cocos Creator 音频文件Audio的绑定与使用(TypeScript)
  8. Python 赋值运算符
  9. RxJava 变换操作符Map
  10. java.lang.ClassNotFoundException: Didn't find class org.apache.http.Protoco