From 784ad3e8f916adebaa6336ba4a7cd9ff8927e6f0 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 6 Sep 2020 02:20:15 +0800 Subject: [PATCH] fix typeUtil --- CHANGELOG.md | 2 +- .../hutool/core/bean/copier/BeanCopier.java | 22 +-- .../cn/hutool/core/collection/CollUtil.java | 2 +- .../core/convert/ConverterRegistry.java | 4 +- .../impl/AtomicReferenceConverter.java | 2 +- .../core/convert/impl/MapConverter.java | 4 +- .../core/convert/impl/ReferenceConverter.java | 2 +- .../cn/hutool/core/date/CalendarUtil.java | 26 +++ .../java/cn/hutool/core/date/DateUtil.java | 12 ++ .../lang/reflect/ActualTypeMapperPool.java | 101 ++++++++++ .../core/lang/reflect/package-info.java | 7 + .../java/cn/hutool/core/util/TypeUtil.java | 173 +++++++++--------- .../cn/hutool/core/bean/BeanUtilTest.java | 24 +++ .../cn/hutool/core/util/TypeUtilTest.java | 13 +- 14 files changed, 269 insertions(+), 125 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/reflect/ActualTypeMapperPool.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/reflect/package-info.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 71d6c01fa..345af5080 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ * 【extra 】 SpringUtil增加注册bean(pr#174@Gitee) * 【core 】 修改NetUtil.getMacAddress避免空指针(issue#1057@Github) * 【core 】 增加EnumItem接口,枚举扩展转换,增加SPI自定义转换(pr#173@Github) -* 【core 】 TypeUtil增加getActualTypeMap方法 +* 【core 】 TypeUtil增加getActualType,增加ActualTypeMapperPool类(issue#I1TBWH@Gitee) ### Bug修复 * 【core 】 重新整理农历节假日,解决一个pr过来的玩笑导致的问题 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 922ab0f85..35d88a75f 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 @@ -7,10 +7,8 @@ import cn.hutool.core.bean.copier.provider.MapValueProvider; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.exceptions.UtilException; -import cn.hutool.core.lang.ParameterizedTypeImpl; import cn.hutool.core.lang.copier.Copier; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ModifierUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; @@ -19,9 +17,7 @@ import cn.hutool.core.util.TypeUtil; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; import java.util.Collection; import java.util.HashSet; import java.util.Map; @@ -246,24 +242,8 @@ public class BeanCopier implements Copier, Serializable { // 获取目标字段真实类型 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(), fieldParameterizedType.getActualTypeArguments()); - if (ArrayUtil.isNotEmpty(actualTypeArguments)) { - // 替换泛型变量为实际类型 - fieldType = new ParameterizedTypeImpl(actualTypeArguments, fieldParameterizedType.getOwnerType(), fieldParameterizedType.getRawType()); - } - } - } else if (fieldType instanceof TypeVariable) { - // 字段类型为泛型,查找其真实类型(适用于泛型方法定义于泛型父类),类似于T a - fieldType = TypeUtil.getActualType(this.destType, field.getDeclaringClass(), fieldType); - } + fieldType = TypeUtil.getActualType(this.destType ,fieldType); - // value = valueProvider.value(providerKey, fieldType); if (null == value && copyOptions.ignoreNullValue) { continue;// 当允许跳过空时,跳过 diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java index 8ec0301a4..48915ed4d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java @@ -2023,7 +2023,7 @@ public class CollUtil { if (null == collection || null == value) { return collection; } - if (TypeUtil.isUnknow(elementType)) { + if (TypeUtil.isUnknown(elementType)) { // 元素类型为空时,使用Object类型来接纳所有类型 elementType = Object.class; } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java index f36174bfb..c84c5609f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java @@ -226,14 +226,14 @@ public class ConverterRegistry implements Serializable { */ @SuppressWarnings("unchecked") public T convert(Type type, Object value, T defaultValue, boolean isCustomFirst) throws ConvertException { - if (TypeUtil.isUnknow(type) && null == defaultValue) { + if (TypeUtil.isUnknown(type) && null == defaultValue) { // 对于用户不指定目标类型的情况,返回原值 return (T) value; } if (ObjectUtil.isNull(value)) { return defaultValue; } - if (TypeUtil.isUnknow(type)) { + if (TypeUtil.isUnknown(type)) { type = defaultValue.getClass(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicReferenceConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicReferenceConverter.java index 7e8fabaa8..fed6fdbd5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicReferenceConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicReferenceConverter.java @@ -23,7 +23,7 @@ public class AtomicReferenceConverter extends AbstractConverter //尝试将值转换为Reference泛型的类型 Object targetValue = null; final Type paramType = TypeUtil.getTypeArgument(AtomicReference.class); - if(false == TypeUtil.isUnknow(paramType)){ + if(false == TypeUtil.isUnknown(paramType)){ targetValue = ConverterRegistry.getInstance().convert(paramType, value); } if(null == targetValue){ diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java index 834fad0a7..3ca2e0552 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java @@ -86,8 +86,8 @@ public class MapConverter extends AbstractConverter> { Object key; Object value; for (Entry entry : srcMap.entrySet()) { - key = TypeUtil.isUnknow(this.keyType) ? entry.getKey() : convert.convert(this.keyType, entry.getKey()); - value = TypeUtil.isUnknow(this.valueType) ? entry.getValue() : convert.convert(this.valueType, entry.getValue()); + key = TypeUtil.isUnknown(this.keyType) ? entry.getKey() : convert.convert(this.keyType, entry.getKey()); + value = TypeUtil.isUnknown(this.valueType) ? entry.getValue() : convert.convert(this.valueType, entry.getValue()); targetMap.put(key, value); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java index b9bbd42ce..15de64ec9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java @@ -37,7 +37,7 @@ public class ReferenceConverter extends AbstractConverter { //尝试将值转换为Reference泛型的类型 Object targetValue = null; final Type paramType = TypeUtil.getTypeArgument(targetType); - if(false == TypeUtil.isUnknow(paramType)){ + if(false == TypeUtil.isUnknown(paramType)){ targetValue = ConverterRegistry.getInstance().convert(paramType, value); } if(null == targetValue){ diff --git a/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java index e4cfb2deb..5f7b2d1d7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java @@ -359,6 +359,19 @@ public class CalendarUtil { return StrUtil.builder().append(cal.get(Calendar.YEAR)).append(cal.get(Calendar.MONTH) / 3 + 1).toString(); } + /** + * 获取指定日期字段的最小值,例如分钟的最小值是0 + * + * @param calendar {@link Calendar} + * @param dateField {@link DateField} + * @return 字段最小值 + * @see Calendar#getActualMinimum(int) + * @since 5.4.2 + */ + public static int getBeginValue(Calendar calendar, DateField dateField) { + return getBeginValue(calendar, dateField.getValue()); + } + /** * 获取指定日期字段的最小值,例如分钟的最小值是0 * @@ -375,6 +388,19 @@ public class CalendarUtil { return calendar.getActualMinimum(dateField); } + /** + * 获取指定日期字段的最大值,例如分钟的最大值是59 + * + * @param calendar {@link Calendar} + * @param dateField {@link DateField} + * @return 字段最大值 + * @see Calendar#getActualMaximum(int) + * @since 5.4.2 + */ + public static int getEndValue(Calendar calendar, DateField dateField) { + return getEndValue(calendar, dateField.getValue()); + } + /** * 获取指定日期字段的最大值,例如分钟的最大值是59 * diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java index f7dc8d07c..ca699fdb1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -1916,6 +1916,18 @@ public class DateUtil extends CalendarUtil { return Year.of(year).length(); } + /** + * 获得指定月份的总天数 + * + * @param month 年份 + * @param isLeapYear 是否闰年 + * @return 天 + * @since 5.4.2 + */ + public static int lengthOfMonth(int month, boolean isLeapYear) { + return java.time.Month.of(month).length(isLeapYear); + } + // ------------------------------------------------------------------------ Private method start /** diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/reflect/ActualTypeMapperPool.java b/hutool-core/src/main/java/cn/hutool/core/lang/reflect/ActualTypeMapperPool.java new file mode 100644 index 000000000..1bf09c11a --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/reflect/ActualTypeMapperPool.java @@ -0,0 +1,101 @@ +package cn.hutool.core.lang.reflect; + +import cn.hutool.core.lang.SimpleCache; +import cn.hutool.core.util.TypeUtil; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.HashMap; +import java.util.Map; + +/** + * 泛型变量和泛型实际类型映射关系缓存 + * + * @author looly + * @since 5.4.2 + */ +public class ActualTypeMapperPool { + + private static final SimpleCache> cache = new SimpleCache<>(); + + /** + * 获取泛型变量和泛型实际类型的对应关系Map + * + * @param type 被解析的包含泛型参数的类 + * @return 泛型对应关系Map + */ + public static Map get(Type type) { + return cache.get(type, () -> createTypeMap(type)); + } + + /** + * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null + * + * @param type 类 + * @param typeVariable 泛型变量,例如T等 + * @return 实际类型,可能为Class等 + */ + public static Type getActualType(Type type, TypeVariable typeVariable) { + final Map typeTypeMap = get(type); + Type result = typeTypeMap.get(typeVariable); + while (result instanceof TypeVariable) { + result = typeTypeMap.get(result); + } + return result; + } + + /** + * 获取指定泛型变量对应的真实类型
+ * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型
+ * + * @param type 真实类型所在类,此类中记录了泛型参数对应的实际类型 + * @param typeVariables 泛型变量,需要的实际类型对应的泛型参数 + * @return 给定泛型参数对应的实际类型,如果无对应类型,对应位置返回null + */ + public static Type[] getActualTypes(Type type, Type... typeVariables) { + // 查找方法定义所在类或接口中此泛型参数的位置 + final Type[] result = new Type[typeVariables.length]; + for (int i = 0; i < typeVariables.length; i++) { + result[i] = (typeVariables[i] instanceof TypeVariable) + ? getActualType(type, (TypeVariable) typeVariables[i]) + : typeVariables[i]; + } + return result; + } + + /** + * 创建类中所有的泛型变量和泛型实际类型的对应关系Map + * + * @param type 被解析的包含泛型参数的类 + * @return 泛型对应关系Map + */ + private static Map createTypeMap(Type type) { + final Map typeMap = new HashMap<>(); + + // 按继承层级寻找泛型变量和实际类型的对应关系 + // 在类中,对应关系分为两类: + // 1. 父类定义变量,子类标注实际类型 + // 2. 父类定义变量,子类继承这个变量,让子类的子类去标注,以此类推 + // 此方法中我们将每一层级的对应关系全部加入到Map中,查找实际类型的时候,根据传入的泛型变量, + // 找到对应关系,如果对应的是继承的泛型变量,则递归继续找,直到找到实际或返回null为止。 + // 如果传入的非Class,例如TypeReference,获取到泛型参数中实际的泛型对象类,继续按照类处理 + while (null != type) { + final ParameterizedType parameterizedType = TypeUtil.toParameterizedType(type); + if(null == parameterizedType){ + break; + } + final Type[] typeArguments = parameterizedType.getActualTypeArguments(); + final Class rawType = (Class) parameterizedType.getRawType(); + final Type[] typeParameters = rawType.getTypeParameters(); + + for (int i = 0; i < typeParameters.length; i++) { + typeMap.put(typeParameters[i], typeArguments[i]); + } + + type = rawType; + } + + return typeMap; + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/reflect/package-info.java b/hutool-core/src/main/java/cn/hutool/core/lang/reflect/package-info.java new file mode 100644 index 000000000..f84002fcd --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/reflect/package-info.java @@ -0,0 +1,7 @@ +/** + * 提供反射相关功能对象和类 + * + * @author looly + * @since 5.4.2 + */ +package cn.hutool.core.lang.reflect; \ No newline at end of file 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 8cf1fe11b..f52e6b0ed 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 @@ -1,6 +1,7 @@ package cn.hutool.core.util; -import cn.hutool.core.map.TableMap; +import cn.hutool.core.lang.ParameterizedTypeImpl; +import cn.hutool.core.lang.reflect.ActualTypeMapperPool; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -8,6 +9,7 @@ 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} 的工具类封装
@@ -281,93 +283,6 @@ 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 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<>(ArrayUtil.map(typeVars, String.class, TypeVariable::getName), actualTypeArguments); - } - - /** - * 获取指定泛型变量对应的真实类型
- * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型
- * 使用此方法注意: - * - *
-	 * 1. superClass必须是clazz的父类或者clazz实现的接口
-	 * 2. typeVariable必须在superClass中声明
-	 * 
- * - * @param actualType 真实类型所在类,此类中记录了泛型参数对应的实际类型 - * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型 - * @param typeVariables 泛型变量,需要的实际类型对应的泛型参数 - * @return 给定泛型参数对应的实际类型,如果无对应类型,返回null - * @since 4.5.7 - */ - public static Type[] getActualTypes(Type actualType, Class typeDefineClass, Type... typeVariables) { - final TableMap tableMap = getActualTypeMap(actualType, typeDefineClass); - - // 查找方法定义所在类或接口中此泛型参数的位置 - final Type[] result = new Type[typeVariables.length]; - for (int i = 0; i < typeVariables.length; i++) { - result[i] = (typeVariables[i] instanceof TypeVariable) - ? tableMap.get(((TypeVariable) typeVariables[i]).getName()) - : typeVariables[i]; - } - return result; - } - - /** - * 获取指定泛型变量对应的真实类型
- * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型
- * 使用此方法注意: - * - *
-	 * 1. superClass必须是clazz的父类或者clazz实现的接口
-	 * 2. typeVariable必须在superClass中声明
-	 * 
- * - * @param actualType 真实类型所在类,此类中记录了泛型参数对应的实际类型 - * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型 - * @param typeVariable 泛型变量,需要的实际类型对应的泛型参数 - * @return 给定泛型参数对应的实际类型 - * @since 4.5.2 - */ - public static Type getActualType(Type actualType, Class typeDefineClass, Type typeVariable) { - final Type[] types = getActualTypes(actualType, typeDefineClass, typeVariable); - if (ArrayUtil.isNotEmpty(types)) { - return types[0]; - } - return null; - } - /** * 是否未知类型
* type为null或者{@link TypeVariable} 都视为未知类型 @@ -376,7 +291,7 @@ public class TypeUtil { * @return 是否未知类型 * @since 4.5.2 */ - public static boolean isUnknow(Type type) { + public static boolean isUnknown(Type type) { return null == type || type instanceof TypeVariable; } @@ -395,4 +310,84 @@ public class TypeUtil { } return false; } + + /** + * 获取泛型变量和泛型实际类型的对应关系Map + * + * @param clazz 被解析的包含泛型参数的类 + * @return 泛型对应关系Map + */ + public static Map getTypeMap(Class clazz) { + return ActualTypeMapperPool.get(clazz); + } + + /** + * 获得泛型字段对应的泛型实际类型,如果此变量没有对应的实际类型,返回null + * + * @param type 实际类型明确的类 + * @param field 字段 + * @return 实际类型,可能为Class等 + */ + public static Type getActualType(Type type, Field field) { + if(null == field){ + return null; + } + return getActualType(ObjectUtil.defaultIfNull(type, field.getDeclaringClass()), field.getGenericType()); + } + + /** + * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null + * 此方法可以处理 + * + * @param type 类 + * @param typeVariable 泛型变量,例如T等 + * @return 实际类型,可能为Class等 + */ + public static Type getActualType(Type type, Type typeVariable) { + if (typeVariable instanceof ParameterizedType) { + return getActualType(type, (ParameterizedType)typeVariable); + } + + if (typeVariable instanceof TypeVariable) { + return ActualTypeMapperPool.getActualType(type, (TypeVariable) typeVariable); + } + + // 没有需要替换的泛型变量,原样输出 + return typeVariable; + } + + /** + * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null + * 此方法可以处理 + * + * @param type 类 + * @param parameterizedType 泛型变量,例如List<T>等 + * @return 实际类型,可能为Class等 + */ + public static Type getActualType(Type type, ParameterizedType parameterizedType) { + // 字段类型为泛型参数类型,解析对应泛型类型为真实类型,类似于List a + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + + // 泛型对象中含有未被转换的泛型变量 + if (TypeUtil.hasTypeVeriable(actualTypeArguments)) { + actualTypeArguments = getActualTypes(type , parameterizedType.getActualTypeArguments()); + if (ArrayUtil.isNotEmpty(actualTypeArguments)) { + // 替换泛型变量为实际类型,例如List变为List + parameterizedType = new ParameterizedTypeImpl(actualTypeArguments, parameterizedType.getOwnerType(), parameterizedType.getRawType()); + } + } + + return parameterizedType; + } + + /** + * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null + * + * @param type 类 + * @param typeVariables 泛型变量数组,例如T等 + * @return 实际类型数组,可能为Class等 + */ + public static Type[] getActualTypes(Type type, Type... typeVariables) { + return ActualTypeMapperPool.getActualTypes(type, typeVariables); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java index f079292e3..bcc8ccc3a 100644 --- a/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java @@ -446,4 +446,28 @@ public class BeanUtilTest { BeanUtil.setProperty(resultMap, "codeList[0].name", "张三"); Console.log(resultMap); } + + @Test + public void beanCopyTest(){ + final Station station = new Station(); + station.setId(123456L); + + final Station station2 = new Station(); + + BeanUtil.copyProperties(station, station2); + Assert.assertEquals(new Long(123456L), station2.getId()); + } + + public static class Station extends Tree { + + } + + public static class Tree extends Entity { + + } + + @Data + public static class Entity{ + private T id; + } } 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 92dd7b1f0..b22ada954 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 @@ -60,24 +60,23 @@ public class TypeUtilTest { @Test public void getActualTypesTest(){ - final Type idType = TypeUtil.getActualType( - Station.class, - Tree.class, - TypeUtil.getFieldType(Station.class, "id")); + // 测试多层级泛型参数是否能获取成功 + Type idType = TypeUtil.getActualType(Level3.class, + ReflectUtil.getField(Level3.class, "id")); Assert.assertEquals(Long.class, idType); } - public static class Station extends Tree{ + public static class Level3 extends Level2{ } - public static class Tree extends Entity{ + public static class Level2 extends Level1{ } @Data - public static class Entity{ + public static class Level1{ private T id; }