From cbbf4671ba3ae8304ab7374e78ee9ecf0ed188c6 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 5 Sep 2020 18:00:25 +0800 Subject: [PATCH] fix bug --- CHANGELOG.md | 9 +- .../java/cn/hutool/core/util/TypeUtil.java | 104 ++++++++++-------- .../cn/hutool/core/util/TypeUtilTest.java | 17 +++ .../java/cn/hutool/extra/cglib/CglibUtil.java | 2 +- 4 files changed, 81 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 075c4607e..7855bc953 100644 --- a/CHANGELOG.md +++ b/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) 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 4ba886fff..eadf66cbf 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 @@ -12,12 +12,12 @@ import java.lang.reflect.WildcardType; /** * 针对 {@link Type} 的工具类封装
* 最主要功能包括: - * + * *
  * 1. 获取方法的参数和返回值类型(包括Type和Class)
  * 2. 获取泛型参数类型(包括对象的泛型参数或集合元素的泛型类型)
  * 
- * + * * @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类型
* 方法优先获取GenericType,获取不到则获取Type - * + * * @param field 字段 * @return {@link Type},可能为{@code null} */ @@ -61,9 +61,21 @@ public class TypeUtil { return field.getGenericType(); } + /** + * 获得字段的泛型类型 + * + * @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 + /** * 获取方法的第一个参数类型
* 优先获取方法的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 { /** * 获取方法的参数类型
* 优先获取方法的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 { /** * 获取方法的参数类型列表
* 优先获取方法的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 + /** * 获取方法的返回值类型
* 获取方法的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 { /** * 获得指定类型中所有泛型参数类型,例如: - * + * *
 	 * class A<T>
 	 * class B extends A<String>
 	 * 
- * + *

* 通过此方法,传入B.class即可得到String - * + * * @param type 指定类型 * @return 所有泛型参数类型 */ @@ -235,14 +249,14 @@ public class TypeUtil { * 将{@link Type} 转换为{@link ParameterizedType}
* {@link ParameterizedType}用于获取当前类或父类中泛型参数化后的类型
* 一般用于获取泛型参数具体的参数类型,例如: - * + * *

 	 * class A<T>
 	 * class B extends A<String>
 	 * 
- * + *

* 通过此方法,传入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实现的接口 * * - * - * @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); } - + /** * 获取指定泛型变量对应的真实类型
* 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型
* 使用此方法注意: - * + * *

 	 * 1. superClass必须是clazz的父类或者clazz实现的接口
 	 * 2. typeVariable必须在superClass中声明
 	 * 
- * - * - * @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; } - + /** * 获取指定泛型变量对应的真实类型
* 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型
* 使用此方法注意: - * + * *
 	 * 1. superClass必须是clazz的父类或者clazz实现的接口
 	 * 2. typeVariable必须在superClass中声明
 	 * 
- * - * - * @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 { /** * 是否未知类型
* 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; } } 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 849b09b14..013fcf6c1 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 @@ -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{ } + public static class Tree extends Entity{ + + } + + @Data + public static class Entity{ + private T id; + } + } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/cglib/CglibUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/cglib/CglibUtil.java index 086aa2516..b1c877bc8 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/cglib/CglibUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/cglib/CglibUtil.java @@ -134,7 +134,7 @@ public class CglibUtil { public static List copyList(Collection source, Supplier target, Converter converter, BiConsumer 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); }