diff --git a/CHANGELOG.md b/CHANGELOG.md index d5e4425ad..075c4607e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ * 【core 】 EnumUtil.getEnumAt负数返回null(pr#167@Gitee) * 【core 】 ChineseDate增加天干地支和转换为公历方法(pr#169@Gitee) * 【core 】 Img增加stroke描边方法(issue#1033@Github) +* 【core 】 TypeUtil增加getActualTypeMap方法 ### Bug修复# * 【poi 】 修复ExcelBase.isXlsx方法判断问题(issue#I1S502@Gitee) diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java index d1420333a..922ab0f85 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java @@ -244,25 +244,27 @@ public class BeanCopier implements Copier, Serializable { continue; } - Type valueType = (null == setterMethod) ? TypeUtil.getType(field) : TypeUtil.getFirstParamType(setterMethod); - if (valueType instanceof ParameterizedType) { - // 参数为泛型参数类型,解析对应泛型类型为真实类型 - ParameterizedType tmp = (ParameterizedType) valueType; - Type[] actualTypeArguments = tmp.getActualTypeArguments(); + // 获取目标字段真实类型 + Type fieldType = (null == setterMethod) ? TypeUtil.getType(field) : TypeUtil.getFirstParamType(setterMethod); + if (fieldType instanceof ParameterizedType) { + // 字段类型为泛型参数类型,解析对应泛型类型为真实类型,类似于List a + final ParameterizedType fieldParameterizedType = (ParameterizedType) fieldType; + Type[] actualTypeArguments = fieldParameterizedType.getActualTypeArguments(); if (TypeUtil.hasTypeVeriable(actualTypeArguments)) { // 泛型对象中含有未被转换的泛型变量 - actualTypeArguments = TypeUtil.getActualTypes(this.destType, field.getDeclaringClass(), tmp.getActualTypeArguments()); + actualTypeArguments = TypeUtil.getActualTypes(this.destType, field.getDeclaringClass(), fieldParameterizedType.getActualTypeArguments()); if (ArrayUtil.isNotEmpty(actualTypeArguments)) { // 替换泛型变量为实际类型 - valueType = new ParameterizedTypeImpl(actualTypeArguments, tmp.getOwnerType(), tmp.getRawType()); + fieldType = new ParameterizedTypeImpl(actualTypeArguments, fieldParameterizedType.getOwnerType(), fieldParameterizedType.getRawType()); } } - } else if (valueType instanceof TypeVariable) { - // 参数为泛型,查找其真实类型(适用于泛型方法定义于泛型父类) - valueType = TypeUtil.getActualType(this.destType, field.getDeclaringClass(), valueType); + } else if (fieldType instanceof TypeVariable) { + // 字段类型为泛型,查找其真实类型(适用于泛型方法定义于泛型父类),类似于T a + fieldType = TypeUtil.getActualType(this.destType, field.getDeclaringClass(), fieldType); } - value = valueProvider.value(providerKey, valueType); + // + value = valueProvider.value(providerKey, fieldType); if (null == value && copyOptions.ignoreNullValue) { continue;// 当允许跳过空时,跳过 } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java index a4b3eb549..4ba886fff 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java @@ -8,7 +8,6 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; -import java.util.Map; /** * 针对 {@link Type} 的工具类封装
@@ -267,6 +266,40 @@ public class TypeUtil { } return result; } + + /** + * 获取泛型变量和真实类型的对应表,使用{@link TableMap}表示,key不会重复
+ * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型
+ * 使用此方法注意: + * + *
+	 * 1. typeDefineClass必须是clazz的父类或者clazz实现的接口
+	 * 
+ * + * + * @param actualType 真实类型所在类,此类中记录了泛型参数对应的实际类型 + * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型 + * @return 给定泛型参数对应的实际类型,如果无对应类型,返回null + * @since 5.4.1 + */ + public static TableMap, Type> getActualTypeMap(Type actualType, Class typeDefineClass) { + if (false == typeDefineClass.isAssignableFrom(getClass(actualType))) { + throw new IllegalArgumentException("Parameter [superClass] must be assignable from [clazz]"); + } + + // 泛型参数标识符列表 + final TypeVariable[] typeVars = typeDefineClass.getTypeParameters(); + if(ArrayUtil.isEmpty(typeVars)) { + return new TableMap<>(0); + } + // 实际类型列表 + final Type[] actualTypeArguments = TypeUtil.getTypeArguments(actualType); + if(ArrayUtil.isEmpty(actualTypeArguments)) { + return new TableMap<>(0); + } + + return new TableMap<>(typeVars, actualTypeArguments); + } /** * 获取指定泛型变量对应的真实类型
@@ -286,26 +319,10 @@ public class TypeUtil { * @since 4.5.7 */ public static Type[] getActualTypes(Type actualType, Class typeDefineClass, Type... typeVariables) { - if (false == typeDefineClass.isAssignableFrom(getClass(actualType))) { - throw new IllegalArgumentException("Parameter [superClass] must be assignable from [clazz]"); - } + final TableMap, Type> tableMap = getActualTypeMap(actualType, typeDefineClass); - // 泛型参数标识符列表 - final TypeVariable[] typeVars = typeDefineClass.getTypeParameters(); - if(ArrayUtil.isEmpty(typeVars)) { - return null; - } - // 实际类型列表 - final Type[] actualTypeArguments = TypeUtil.getTypeArguments(actualType); - if(ArrayUtil.isEmpty(actualTypeArguments)) { - return null; - } - - int size = Math.min(actualTypeArguments.length, typeVars.length); - final Map, Type> tableMap = new TableMap<>(typeVars, actualTypeArguments); - // 查找方法定义所在类或接口中此泛型参数的位置 - final Type[] result = new Type[size]; + final Type[] result = new Type[typeVariables.length]; for(int i = 0; i < typeVariables.length; i++) { //noinspection SuspiciousMethodCalls result[i] = (typeVariables[i] instanceof TypeVariable) ? tableMap.get(typeVariables[i]) : typeVariables[i]; diff --git a/hutool-core/src/test/java/cn/hutool/core/util/TypeUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/TypeUtilTest.java index 6b7cd97ec..849b09b14 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/TypeUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/TypeUtilTest.java @@ -57,4 +57,9 @@ public class TypeUtilTest { } } + @Test + public void getActualTypesTest(){ + + } + }