Lombok注解引发的空指针问题分析
一、问题描述
在一次上线后,日志中出现空指针的报错,但是报错代码位置以及相应工具类未进行过修改,接下来进一步分析。
以下为报错堆栈信息:
java.lang.NullPointerException: null
at net.sf.cglib.core.ReflectUtils.getMethodInfo(ReflectUtils.java:424) ~[cglib-3.1.jar:?]
at net.sf.cglib.beans.BeanCopier$Generator.generateClass(BeanCopier.java:133) ~[cglib-3.1.jar:?]
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) ~[cglib-3.1.jar:?]
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216) ~[cglib-3.1.jar:?]
at net.sf.cglib.beans.BeanCopier$Generator.create(BeanCopier.java:90) ~[cglib-3.1.jar:?]
at net.sf.cglib.beans.BeanCopier.create(BeanCopier.java:50) ~[cglib-3.1.jar:?]
at ***.CglibBeanCopier.copyProperties(CglibBeanCopier.java:90) ~[***.jar:1.2.0]
at ***.CglibBeanCopier.copyProperties(CglibBeanCopier.java:113) ~[***.jar:1.2.0]
at ***.CglibBeanCopier.copyPropertiesOfList(CglibBeanCopier.java:123) ~[***.jar:1.2.0]
..省略
二、问题分析
1.分析链路长,直接抛结论
通过Lombok提供的功能使得我们不必在对象中显式定义get和set方法。并且Lombok提供链式编程,通过在对象头部加上@Accessors(chain = true)注解,给属性赋值时,可以写成obj.setA(a).setB(b).setC(c),省去先new再对属性逐个set赋值。使用了该注解,这个类的set方法返回我就不是void而是this对象本身。
@Accessors(chain = true)
public class YourClass {
private int a;
@Setter
public YourClass setA(int a) {
this.a = a;
return this;
}
}
而JDK Introspector(它为目标JavaBean提供了一种了解原类方法、属性和事件的标准方法)中对写入方法是有特殊判断的,截取Introspector.getBeanInfo(beanClass)中一段源码,只有返回值是void,且方法名以set作为前缀的,才会被当做writeMethod,即写入方法。所以返回值为void且是“set”开头的才是Introspector认为的写入方法,一种狭义的定义。
else if (argCount == 1) {
if (int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, method, null);
} else if (void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {
// Simple setter
pd = new PropertyDescriptor(this.beanClass, name.substring(3), null, method);