最近项目中使用了BeanCopier,但是使用过程中,存在有些数据无法拷贝成功的情况,故特地进行了整理。
1. 素材准备
对象A,A1,A2表示源对象,B,B1,B2表示目标对象。
A1,B1表示嵌套对象的场景
A2,B2表示嵌套集合的场景
示例如下:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class A {
private String name;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class A1 {
private long id;
private A a;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class A2 {
private long id;
private List<A> list;
}
@Data
public class B {
private String name;
private int age;
}
@Data
public class B1 {
private long id;
private B a;
}
@Data
public class B2 {
private long id;
private List<B> list;
}
public class Solution {
public static void main(String[] args) {
// 此处设置生成的代理对象路径
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\logs");
A a = new A("测试A");
List<A> list = new ArrayList<>();
list.add(a);
A1 a1 = new A1(1,a);
A2 a2 = new A2(2,list);
// 包含对象
BeanCopier copier = BeanCopier.create(A1.class, B1.class,false);
B1 b1 = new B1();
copier.copy(a1, b1,null);
System.out.println(JSON.toJSON(b1));
// 包含List
BeanCopier copier1 = BeanCopier.create(A2.class, B2.class,false);
B2 b2 = new B2();
copier1.copy(a2, b2,null);
// b2.getList().get(0).setAge(22);
System.out.println(JSON.toJSON(b2));
}
}
2.执行分析
执行完上文的main方法,进入上文设置的目录,可以发现生成了三个文件class,其中一个是BeanCopierKey文件,这里不关心。主要看下另外的文件。
一个对应嵌套对象的场景,如下:
public class Object$$BeanCopierByCGLIB$$e225ae67 extends BeanCopier {
public Object$$BeanCopierByCGLIB$$e225ae67() {
}
public void copy(Object var1, Object var2, Converter var3) {
// 这里只进行基本属性设置,嵌套对象未设置
((B1)var2).setId(((A1)var1).getId());
}
}
一个对应嵌套List的场景,如下:
public class Object$$BeanCopierByCGLIB$$d653fb7d extends BeanCopier {
public Object$$BeanCopierByCGLIB$$d653fb7d() {
}
public void copy(Object var1, Object var2, Converter var3) {
B2 var10000 = (B2)var2;
A2 var10001 = (A2)var1;
var10000.setId(((A2)var1).getId());
// 这里List使用了相同的引用
var10000.setList(var10001.getList());
}
}
从这两个类文件可以很直观看出,BeanCopier是通过生成代理对象,进行了set/get操作。
放开上文中的 如下注释,再次Debug运行
// b2.getList().get(0).setAge(22);
运行到b2.getList().get(0).setAge(22)处, 会抛出类型转换异常:
Exception in thread "main" java.lang.ClassCastException
3. 结论
- BeanCopier拷贝基本属性是以属性名进行设置的
- BeanCopier拷贝嵌套对象不会进行设置,即使属性名称一致
- BeanCopier拷贝集合对象使用了相同引用,故而拷贝之后对集合数据进行set操作,会报类型转换错误。