使用Cglib的BeanCopier实现Bean的复制

转载于http://czj4451.iteye.com/blog/1998750


cglib是一款比较底层的操作java字节码的框架。

下面通过拷贝bean对象来测试BeanCopier的特性:

Java代码   收藏代码
  1. public class OrderEntity {  
  2.     private int id;  
  3.     private String name;  
  4.     // Getters and setters are omitted  
  5. }  
public class OrderEntity {
    private int id;
    private String name;
    // Getters and setters are omitted
}

Java代码   收藏代码
  1. public class OrderDto {  
  2.     private int id;  
  3.     private String name;  
  4.     // Getters and setters are omitted  
  5. }  
public class OrderDto {
    private int id;
    private String name;
    // Getters and setters are omitted
}

Java代码   收藏代码
  1. public class PropWithDiffType {  
  2.     private Integer id;  
  3.     private String name;  
  4.     // Getters and setters are omitted  
  5. }  
public class PropWithDiffType {
    private Integer id;
    private String name;
    // Getters and setters are omitted
}

Java代码   收藏代码
  1. public class LackOfSetter {  
  2.     private int id;  
  3.     private String name;  
  4.   
  5.     public LackOfSetter() {  
  6.     }  
  7.   
  8.     public LackOfSetter(int id, String name) {  
  9.         this.id = id;  
  10.         this.name = name;  
  11.     }  
  12.     // Getters and setters are omitted  
  13.     // public void setName(String name) {  
  14.     //  this.name = name;  
  15.     // }  
  16. }  
public class LackOfSetter {
    private int id;
    private String name;

    public LackOfSetter() {
    }

    public LackOfSetter(int id, String name) {
        this.id = id;
        this.name = name;
    }
    // Getters and setters are omitted
    // public void setName(String name) {
    //  this.name = name;
    // }
}


1. 属性名称、类型都相同:
Java代码   收藏代码
  1. @Test  
  2. public void normalCopyTest() {  
  3.     OrderEntity entity = new OrderEntity();  
  4.     entity.setId(1);  
  5.     entity.setName(”orderName”);  
  6.     final BeanCopier copier = BeanCopier.create(OrderEntity.class, OrderDto.classfalse);  
  7.     OrderDto dto = new OrderDto();  
  8.     copier.copy(entity, dto, null);  
  9.     Assert.assertEquals(1, dto.getId());  
  10.     Assert.assertEquals(”orderName”, dto.getName());  
  11. }  
@Test
public void normalCopyTest() {
    OrderEntity entity = new OrderEntity();
    entity.setId(1);
    entity.setName("orderName");
    final BeanCopier copier = BeanCopier.create(OrderEntity.class, OrderDto.class, false);
    OrderDto dto = new OrderDto();
    copier.copy(entity, dto, null);
    Assert.assertEquals(1, dto.getId());
    Assert.assertEquals("orderName", dto.getName());
}

结论:拷贝OK。

2. 属性名称相同、类型不同:

Java代码   收藏代码
  1. @Test  
  2. public void sameNameDifferentTypeCopyTest() {  
  3.     OrderEntity entity = new OrderEntity();  
  4.     entity.setId(1);  
  5.     entity.setName(”orderName”);  
  6.     final BeanCopier copier = BeanCopier.create(OrderEntity.class, PropWithDiffType.classfalse);  
  7.     PropWithDiffType dto = new PropWithDiffType();  
  8.     copier.copy(entity, dto, null);  
  9.     Assert.assertEquals(null, dto.getId()); // OrderEntity的id为int类型,而PropWithDiffType的id为Integer类型,不拷贝  
  10.     Assert.assertEquals(”orderName”, dto.getName());  
  11. }  
@Test
public void sameNameDifferentTypeCopyTest() {
    OrderEntity entity = new OrderEntity();
    entity.setId(1);
    entity.setName("orderName");
    final BeanCopier copier = BeanCopier.create(OrderEntity.class, PropWithDiffType.class, false);
    PropWithDiffType dto = new PropWithDiffType();
    copier.copy(entity, dto, null);
    Assert.assertEquals(null, dto.getId()); // OrderEntity的id为int类型,而PropWithDiffType的id为Integer类型,不拷贝
    Assert.assertEquals("orderName", dto.getName());
}

结论:名称相同而类型不同的属性不会被拷贝。

注意:即使源类型是 原始类型(int, short和char等),目标类型是其 包装类型(Integer, Short和Character等),或反之:都 不会被拷贝。

