网站开发是什么,网站建设能赚很多钱,浏览器打不开wordpress,wordpress 安装后空白来源#xff1a;juejin.im/post/6881432532332576781序言去年在项目当中引入了Lombok插件#xff0c;着实解放了双手#xff0c;代替了一些重复的简单工作(Getter,Setter,toString等方法的编写)#xff0c;但是#xff0c;在使用的过程当中#xff0c;也发现了一些坑juejin.im/post/6881432532332576781序言去年在项目当中引入了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方法也是大写}
}#ideaMybatisJava官方默认的行为为
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 . Didnt 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是大写的那就直接返回nameif (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(https://github.com/alibaba/easyexcel) 导出的时候发现以前的实体类导出都很正常但是现在新加的实体类不正常了比对了发现新加的实体类增加了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 setterpd 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中不可或缺的59个小技巧贼好用2万字长文包教包会 JVM 内存结构2万字看完这篇才敢说自己真的懂线程池关注我每天陪你进步一点点