spring的BeanUtils屬性copy

1、使用

BeanUtils.copyProperties將一個對象的屬性copy到另外一個對象中。

2、copy的原理是獲取需要copy屬性的屬性描述器(PropertyDescriptor),獲取目標屬性的PropertyDescriptor,並獲取writeMethod,獲取源屬性的readMethod,將readMethod得到的結果(Object)寫入到writeMethod中,所以如果屬性是對象的,寫入的是源對象引用的對象。

源碼如下

private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties) throws BeansException {
        Assert.notNull(source, "Source must not be null");
        Assert.notNull(target, "Target must not be null");
        Class<?> actualEditable = target.getClass();
        if (editable != null) {
            if (!editable.isInstance(target)) {
                throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");
            }

            actualEditable = editable;
        }

        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
        List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
        PropertyDescriptor[] var7 = targetPds;
        int var8 = targetPds.length;

        for(int var9 = 0; var9 < var8; ++var9) {
            PropertyDescriptor targetPd = var7[var9];
            Method writeMethod = targetPd.getWriteMethod();
            if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
                PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
                if (sourcePd != null) {
                    Method readMethod = sourcePd.getReadMethod();
                    if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
                        try {
                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                readMethod.setAccessible(true);
                            }

                            Object value = readMethod.invoke(source);
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }

                            writeMethod.invoke(target, value);
                        } catch (Throwable var15) {
                            throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);
                        }
                    }
                }
            }
        }

    }

我們用一個實際例子

兩個對象Request1,Request2

package local.beancopy;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
 * @author: suntao
 */
@Data
public class Request1 {

    private String request;
    private List<Detail1> detail;

    @Data
    public static class Detail1 {
        private String name;
        private Integer age;
        private Integer sex;
        private BigDecimal income;
    }
}
@Data
public class Request2 {

    private String request;
    private List<Detail2> detail;

    @Data
    public static class Detail2 {
        private String name;
        private Integer age;
        private Integer sex;
        private BigDecimal income;
        private String secondName;
    }
}

Test代碼:

package local.beancopy;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import cn.quantgroup.cashloanflow.util.JsonUtil;
import org.junit.Test;
import org.springframework.beans.BeanUtils;

/**
 * function:
 * date: 2019/12/2
 *
 * @author: suntao
 */
public class BeanUtilCopyTest {

    @Test
    public void testCopy() {
        Request2 request2 = new Request2();
        request2.setRequest("request2");

        List<Request2.Detail2> detail2List = new ArrayList<>();
        for (int i = 0; i < 2; i++) {
            Request2.Detail2 detail2 = new Request2.Detail2();
            detail2.setName("小明");
            detail2.setAge(i + 10);
            detail2.setSex(0);
            detail2.setIncome(new BigDecimal("2220"));
            detail2.setSecondName("fuck you,錯了是 thank you");
            detail2List.add(detail2);
        }

        request2.setDetail(detail2List);

        Request1 request1 = new Request1();

        BeanUtils.copyProperties(request2, request1);

        request2.getDetail().get(0).setSecondName("愛你哦");

        System.out.println(JsonUtil.toJson(request1));

    }
}

打印結果:

{"request":"request2","detail":[{"name":"小明","age":10,"sex":0,"income":2220,"secondName":"愛你哦"},{"name":"小明","age":11,"sex":0,"income":2220,"secondName":"fuck you,錯了是 thank you"}]}

案例的意思是要把Request2的對象copy到Request1的對象中。

但是注意看將Request2的對象copy到Request1的對象後,Request1.detail對象並沒有secondName屬性,這個屬性只有Request2.detail纔有,所以copy是在獲取

request2的detail對象後,通過java反射吧得到Object直接賦值給request1,其繞過了java編譯器,不會報錯。

3、copy執行之後,改變源對象的引用值,copy後的對象也會改變

如上例子

request2.getDetail().get(0).setSecondName("愛你哦");

在copy之後執行。request1.detail的0號元素的secondName已經被改變.

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