This commit is contained in:
Looly
2020-09-05 18:00:25 +08:00
parent dba35b9395
commit cbbf4671ba
4 changed files with 81 additions and 51 deletions

View File

@@ -3,7 +3,7 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.4.2 (2020-09-03) # 5.4.2 (2020-09-05)
### 新特性 ### 新特性
* 【core 】 lock放在try外边pr#1050@Github * 【core 】 lock放在try外边pr#1050@Github
@@ -14,11 +14,13 @@
* 【poi 】 RowUtil增加插入和删除行pr#1060@Github * 【poi 】 RowUtil增加插入和删除行pr#1060@Github
* 【extra 】 SpringUtil增加注册beanpr#174@Gitee * 【extra 】 SpringUtil增加注册beanpr#174@Gitee
* 【core 】 修改NetUtil.getMacAddress避免空指针issue#1057@Github * 【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过来的玩笑导致的问题 * 【core 】 重新整理农历节假日解决一个pr过来的玩笑导致的问题
* 【poi 】 修复ExcelFileUtil.isXls判断问题pr#1055@Github * 【poi 】 修复ExcelFileUtil.isXls判断问题pr#1055@Github
* 【poi 】 修复CglibUtil.copyList参数错误导致的问题
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
@@ -40,7 +42,6 @@
* 【core 】 EnumUtil.getEnumAt负数返回nullpr#167@Gitee * 【core 】 EnumUtil.getEnumAt负数返回nullpr#167@Gitee
* 【core 】 ChineseDate增加天干地支和转换为公历方法pr#169@Gitee * 【core 】 ChineseDate增加天干地支和转换为公历方法pr#169@Gitee
* 【core 】 Img增加stroke描边方法issue#1033@Github * 【core 】 Img增加stroke描边方法issue#1033@Github
* 【core 】 TypeUtil增加getActualTypeMap方法
### Bug修复# ### Bug修复#
* 【poi 】 修复ExcelBase.isXlsx方法判断问题issue#I1S502@Gitee * 【poi 】 修复ExcelBase.isXlsx方法判断问题issue#I1S502@Gitee

View File

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

View File

@@ -1,5 +1,6 @@
package cn.hutool.core.util; package cn.hutool.core.util;
import lombok.Data;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@@ -59,7 +60,23 @@ public class TypeUtilTest {
@Test @Test
public void getActualTypesTest(){ 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;
}
} }

View File

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