Browse Source

add getActualTypeMap

Looly 5 years ago
parent
commit
dba35b9395

+ 1 - 0
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)

+ 13 - 11
hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java

@@ -244,25 +244,27 @@ public class BeanCopier<T> implements Copier<T>, 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<T> 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;// 当允许跳过空时,跳过
 			}

+ 35 - 18
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} 的工具类封装<br>
@@ -267,25 +266,23 @@ public class TypeUtil {
 		}
 		return result;
 	}
-	
+
 	/**
-	 * 获取指定泛型变量对应的真实类型<br>
+	 * 获取泛型变量和真实类型的对应表,使用{@link TableMap}表示,key不会重复<br>
 	 * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型<br>
 	 * 使用此方法注意:
-	 * 
+	 *
 	 * <pre>
-	 * 1. superClass必须是clazz的父类或者clazz实现的接口
-	 * 2. typeVariable必须在superClass中声明
+	 * 1. typeDefineClass必须是clazz的父类或者clazz实现的接口
 	 * </pre>
-	 * 
-	 * 
+	 *
+	 *
 	 * @param actualType 真实类型所在类,此类中记录了泛型参数对应的实际类型
 	 * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型
-	 * @param typeVariables 泛型变量,需要的实际类型对应的泛型参数
 	 * @return 给定泛型参数对应的实际类型,如果无对应类型,返回null
-	 * @since 4.5.7
+	 * @since 5.4.1
 	 */
-	public static Type[] getActualTypes(Type actualType, Class<?> typeDefineClass, Type... typeVariables) {
+	public static TableMap<TypeVariable<?>, Type> getActualTypeMap(Type actualType, Class<?> typeDefineClass) {
 		if (false == typeDefineClass.isAssignableFrom(getClass(actualType))) {
 			throw new IllegalArgumentException("Parameter [superClass] must be assignable from [clazz]");
 		}
@@ -293,19 +290,39 @@ public class TypeUtil {
 		// 泛型参数标识符列表
 		final TypeVariable<?>[] typeVars = typeDefineClass.getTypeParameters();
 		if(ArrayUtil.isEmpty(typeVars)) {
-			return null;
+			return new TableMap<>(0);
 		}
 		// 实际类型列表
 		final Type[] actualTypeArguments = TypeUtil.getTypeArguments(actualType);
 		if(ArrayUtil.isEmpty(actualTypeArguments)) {
-			return null;
+			return new TableMap<>(0);
 		}
-		
-		int size = Math.min(actualTypeArguments.length, typeVars.length);
-		final Map<TypeVariable<?>, Type> tableMap = new TableMap<>(typeVars, actualTypeArguments);
-		
+
+		return new TableMap<>(typeVars, actualTypeArguments);
+	}
+	
+	/**
+	 * 获取指定泛型变量对应的真实类型<br>
+	 * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型<br>
+	 * 使用此方法注意:
+	 * 
+	 * <pre>
+	 * 1. superClass必须是clazz的父类或者clazz实现的接口
+	 * 2. typeVariable必须在superClass中声明
+	 * </pre>
+	 * 
+	 * 
+	 * @param actualType 真实类型所在类,此类中记录了泛型参数对应的实际类型
+	 * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型
+	 * @param typeVariables 泛型变量,需要的实际类型对应的泛型参数
+	 * @return 给定泛型参数对应的实际类型,如果无对应类型,返回null
+	 * @since 4.5.7
+	 */
+	public static Type[] getActualTypes(Type actualType, Class<?> typeDefineClass, Type... typeVariables) {
+		final TableMap<TypeVariable<?>, Type> tableMap = getActualTypeMap(actualType, typeDefineClass);
+
 		// 查找方法定义所在类或接口中此泛型参数的位置
-		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];

+ 5 - 0
hutool-core/src/test/java/cn/hutool/core/util/TypeUtilTest.java

@@ -57,4 +57,9 @@ public class TypeUtilTest {
 		}
 	}
 
+	@Test
+	public void getActualTypesTest(){
+
+	}
+
 }