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已經被改變.