该工具类中包括了怎么从泛型类型中通过反射获取泛型类型。
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* ComUtil class
*
* @author xxxxx
* @date 2020.03.10 22:38
*/
public class ComUtil {
/**
* 用于将一个类中具有相同属性名和类型的值拷贝到另一个类中
*
* @param source 被复制属性的类
* @param target 需要获取属性的类
* @throws Exception
*/
public static void copyProperties(Object source, Object target) throws Exception {
if (source == null || target == null) {
throw new Exception("传入的 source 或 target 中有为 null 的对象");
}
// 获取 source 和 target 的属性列表
Field[] sourFields = source.getClass().getDeclaredFields();
Field[] tarFields = target.getClass().getDeclaredFields();
// 将 source 的属性对象为 value,属性名为 key 封装为 map
Map<String, Field> sourFieldMap = new HashMap<>(16);
for (Field sourField : sourFields) {
// 获取属性名
String fieldName = sourField.getName();
sourFieldMap.put(fieldName, sourField);
}
for (Field tarField : tarFields) {
// 获取属性名
String fieldName = tarField.getName();
// 从 sourFieldMap 中通过 fieldName 取值,若能取出表示存在相同的属性名
Field sourField = sourFieldMap.get(fieldName);
if (sourField != null) {
// 获取 List 泛型类型
Class tarGenericClass = getGenericClass(tarField);
Class sourGenericClass = getGenericClass(sourField);
// 获取属性声明的类型 Class 对象
Class<?> sourType = sourField.getType();
Class<?> tarType = tarField.getType();
// 获取权限
sourField.setAccessible(true);
tarField.setAccessible(true);
// 若不是 List 或其父接口类型,为 null
if (tarGenericClass == null && sourGenericClass == null) {
// target 属性类型是 source 属性类型的子类或子接口
if (sourType.isAssignableFrom(tarType)) {
tarField.set(target, sourField.get(source));
}
} else if (tarGenericClass != null && sourGenericClass != null) {
// Iterable 是 List 最顶层接口,在 sourGenericClass 中判断是声明类型是 List 或其父接口
Iterable sourList = (Iterable) sourField.get(source);
if (sourList == null) {
continue;
}
// 该集合用于添加 target 拷贝的对象
List tarList = new ArrayList();
// 遍历 sourList,取出每个泛型对象
for (Object sourObj : sourList) {
// 创建 target List 集合泛型实例
Object tarObj = tarGenericClass.newInstance();
// 递归调用本方法,将相同属性名赋值
copyProperties(sourObj, tarObj);
// 将实例对象添加到集合中
tarList.add(tarObj);
}
// 将集合赋值给 target 同名的属性
tarField.set(target, tarList);
}
}
}
}
/**
* 获取属性类型中的泛型类型,获取泛型的过程适用于其他类型,但是本方法仅适用于 List 集合,
* 并且只有一个泛型的情况,若有需求后续增加功能。
*
* @param field
* @return
* @throws Exception
*/
private static Class getGenericClass(Field field) throws Exception {
// 获取属性声明的类型 Class 对象
Class<?> type = field.getType();
// 判断该 type 是否是 List 或其父接口
if (type.isAssignableFrom(List.class)) {
// 获取该属性声明的类型(Type 接口),getType():是获取属性声明的类型 Class 对象
Type genericType = field.getGenericType();
if (genericType == null) {
return null;
}
// 判断 geneicType 是否是参数化类型,即明确指定泛型的类型,如:java.util.List<java.lang.String>
if (genericType instanceof ParameterizedType) {
//因为 genericType 是 ParameterizedType 的实例,故可以强转
ParameterizedType pt = (ParameterizedType) genericType;
// 获取泛型的类型数组
Type[] genericArgs = pt.getActualTypeArguments();
// 当泛型类型大于 1 个时,抛出异常
if (genericArgs.length > 1) {
throw new Exception(genericType + " " + field.getName() + ": 泛型不只一个无法赋值");
}
// 当只有一个泛型类型时,获取泛型类型
return (Class) genericArgs[0];
}
}
return null;
}
}