Looly 5 years ago
parent
commit
cbbf4671ba

+ 5 - 4
CHANGELOG.md

@@ -3,7 +3,7 @@
 
 -------------------------------------------------------------------------------------------------------------
 
-# 5.4.2 (2020-09-03)
+# 5.4.2 (2020-09-05)
 
 ### 新特性
 * 【core  】     lock放在try外边(pr#1050@Github)
@@ -14,11 +14,13 @@
 * 【poi   】     RowUtil增加插入和删除行(pr#1060@Github)
 * 【extra 】     SpringUtil增加注册bean(pr#174@Gitee)
 * 【core  】     修改NetUtil.getMacAddress避免空指针(issue#1057@Github)
-* 【core  】     增加EnumItem接口,枚举扩展转换,增加SPI自定义转换(pr#173@Gitee)
+* 【core  】     增加EnumItem接口,枚举扩展转换,增加SPI自定义转换(pr#173@Github)
+* 【core  】     TypeUtil增加getActualTypeMap方法
 
-### Bug修复#
+### Bug修复
 * 【core  】     重新整理农历节假日,解决一个pr过来的玩笑导致的问题
 * 【poi   】     修复ExcelFileUtil.isXls判断问题(pr#1055@Github)
+* 【poi   】     修复CglibUtil.copyList参数错误导致的问题
 
 -------------------------------------------------------------------------------------------------------------
 
@@ -40,7 +42,6 @@
 * 【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)

+ 58 - 46
hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java

@@ -12,12 +12,12 @@ import java.lang.reflect.WildcardType;
 /**
  * 针对 {@link Type} 的工具类封装<br>
  * 最主要功能包括:
- * 
+ *
  * <pre>
  * 1. 获取方法的参数和返回值类型(包括Type和Class)
  * 2. 获取泛型参数类型(包括对象的泛型参数或集合元素的泛型类型)
  * </pre>
- * 
+ *
  * @author Looly
  * @since 3.0.8
  */
@@ -25,7 +25,7 @@ public class TypeUtil {
 
 	/**
 	 * 获得Type对应的原始类
-	 * 
+	 *
 	 * @param type {@link Type}
 	 * @return 原始类,如果无法获取原始类,返回{@code null}
 	 */
@@ -50,7 +50,7 @@ public class TypeUtil {
 	/**
 	 * 获取字段对应的Type类型<br>
 	 * 方法优先获取GenericType,获取不到则获取Type
-	 * 
+	 *
 	 * @param field 字段
 	 * @return {@link Type},可能为{@code null}
 	 */
@@ -62,8 +62,20 @@ public class TypeUtil {
 	}
 
 	/**
+	 * 获得字段的泛型类型
+	 *
+	 * @param clazz     Bean类
+	 * @param fieldName 字段名
+	 * @return 字段的泛型类型
+	 * @since 5.4.2
+	 */
+	public static Type getFieldType(Class<?> clazz, String fieldName) {
+		return getType(ReflectUtil.getField(clazz, fieldName));
+	}
+
+	/**
 	 * 获得Field对应的原始类
-	 * 
+	 *
 	 * @param field {@link Field}
 	 * @return 原始类,如果无法获取原始类,返回{@code null}
 	 * @since 3.1.2
@@ -73,10 +85,11 @@ public class TypeUtil {
 	}
 
 	// ----------------------------------------------------------------------------------- Param Type
+
 	/**
 	 * 获取方法的第一个参数类型<br>
 	 * 优先获取方法的GenericParameterTypes,如果获取不到,则获取ParameterTypes
-	 * 
+	 *
 	 * @param method 方法
 	 * @return {@link Type},可能为{@code null}
 	 * @since 3.1.2
@@ -87,7 +100,7 @@ public class TypeUtil {
 
 	/**
 	 * 获取方法的第一个参数类
-	 * 
+	 *
 	 * @param method 方法
 	 * @return 第一个参数类型,可能为{@code null}
 	 * @since 3.1.2
@@ -99,9 +112,9 @@ public class TypeUtil {
 	/**
 	 * 获取方法的参数类型<br>
 	 * 优先获取方法的GenericParameterTypes,如果获取不到,则获取ParameterTypes
-	 * 
+	 *
 	 * @param method 方法
-	 * @param index 第几个参数的索引,从0开始计数
+	 * @param index  第几个参数的索引,从0开始计数
 	 * @return {@link Type},可能为{@code null}
 	 */
 	public static Type getParamType(Method method, int index) {
@@ -114,9 +127,9 @@ public class TypeUtil {
 
 	/**
 	 * 获取方法的参数类
-	 * 
+	 *
 	 * @param method 方法
-	 * @param index 第几个参数的索引,从0开始计数
+	 * @param index  第几个参数的索引,从0开始计数
 	 * @return 参数类,可能为{@code null}
 	 * @since 3.1.2
 	 */
@@ -131,7 +144,7 @@ public class TypeUtil {
 	/**
 	 * 获取方法的参数类型列表<br>
 	 * 优先获取方法的GenericParameterTypes,如果获取不到,则获取ParameterTypes
-	 * 
+	 *
 	 * @param method 方法
 	 * @return {@link Type}列表,可能为{@code null}
 	 * @see Method#getGenericParameterTypes()
@@ -147,7 +160,6 @@ public class TypeUtil {
 	 *
 	 * @param method t方法
 	 * @return 参数类型类列表
-	 *
 	 * @see Method#getGenericParameterTypes
 	 * @see Method#getParameterTypes
 	 * @since 3.1.2
@@ -157,10 +169,11 @@ public class TypeUtil {
 	}
 
 	// ----------------------------------------------------------------------------------- Return Type
+
 	/**
 	 * 获取方法的返回值类型<br>
 	 * 获取方法的GenericReturnType
-	 * 
+	 *
 	 * @param method 方法
 	 * @return {@link Type},可能为{@code null}
 	 * @see Method#getGenericReturnType()
@@ -184,9 +197,10 @@ public class TypeUtil {
 	}
 
 	// ----------------------------------------------------------------------------------- Type Argument
+
 	/**
 	 * 获得给定类的第一个泛型参数
-	 * 
+	 *
 	 * @param type 被检查的类型,必须是已经确定泛型类型的类型
 	 * @return {@link Type},可能为{@code null}
 	 */
@@ -196,8 +210,8 @@ public class TypeUtil {
 
 	/**
 	 * 获得给定类的泛型参数
-	 * 
-	 * @param type 被检查的类型,必须是已经确定泛型类型的类
+	 *
+	 * @param type  被检查的类型,必须是已经确定泛型类型的类
 	 * @param index 泛型类型的索引号,即第几个泛型类型
 	 * @return {@link Type}
 	 */
@@ -211,14 +225,14 @@ public class TypeUtil {
 
 	/**
 	 * 获得指定类型中所有泛型参数类型,例如:
-	 * 
+	 *
 	 * <pre>
 	 * class A&lt;T&gt;
 	 * class B extends A&lt;String&gt;
 	 * </pre>
-	 * 
+	 * <p>
 	 * 通过此方法,传入B.class即可得到String
-	 * 
+	 *
 	 * @param type 指定类型
 	 * @return 所有泛型参数类型
 	 */
@@ -235,14 +249,14 @@ public class TypeUtil {
 	 * 将{@link Type} 转换为{@link ParameterizedType}<br>
 	 * {@link ParameterizedType}用于获取当前类或父类中泛型参数化后的类型<br>
 	 * 一般用于获取泛型参数具体的参数类型,例如:
-	 * 
+	 *
 	 * <pre>
 	 * class A&lt;T&gt;
 	 * class B extends A&lt;String&gt;
 	 * </pre>
-	 * 
+	 * <p>
 	 * 通过此方法,传入B.class即可得到B{@link ParameterizedType},从而获取到String
-	 * 
+	 *
 	 * @param type {@link Type}
 	 * @return {@link ParameterizedType}
 	 * @since 4.5.2
@@ -254,10 +268,10 @@ public class TypeUtil {
 		} else if (type instanceof Class) {
 			final Class<?> clazz = (Class<?>) type;
 			Type genericSuper = clazz.getGenericSuperclass();
-			if(null == genericSuper || Object.class.equals(genericSuper)){
+			if (null == genericSuper || Object.class.equals(genericSuper)) {
 				// 如果类没有父类,而是实现一些定义好的泛型接口,则取接口的Type
 				final Type[] genericInterfaces = clazz.getGenericInterfaces();
-				if(ArrayUtil.isNotEmpty(genericInterfaces)){
+				if (ArrayUtil.isNotEmpty(genericInterfaces)) {
 					// 默认取第一个实现接口的泛型Type
 					genericSuper = genericInterfaces[0];
 				}
@@ -276,8 +290,7 @@ public class TypeUtil {
 	 * 1. typeDefineClass必须是clazz的父类或者clazz实现的接口
 	 * </pre>
 	 *
-	 *
-	 * @param actualType 真实类型所在类,此类中记录了泛型参数对应的实际类型
+	 * @param actualType      真实类型所在类,此类中记录了泛型参数对应的实际类型
 	 * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型
 	 * @return 给定泛型参数对应的实际类型,如果无对应类型,返回null
 	 * @since 5.4.1
@@ -289,32 +302,31 @@ public class TypeUtil {
 
 		// 泛型参数标识符列表
 		final TypeVariable<?>[] typeVars = typeDefineClass.getTypeParameters();
-		if(ArrayUtil.isEmpty(typeVars)) {
+		if (ArrayUtil.isEmpty(typeVars)) {
 			return new TableMap<>(0);
 		}
 		// 实际类型列表
 		final Type[] actualTypeArguments = TypeUtil.getTypeArguments(actualType);
-		if(ArrayUtil.isEmpty(actualTypeArguments)) {
+		if (ArrayUtil.isEmpty(actualTypeArguments)) {
 			return new TableMap<>(0);
 		}
 
 		return new TableMap<>(typeVars, actualTypeArguments);
 	}
-	
+
 	/**
 	 * 获取指定泛型变量对应的真实类型<br>
 	 * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型<br>
 	 * 使用此方法注意:
-	 * 
+	 *
 	 * <pre>
 	 * 1. superClass必须是clazz的父类或者clazz实现的接口
 	 * 2. typeVariable必须在superClass中声明
 	 * </pre>
-	 * 
-	 * 
-	 * @param actualType 真实类型所在类,此类中记录了泛型参数对应的实际类型
+	 *
+	 * @param actualType      真实类型所在类,此类中记录了泛型参数对应的实际类型
 	 * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型
-	 * @param typeVariables 泛型变量,需要的实际类型对应的泛型参数
+	 * @param typeVariables   泛型变量,需要的实际类型对应的泛型参数
 	 * @return 给定泛型参数对应的实际类型,如果无对应类型,返回null
 	 * @since 4.5.7
 	 */
@@ -323,33 +335,32 @@ public class TypeUtil {
 
 		// 查找方法定义所在类或接口中此泛型参数的位置
 		final Type[] result = new Type[typeVariables.length];
-		for(int i = 0; i < typeVariables.length; i++) {
+		for (int i = 0; i < typeVariables.length; i++) {
 			//noinspection SuspiciousMethodCalls
 			result[i] = (typeVariables[i] instanceof TypeVariable) ? tableMap.get(typeVariables[i]) : typeVariables[i];
 		}
 		return result;
 	}
-	
+
 	/**
 	 * 获取指定泛型变量对应的真实类型<br>
 	 * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型<br>
 	 * 使用此方法注意:
-	 * 
+	 *
 	 * <pre>
 	 * 1. superClass必须是clazz的父类或者clazz实现的接口
 	 * 2. typeVariable必须在superClass中声明
 	 * </pre>
-	 * 
-	 * 
-	 * @param actualType 真实类型所在类,此类中记录了泛型参数对应的实际类型
+	 *
+	 * @param actualType      真实类型所在类,此类中记录了泛型参数对应的实际类型
 	 * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型
-	 * @param typeVariable 泛型变量,需要的实际类型对应的泛型参数
+	 * @param typeVariable    泛型变量,需要的实际类型对应的泛型参数
 	 * @return 给定泛型参数对应的实际类型
 	 * @since 4.5.2
 	 */
 	public static Type getActualType(Type actualType, Class<?> typeDefineClass, Type typeVariable) {
 		Type[] types = getActualTypes(actualType, typeDefineClass, typeVariable);
-		if(ArrayUtil.isNotEmpty(types)) {
+		if (ArrayUtil.isNotEmpty(types)) {
 			return types[0];
 		}
 		return null;
@@ -358,7 +369,7 @@ public class TypeUtil {
 	/**
 	 * 是否未知类型<br>
 	 * type为null或者{@link TypeVariable} 都视为未知类型
-	 * 
+	 *
 	 * @param type Type类型
 	 * @return 是否未知类型
 	 * @since 4.5.2
@@ -366,16 +377,17 @@ public class TypeUtil {
 	public static boolean isUnknow(Type type) {
 		return null == type || type instanceof TypeVariable;
 	}
-	
+
 	/**
 	 * 指定泛型数组中是否含有泛型变量
+	 *
 	 * @param types 泛型数组
 	 * @return 是否含有泛型变量
 	 * @since 4.5.7
 	 */
 	public static boolean hasTypeVeriable(Type... types) {
 		for (Type type : types) {
-			if(type instanceof TypeVariable) {
+			if (type instanceof TypeVariable) {
 				return true;
 			}
 		}

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

@@ -1,5 +1,6 @@
 package cn.hutool.core.util;
 
+import lombok.Data;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -59,7 +60,23 @@ public class TypeUtilTest {
 
 	@Test
 	public void getActualTypesTest(){
+		final Type id = TypeUtil.getActualType(
+				Station.class,
+				Entity.class,
+				TypeUtil.getFieldType(Station.class, "id"));
+	}
+
+	public static class Station extends Tree<Station, Long>{
+
+	}
+
+	public static class Tree<E, T> extends Entity<T>{
+
+	}
 
+	@Data
+	public static class Entity<T>{
+		private T id;
 	}
 
 }

+ 1 - 1
hutool-extra/src/main/java/cn/hutool/extra/cglib/CglibUtil.java

@@ -134,7 +134,7 @@ public class CglibUtil {
 	public static <S, T> List<T> copyList(Collection<S> source, Supplier<T> target, Converter converter, BiConsumer<S, T> callback) {
 		return source.stream().map(s -> {
 			T t = target.get();
-			copy(source, t, converter);
+			copy(s, t, converter);
 			if (callback != null) {
 				callback.accept(s, t);
 			}