前言 這次新建了一個工程,因為 Lombok 用得很習慣,但以前的話,一般只用了@Data,@AllArgsConstructor,@EqualsAndHashCode等常規注解;那這個Accessors(chain = true)注解是干嘛的呢? 用了這個注解后,生成的set方法是這樣的: #加了Accessors(chain = true) public Devolution setCenterId(Long centerId) { this.centerId = centerId; return this; } 注意,正常情況下,方法應該是下面這樣的: #沒加Accessors(chain = true) public void setCenterId(Long centerId) { this.centerId = centerId; } 為什么要用這個方法?主要是方便級聯操作?;谶@個考慮就加了。 加了后,出現了什么問題? 我們之前有個bean拷貝的工具類,用于在 po 和 vo 間拷貝屬性。 import org.springframework.cglib.beans.BeanCopier; public static void copyProperties(Object source,Object target){ BeanCopier copier = getBeanCopier(source.getClass(), target.getClass()); copier.copy(source, target, null); } 結果,同事反映說,當target的類型,加了 Accessors(chain = true)時, 這個工具類不能用了! 跟蹤問題 我本來以為改改spring源碼就可以了,結果發現org.springframework.cglib.beans.BeanCopier 源碼打不開,換了個spring 4的版本,也不行??吹桨锩?,是待了cglib的,于是本地找了個cglib的包,發現是帶source的,于是解壓后導入工程,嗯,還不錯,可以用! 工程代碼在: //gitee.com/ckl111/cglib-lombok-test 我這里先說問題原因: 我找到了一個測試用例,大概如下: public void testSimple() { BeanCopier copier = BeanCopier.create(MA.class, MA.class, false); MA bean1 = new MA(); bean1.setIntP(42); MA bean2 = new MA(); copier.copy(bean1, bean2, null); assertTrue(bean2.getIntP() == 42); } 然后自己改造了一下,加了個類: @Data @Accessors(chain = true) class MaWithLombok { private Long id; private String name; private String privateName; private int intP; private long longP; private boolean booleanP; private char charP; private byte byteP; private short shortP; private float floatP; private double doubleP; private String stringP; public String publicField; } 這里是測試用例: public void testSimpleLombok() { BeanCopier copier = BeanCopier.create(MA.class, MaWithLombok.class, false); MA bean1 = new MA(); bean1.setIntP(42); MaWithLombok bean2 = new MaWithLombok(); copier.copy(bean1, bean2, null); assertTrue(bean2.getIntP() == 42); } 接下來,就是調試了,在不打斷點直接run時,會拋下面異常: java.lang.NullPointerException at net.sf.cglib.core.ReflectUtils.getMethodInfo(ReflectUtils.java:424) at net.sf.cglib.beans.BeanCopier$Generator.generateClass(BeanCopier.java:133) at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216) at net.sf.cglib.beans.BeanCopier$Generator.create(BeanCopier.java:90) at net.sf.cglib.beans.BeanCopier.create(BeanCopier.java:50) at net.sf.cglib.beans.TestBeanCopier.testSimpleLombok(TestBeanCopier.java:38) 打斷點時,發現: 參數member為null,ok,把堆棧退一層(鼠標點到上一層frame) 然后尋找setter的來源: PropertyDescriptor[] setters = ReflectUtils.getBeanGetters(target); 單步調試,會找到這個地方: 這里是進到了jdk的類,這里 java.beans.Introspector#getBeanInfo() private BeanInfo getBeanInfo() throws IntrospectionException { // the evaluation order here is import, as we evaluate the // event sets and locate PropertyChangeListeners before we // look for properties. BeanDescriptor bd = getTargetBeanDescriptor(); MethodDescriptor mds[] = getTargetMethodInfo(); EventSetDescriptor esds[] = getTargetEventInfo(); PropertyDescriptor pds[] = getTargetPropertyInfo();//在這里,獲取目標類的屬性描述符列表 int defaultEvent = getTargetDefaultEventIndex(); int defaultProperty = getTargetDefaultPropertyIndex(); return new GenericBeanInfo(bd, esds, defaultEvent, pds, defaultProperty, mds, explicitBeanInfo); } 我們進入該方法,下圖就能告訴你為什么(java/beans/Introspector.java:520): 原因總結 好了,經過上面的問題,大家能發現,因為我們注解的原因,導致setXXX方法的返回值不為void,所以使用 java.beans.Introspector#getTargetPropertyInfo來獲取 PropertyDescriptor的時候,出現了問題。 問題解決 問題發現了,要怎么解決呢,也簡單,我google了一下,哈哈哈。 參考://github.com/cglib/cglib/issues/108 使用下面這個工具方法即可: org.springframework.beans.BeanUtils.copyProperties(source, target); 我的測試工程在,如果大家需要調試 cglib源碼,也可以看看,里面有很多功能的test用例: //gitee.com/ckl111/cglib-lombok-test
轉載自://www.cnblogs.com/grey-wolf/p/11812528.html
国产无遮挡无码视频在线观看