3. 源类和目标类有相同的属性(两者的getter都存在),但目标类的setter不存在
Java代码   收藏代码
  1. @Test  
  2. public void targetLackOfSetterCopyTest() {  
  3.     OrderEntity entity = new OrderEntity();  
  4.     entity.setId(1);  
  5.     entity.setName(”orderName”);  
  6.     final BeanCopier copier = BeanCopier.create(OrderEntity.class, LackOfSetter.classfalse);  // 抛NullPointerException  
  7.     LackOfSetter dto = new LackOfSetter();  
  8.     copier.copy(entity, dto, null);  
  9. }  
@Test
public void targetLackOfSetterCopyTest() {
    OrderEntity entity = new OrderEntity();
    entity.setId(1);
    entity.setName("orderName");
    final BeanCopier copier = BeanCopier.create(OrderEntity.class, LackOfSetter.class, false);  // 抛NullPointerException
    LackOfSetter dto = new LackOfSetter();
    copier.copy(entity, dto, null);
}

结论:创建BeanCopier的时候抛异常。

导致异常的原因是BeanCopier类的第128~133行
Java代码   收藏代码
  1. for (int i = 0; i < setters.length; i++) { // 遍历目标类的属性描述集  
  2.     PropertyDescriptor setter = setters[i];  
  3.     PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName()); // 从源类获取和目标类属性名称相同的属性描述  
  4.     if (getter != null) {  
  5.         MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod()); // 获取源类属性的getter方法  
  6.         MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod()); // 获取目标类属性的setter方法。LackOfSetter类name属性的setter方法没有,所以报错  
            for (int i = 0; i < setters.length; i++) { // 遍历目标类的属性描述集
                PropertyDescriptor setter = setters[i];
                PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName()); // 从源类获取和目标类属性名称相同的属性描述
                if (getter != null) {
                    MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod()); // 获取源类属性的getter方法
                    MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod()); // 获取目标类属性的setter方法。LackOfSetter类name属性的setter方法没有,所以报错


4. 源类或目标类的setter比getter少
Java代码   收藏代码
  1. @Test  
  2. public void sourceLackOfSetterCopyTest() {  
  3.     LackOfSetter source = new LackOfSetter(1“throne”);  
  4.     final BeanCopier copier = BeanCopier.create(LackOfSetter.class, OrderDto.classfalse);  
  5.     OrderDto dto = new OrderDto();  
  6.     copier.copy(source, dto, null);  
  7.     Assert.assertEquals(1, dto.getId());  
  8.     Assert.assertEquals(”throne”, dto.getName());  
  9. }  
@Test
public void sourceLackOfSetterCopyTest() {
    LackOfSetter source = new LackOfSetter(1, "throne");
    final BeanCopier copier = BeanCopier.create(LackOfSetter.class, OrderDto.class, false);
    OrderDto dto = new OrderDto();
    copier.copy(source, dto, null);
    Assert.assertEquals(1, dto.getId());
    Assert.assertEquals("throne", dto.getName());
}

结论:拷贝OK。此时的setter多余,但不会报错。

总结:

1. BeanCopier只拷贝名称和类型都相同的属性。

2. 当目标类的setter数目比getter少时,创建BeanCopier会失败而导致拷贝不成功。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
CGLIB是一个强大的代码生成库,可以在运行时扩展Java实现Java接口。它广泛用于许多框架和库中,例如Spring、Hibernate等。下面是一个简单的CGLIB代码实现示例: 1. 首先,我们需要添加CGLIB的依赖项,例如Maven中的以下代码: ```xml <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> ``` 2. 然后,我们需要创建一个目标,它将在运行时被扩展: ```java public class Target { public void sayHello() { System.out.println("Hello, world!"); } } ``` 3. 接下来,我们需要创建一个代理,它将在运行时扩展目标: ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class TargetProxy implements MethodInterceptor { private Object target; public TargetProxy(Object target) { this.target = target; } public Object createProxy() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before method " + method.getName() + " is called."); Object result = proxy.invoke(target, args); System.out.println("After method " + method.getName() + " is called."); return result; } } ``` 4. 最后,我们可以使用代理来扩展目标: ```java public class Main { public static void main(String[] args) { Target target = new Target(); Target proxy = (Target) new TargetProxy(target).createProxy(); proxy.sayHello(); } } ``` 运行程序,输出结果如下: ``` Before method sayHello is called. Hello, world! After method sayHello is called. ``` 在这个示例中,我们使用CGLIB创建了一个代理,该代理扩展了目标并在目标方法调用前后添加了额外的逻辑。CGLIB可以帮助我们轻松地扩展Java和接口,使其更加灵活和可扩展。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值