diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ActualTypeMapperPool.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ActualTypeMapperPool.java index dbf4200fa..d797084ce 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ActualTypeMapperPool.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ActualTypeMapperPool.java @@ -16,9 +16,11 @@ package org.dromara.hutool.core.reflect; +import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.convert.ConvertUtil; import org.dromara.hutool.core.map.reference.WeakConcurrentMap; +import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; @@ -35,6 +37,17 @@ public class ActualTypeMapperPool { private static final WeakConcurrentMap> CACHE = new WeakConcurrentMap<>(); + /** + * 获取泛型变量名(字符串)和泛型实际类型的对应关系Map + * + * @param type 被解析的包含泛型参数的类 + * @return 泛型对应关系Map + * @since 5.7.16 + */ + public static Map getStrKeyMap(final Type type) { + return ConvertUtil.toMap(String.class, Type.class, get(type)); + } + /** * 获取泛型变量和泛型实际类型的对应关系Map * @@ -45,21 +58,10 @@ public class ActualTypeMapperPool { return CACHE.computeIfAbsent(type, (key) -> createTypeMap(type)); } - /** - * 获取泛型变量名(字符串)和泛型实际类型的对应关系Map - * - * @param type 被解析的包含泛型参数的类 - * @return 泛型对应关系Map - * @since 5.7.16 - */ - public static Map getStrKeyMap(final Type type){ - return ConvertUtil.toMap(String.class, Type.class, get(type)); - } - /** * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null * - * @param type 类 + * @param type 类 * @param typeVariable 泛型变量,例如T等 * @return 实际类型,可能为Class等 */ @@ -72,11 +74,35 @@ public class ActualTypeMapperPool { return result; } + /** + * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null + * + * @param type 类 + * @param genericArrayType 泛型数组 + * @return 实际类型,可能为Class等 + * @since 5.8.37 + */ + public static Type getActualType(final Type type, final GenericArrayType genericArrayType) { + final Map typeTypeMap = get(type); + Type actualType = typeTypeMap.get(genericArrayType); + + if (actualType == null) { + final Type componentType = typeTypeMap.get(genericArrayType.getGenericComponentType()); + if (!(componentType instanceof Class)) { + return null; + } + actualType = ArrayUtil.getArrayType((Class) componentType); + typeTypeMap.put(genericArrayType, actualType); + } + + return actualType; + } + /** * 获取指定泛型变量对应的真实类型
* 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型
* - * @param type 真实类型所在类,此类中记录了泛型参数对应的实际类型 + * @param type 真实类型所在类,此类中记录了泛型参数对应的实际类型 * @param typeVariables 泛型变量,需要的实际类型对应的泛型参数 * @return 给定泛型参数对应的实际类型,如果无对应类型,对应位置返回null */ @@ -85,8 +111,8 @@ public class ActualTypeMapperPool { 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]; + ? getActualType(type, (TypeVariable) typeVariables[i]) + : typeVariables[i]; } return result; } @@ -109,7 +135,7 @@ public class ActualTypeMapperPool { // 如果传入的非Class,例如TypeReference,获取到泛型参数中实际的泛型对象类,继续按照类处理 while (null != type) { final ParameterizedType parameterizedType = TypeUtil.toParameterizedType(type); - if(null == parameterizedType){ + if (null == parameterizedType) { break; } final Type[] typeArguments = parameterizedType.getActualTypeArguments(); @@ -120,7 +146,7 @@ public class ActualTypeMapperPool { for (int i = 0; i < typeParameters.length; i++) { value = typeArguments[i]; // 跳过泛型变量对应泛型变量的情况 - if(!(value instanceof TypeVariable)){ + if (!(value instanceof TypeVariable)) { typeMap.put(typeParameters[i], value); } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeUtil.java index 5d85d2693..5d4e20587 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeUtil.java @@ -426,10 +426,13 @@ public class TypeUtil { if (typeVariable instanceof ParameterizedType) { return getActualType(type, (ParameterizedType) typeVariable); } - if (typeVariable instanceof TypeVariable) { return getActualType(type, (TypeVariable) typeVariable); } + // pr#3876 解决泛型数组泛型类型无法识别问题 + if (typeVariable instanceof GenericArrayType) { + return ActualTypeMapperPool.getActualType(type, (GenericArrayType) typeVariable); + } // 没有需要替换的泛型变量,原样输出 return typeVariable; diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/issues/Issue3873Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/issues/Issue3873Test.java new file mode 100644 index 000000000..e1662d5f6 --- /dev/null +++ b/hutool-json/src/test/java/org/dromara/hutool/json/issues/Issue3873Test.java @@ -0,0 +1,34 @@ +package org.dromara.hutool.json.issues; + +import lombok.Data; +import org.dromara.hutool.core.array.ArrayUtil; +import org.dromara.hutool.core.reflect.TypeReference; +import org.dromara.hutool.json.JSONConfig; +import org.dromara.hutool.json.JSONUtil; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class Issue3873Test { + /** + * 类型引用数组泛型丢失 + */ + @Test + public void toBeanTest() { + final String json = "{\"results\":[{\"uid\":\"1\"}],\"offset\":0,\"limit\":20,\"total\":0}"; + final Results deserialize = JSONUtil.toBean(json, JSONConfig.of(), (new TypeReference>() {})); + + assertEquals(Results.class, deserialize.getClass()); + assertEquals(ArrayUtil.getArrayType(Index.class), deserialize.results.getClass()); + } + + @Data + public static class Results { + public T[] results; + } + + @Data + public static class Index { + public String uid; + } +}