工具类中自带的BeanUtil.copyProperties只能赋值基本类型的属性。对于复杂类型:如List、Map仍然需要手动赋值。于是乎,自己定义了一个copyProperties工具方法,实现对复杂类型的的赋值。用于实体类与VO对象之间的复制。
实现共定义了四个方法,一个常用类(generalType)集合。除常用类、集合、列表以及数组之外,认为其他类型是自定义类型。
代码:
import java.lang.reflect.*;
import java.util.*;
public final class BeanUtil {
/**
* 定义所有的基本类型及包装类型,或者是String、Date
*/
private static final List<String> generalType = new ArrayList<String>() {{
add(Integer.class.getName());
add(Double.class.getName());
add(Float.class.getName());
add(Long.class.getName());
add(Short.class.getName());
add(Byte.class.getName());
add(Boolean.class.getName());
add(Character.class.getName());
add(String.class.getName());
add(Date.class.getName());
add("int");
add("double");
add("float");
add("long");
add("short");
add("byte");
add("boolean");
add("char");
}};
/**
* 用于两个对象属性名相同之间的复制
*
* 支持字段类型:
* 1. 所有基本类型 ;
* 2. String;
* 3. Date;
* 4. List(允许源对象、目标对象类型不一致,以目标对象为主。抽象类默认为ArrayList);
* 5. Map 其中S,T为基本类型、String、Date、自定义类型,
* 6. Set(允许源对象、目标对象类型不一致,以目标对象为主。抽象类默认为HashSet);
* 7. 自定义对象,包含自己本身,可以实现无限层级复制字段值(最重要的功能)
* 8. 其他未知
*
* @param source 原资源对象
* @param target 目标资源对象
* @param 目标类型
* @param 原资源类型
* @return
*/
public static final <T, S> T copyProperties(S source, T target) {
try {
Class<?> sClass = source.getClass();
Class<?> tClass = target.getClass();
// 如果source为基本类型,直接复制
if (generalType.contains(sClass.getName())) {
target = (T) source;
return target;
}
// 获取所有字段
Field[] fields = sClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field sField = fields[i];
// 获取字段Class
Class<?> sFieldClass = sField.getType();
// 获取字段名
String name = sField.getName();
// 获取字段值
String firstLetter = name.substring(0, 1).toUpperCase();
String getter = "get" + firstLetter + name.substring(1);
// 对象类型使用get方法
Method getMethod = sClass.getDeclaredMethod(getter, new Class[]{});
Object value = getMethod.invoke(source, new Object[]{});
if (value == null) {
// 值为空,跳过
continue;
}
// 获取目标类字段
Field tField;
try{
// 尝试获取属性字段,获取不到不复制
tField = tClass.getDeclaredField(name);
}catch (Exception e){
continue;
}
Class<?> tFieldClass = tField.getType();
String setter = "set" + firstLetter + name.substring(1);
Method setMethod = tClass.getDeclaredMethod(setter, tFieldClass);
if (generalType.contains(sFieldClass.getName())) {
// 基本类型 + String + Date,直接复制值
/**
* 判断源字段属性的类型和目标字段属性类型一致,进行赋值,否则跳过
*/
if (tFieldClass.getName().equals(sFieldClass.getName())) {
setMethod.invoke(target, value);
}
} else if (tFieldClass.isArray()) {
// 数组类型
// 获取数组的Class
Class<?> componentType = tFieldClass.getComponentType();
if (generalType.contains(componentType.getName())) {
// 如果为通用类型数组,进行复制
setMethod.invoke(target, value);
} else {
// 复杂类型使用该方法复制
Object[] arr = (Object[]) value;
Object targetArr = Array.newInstance(componentType, arr.length);
for (int j = 0; j < arr.length; j++) {
Object itemSource = arr[j];
// 定义目标对象
Object itemTarget = componentType.newInstance();
// 复制对象
copyProperties(itemSource, itemTarget);
// 添加到对应数组
Array.set(targetArr, j, itemTarget);
}
// 复制属性
setMethod.invoke(target, targetArr);
}
} else if (List.class.isAssignableFrom(tFieldClass)) {
// 列表类型
// 强转列表值
List listValue = (List) value;
// 获取列表中的泛型
Type genericType = tField.getGenericType();
// 获取类型Class
if (genericType instanceof ParameterizedType) {
ParameterizedType typeCls = (ParameterizedType) genericType;
// 列表中的泛型类型
Class subGenericClass = (Class<?>) typeCls.getActualTypeArguments()[0];
// 最终属性值,默认转成了ArrayList
List targetList = copyList(listValue, subGenericClass);
// 复制属性值
// 如果为抽象类,或者目标类型与源类型相同,直接复制
if (tFieldClass == List.class || tFieldClass == targetList.getClass()) {
// 默认为ArrayList
setMethod.invoke(target, targetList);
} else {
// 其他List
List otherList = (List) tFieldClass.newInstance();
// 转换目标类型列表
targetList.stream().forEach(item -> otherList.add(item));
// 复制
setMethod.invoke(target, otherList);
}
}
} else if (Set.class.isAssignableFrom(tFieldClass)) {
// 列表类型
// 强转列表值
Set listValue = (Set) value;
// 获取列表中的泛型
Type genericType = tField.getGenericType();
// 获取类型Class
if (genericType instanceof ParameterizedType) {
ParameterizedType typeCls = (ParameterizedType) genericType;
// 列表中的泛型类型
Class subGenericClass = (Class<?>) typeCls.getActualTypeArguments()[0];
// 最终属性值,默认转成了ArrayList
Set targetSet = copySet(listValue, subGenericClass);
// 复制属性值
// 如果为抽象类,或者目标类型与源类型相同,直接复制
if (tFieldClass == Set.class || tFieldClass == targetSet.getClass()) {
// 默认为ArrayList
setMethod.invoke(target, targetSet);
} else {
// 其他List
Set otherSet = (Set) tFieldClass.newInstance();
// 转换目标类型列表
targetSet.stream().forEach(item -> otherSet.add(item));
// 复制
setMethod.invoke(target, otherSet);
}
}
} else if (Map.class.isAssignableFrom(tFieldClass)) {
// 集合类型
// 强转集合
Map mapValue = (Map) value;
// key值集合
List keys = new ArrayList(mapValue.keySet());
// value值集合
List values = new ArrayList(mapValue.values());
// 获取列表中的泛型
Type genericType = tField.getGenericType();
// 获取类型Class
if (genericType instanceof ParameterizedType) {
ParameterizedType typeCls = (ParameterizedType) genericType;
// 获取key的类型
Class keyClass = (Class) typeCls.getActualTypeArguments()[0];
// 获取value的类型
Class valueClass = (Class) typeCls.getActualTypeArguments()[1];
// 转换keys集合
List targetKeysList = copyList(keys, keyClass);
// 转换values集合
List targetValuesList = copyList(values, valueClass);
// 实例化map对象
Map targetValue;
try {
// 属性可能使用具体类
targetValue = (Map) tFieldClass.newInstance();
} catch (Exception e) {
// 如果使用抽象类,则使用value值的类型
targetValue = (Map) value.getClass().newInstance();
}
// 转换目标Map集合
for (int j = 0; j < targetKeysList.size(); j++) {
Object targetMapKey = targetKeysList.get(j);
Object targetMapValue = targetValuesList.get(j);
targetValue.put(targetMapKey, targetMapValue);
}
// 复制属性
setMethod.invoke(target, targetValue);
}
} else {
// 自定义对象类型
// 定义目标对象
Object targetValue = tFieldClass.newInstance();
// 复制子属性值
copyProperties(value, targetValue);
// 复制属性值
setMethod.invoke(target, targetValue);
}
}
return target;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 复制集合
* @param source
* @param target
* @param targetClass
* @param
* @param
*/
private static final <T, S> void copyCollection(Collection<S> source, Collection<T> target, Class<T> targetClass) {
source.stream().forEach(item -> {
try {
T t;
// 如果是基本类型
if (generalType.contains(targetClass.getName())) {
target.add((T) item);
} else {
t = targetClass.newInstance();
copyProperties(item, t);
target.add(t);
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
/**
* 实体类与VO对象列表的copy
* 转换后以源列表为主,默认为ArrayList
*
* @param source 数据源列表
* @param targetClass 目标列表中对象类Class
* @param 目标列表类型
* @param 数据源列表类型
* @return
*/
public static final <T, S> List<T> copyList(List<S> source, Class<T> targetClass) {
List<T> target;
try {
if (source.getClass() == List.class || source.getClass() == ArrayList.class) {
target = new ArrayList<>();
} else {
target = source.getClass().newInstance();
}
List<T> finalTarget = target;
copyCollection(source, target, targetClass);
return finalTarget;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 实体类与VO对象Set列表的copy
* 转换后的集合类型以源类型为主,默认为HashSet
*
* @param source 数据源列表
* @param targetClass 目标列表中对象类Class
* @param 目标列表类型
* @param 数据源列表类型
* @return
*/
public static final <T, S> Set<T> copySet(Set<S> source, Class<T> targetClass) {
Set<T> target;
try {
if (source.getClass() == Set.class || source.getClass() == HashSet.class) {
target = new HashSet<>();
} else {
target = source.getClass().newInstance();
}
Set<T> finalTarget = target;
copyCollection(source, target, targetClass);
return finalTarget;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public class Copy {
private Integer a;
private double b;
private String c;
private Date d;
private Test test;
private Test[] tests;
private int[] e;
private LinkedList<Test> f;
private Map<Integer,String> map;
private Map<Test,Test> mapObj;
private Set<Test> setList;
private Copy copy;
// ... get、set、toString 略
}
public class CopyVO {
private Integer a;
private double b;
private String c;
private Date d;
private TestVO test;
private TestVO[] tests;
private int[] e;
private ArrayList<TestVO> f;
private Map<Integer,String> map;
private Map<Test,TestVO> mapObj;
private Set<Test> setList;
private CopyVO copy;
// ... get、set、toString 略
}
public class Test implements Comparable<Test>{
private String name;
public Test() {}
public Test(String name) {
this.name = name;
}
@Override
public int compareTo(Test o) {
return this.name.compareTo(o.name);
}
// ... get、set、toString 略
}
public class TestVO implements Comparable<TestVO>{
private String name;
@Override
public int compareTo(TestVO o) {
return this.name.compareTo(o.name);
}
// ... get、set、toString 略
}
public class Main {
public static void main(String[] args) {
Copy copy = new Copy();
// 基本类型
copy.setA(1);
copy.setB(10.2);
copy.setC("ABC");
copy.setD(new Date());
// 数组
copy.setE(new int[]{10, 20, 30});
// 自定义对象、数组
copy.setTest(new Test("你好"));
copy.setTests(new Test[]{new Test("Hello")});
// 列表
copy.setF(new LinkedList<>(Collections.singletonList(new Test("test"))));
// Set集合
TreeSet treeSet = new TreeSet<Test>();
treeSet.add(new Test("Set集合测试"));
copy.setSetList(treeSet);
// Map集合
Map<Integer, String> map = new HashMap<>();
map.put(200, "OK");
map.put(404, "error");
copy.setMap(map);
// Map集合(key,value为自定义对象)
Map<Test,Test> mapObj = new TreeMap<>();
mapObj.put(new Test("map测试"),new Test("map测试"));
copy.setMapObj(mapObj);
// 对象自己,测试层级关系
Copy subCopy = new Copy();
subCopy.setC("子对象测试");
Copy subSubCopy = new Copy();
subSubCopy.setC("子对象的子对象测试");
subCopy.setCopy(subSubCopy);
copy.setCopy(subCopy);
CopyVO copyVO = new CopyVO();
long start = System.currentTimeMillis();
// 工具包调用复制
BeanUtil.copyProperties(copy, copyVO);
long end = System.currentTimeMillis();
System.out.println(copy);
System.out.println();
System.out.println(copyVO);
System.out.println("耗时:"+(end-start)+" ms");
}
}
结果:
Copy{a=1, b=10.2, c='ABC', d=Fri Jul 08 09:53:54 CST 2022, test=Test{name='你好'}, tests=[Test{name='Hello'}], e=[10, 20, 30], f=[Test{name='test'}], map={404=error, 200=OK}, mapObj={Test{name='map测试'}=Test{name='map测试'}}, setList=[Test{name='Set集合测试'}], copy=Copy{a=null, b=0.0, c='子对象测试', d=null, test=null, tests=null, e=null, f=null, map=null, mapObj=null, setList=null, copy=Copy{a=null, b=0.0, c='子对象的子对象测试', d=null, test=null, tests=null, e=null, f=null, map=null, mapObj=null, setList=null, copy=null}}}
CopyVO{a=1, b=10.2, c='ABC', d=Fri Jul 08 09:53:54 CST 2022, test=TestVO{name='你好'}, tests=[TestVO{name='Hello'}], e=[10, 20, 30], f=[TestVO{name='test'}], map={404=error, 200=OK}, mapObj={Test{name='map测试'}=TestVO{name='map测试'}}, setList=[Test{name='Set集合测试'}], copy=CopyVO{a=null, b=0.0, c='子对象测试', d=null, test=null, tests=null, e=null, f=null, map=null, mapObj=null, setList=null, copy=CopyVO{a=null, b=0.0, c='子对象的子对象测试', d=null, test=null, tests=null, e=null, f=null, map=null, mapObj=null, setList=null, copy=null}}}
耗时:42 ms
对于以上各种类型的测试,测试结果平均耗时仅在50ms左右,还算可观。