對BeanCopier拷貝對象中List類型屬性的思考

背景

最近開發接口過程中,使用BeanCopier拷貝對象,當對象中嵌套自定義對象類型屬性的時候,
如果對象名稱一致,但是對象類型不一致,拷貝的時候,該屬性是會被忽略的,但是當對象中嵌套List集合類型屬性(集合中是不同的對象類型)時,使用BeanCopier拷貝之後,返回給前臺的數據是正確的,感覺不太懂其中的原理,就測試了下。

測試過程

  1. 新建幾個對象
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ClassA {

    private String id;

    private String name;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ClassB {

    private String id;

    private String name;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class BeanA {

    private String name;

    private List<ClassA> aList;
}F

@Data
@NoArgsConstructor
@AllArgsConstructor
public class BeanA1 {

    private String name;

    private ClassA className;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class BeanB {

    private String name;

    private List<ClassB> aList;
}

Data
@NoArgsConstructor
@AllArgsConstructor
public class BeanB1 {

    private String name;

    private ClassB className;
}
  1. 拷貝BeanA1到BeanB1
public static void main(String[] args) {

    /**
     * 將cglib生成的代理類的class文件打印到指定目錄
     */
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/haiyoung/logs");

    BeanA1 beanA1 = new BeanA1();

    beanA1.setName("aaa");

    beanA1.setClassName(new ClassA("001", "001"));

    BeanB1 beanB1 = new BeanB1();

    BeanCopier beanCopier = BeanCopier.create(BeanA1.class, BeanB1.class,false);

    beanCopier.copy(beanA1, beanB1,null);

    System.out.println(beanB1);

}

轉換結果如下圖所示:對象類型被忽略
image

cglib生成的代理類如下所示

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cglib.empty;

import com.haiyoung.hyweb.beanCopier.BeanA1;
import com.haiyoung.hyweb.beanCopier.BeanB1;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;

public class Object$$BeanCopierByCGLIB$$c00337e1 extends BeanCopier {
    public Object$$BeanCopierByCGLIB$$c00337e1() {
    }

    public void copy(Object var1, Object var2, Converter var3) {
        ((BeanB1)var2).setName(((BeanA1)var1).getName());
    }
}

從copy實現代碼中可以看到,不同對象類型屬性間的拷貝被忽略

  1. 拷貝BeanA到BeanB
public static void main(String[] args) {

        /**
         * 將cglib生成的代理類的class文件打印到指定目錄
         */
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/haiyoung/logs");

        BeanA beanA = new BeanA();

        beanA.setName("aaa");

        List<ClassA> list = new ArrayList<>();
        list.add(new ClassA("001", "001"));

        beanA.setAList(list);

        BeanB beanB = new BeanB();

        BeanCopier beanCopier = BeanCopier.create(BeanA.class, BeanB.class,false);

        beanCopier.copy(beanA, beanB,null);

        System.out.println(beanB);

        List<ClassB> list1 = beanB.getAList();

        System.out.println(list1);

//        ClassB classB = list1.get(0);
//
//        System.out.println(classB);
    }

轉換結果如下圖所示,list對象類型屬性被成功賦值
image
但是對象beanA和benaB中的List屬性,指向相同的引用,當用ClassB接收beanB中的List屬性中的對象時,
會報對象強轉失敗

Exception in thread "main" [ClassA(id=001, name=001)]
java.lang.ClassCastException: com.haiyoung.hyweb.beanCopier.ClassA cannot be cast to com.haiyoung.hyweb.beanCopier.ClassB
	at com.haiyoung.hyweb.beanCopier.CopyTest.main(CopyTest.java:44)

cglib生成的代理類如下所示

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cglib.empty;

import com.haiyoung.hyweb.beanCopier.BeanA;
import com.haiyoung.hyweb.beanCopier.BeanB;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;

public class Object$$BeanCopierByCGLIB$$27129331 extends BeanCopier {
    public Object$$BeanCopierByCGLIB$$27129331() {
    }

    public void copy(Object var1, Object var2, Converter var3) {
        BeanB var10000 = (BeanB)var2;
        BeanA var10001 = (BeanA)var1;
        var10000.setAList(((BeanA)var1).getAList());
        var10000.setName(var10001.getName());
    }
}

從copy的實現代碼中可以看到,兩個對象中的List類型的對象集合屬性被成功賦值,但是是引用賦值

結論

BeanCopier對不同對象中的List對象集合類型的屬性的拷貝是弱拷貝,而不是深拷貝,如果只是做對象拷貝,然後直接拋出這個對象給前臺使用是沒有問題的,但是如果這個通過拷貝得到的對象要在代碼中進行業務流轉,則會報java.lang.ClassCastException 類強轉異常

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章