mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
修复JsonUtil.toBean
泛型数组类型丢失问题(pr#3876@Github)
This commit is contained in:
parent
d3941e5dd7
commit
bb0eb91087
@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.reflect;
|
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.convert.ConvertUtil;
|
||||||
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
|
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
|
||||||
|
|
||||||
|
import java.lang.reflect.GenericArrayType;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.lang.reflect.TypeVariable;
|
import java.lang.reflect.TypeVariable;
|
||||||
@ -35,6 +37,17 @@ public class ActualTypeMapperPool {
|
|||||||
|
|
||||||
private static final WeakConcurrentMap<Type, Map<Type, Type>> CACHE = new WeakConcurrentMap<>();
|
private static final WeakConcurrentMap<Type, Map<Type, Type>> CACHE = new WeakConcurrentMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取泛型变量名(字符串)和泛型实际类型的对应关系Map
|
||||||
|
*
|
||||||
|
* @param type 被解析的包含泛型参数的类
|
||||||
|
* @return 泛型对应关系Map
|
||||||
|
* @since 5.7.16
|
||||||
|
*/
|
||||||
|
public static Map<String, Type> getStrKeyMap(final Type type) {
|
||||||
|
return ConvertUtil.toMap(String.class, Type.class, get(type));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取泛型变量和泛型实际类型的对应关系Map
|
* 获取泛型变量和泛型实际类型的对应关系Map
|
||||||
*
|
*
|
||||||
@ -45,21 +58,10 @@ public class ActualTypeMapperPool {
|
|||||||
return CACHE.computeIfAbsent(type, (key) -> createTypeMap(type));
|
return CACHE.computeIfAbsent(type, (key) -> createTypeMap(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取泛型变量名(字符串)和泛型实际类型的对应关系Map
|
|
||||||
*
|
|
||||||
* @param type 被解析的包含泛型参数的类
|
|
||||||
* @return 泛型对应关系Map
|
|
||||||
* @since 5.7.16
|
|
||||||
*/
|
|
||||||
public static Map<String, Type> getStrKeyMap(final Type type){
|
|
||||||
return ConvertUtil.toMap(String.class, Type.class, get(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null
|
* 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null
|
||||||
*
|
*
|
||||||
* @param type 类
|
* @param type 类
|
||||||
* @param typeVariable 泛型变量,例如T等
|
* @param typeVariable 泛型变量,例如T等
|
||||||
* @return 实际类型,可能为Class等
|
* @return 实际类型,可能为Class等
|
||||||
*/
|
*/
|
||||||
@ -72,11 +74,35 @@ public class ActualTypeMapperPool {
|
|||||||
return result;
|
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<Type, Type> 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定泛型变量对应的真实类型<br>
|
* 获取指定泛型变量对应的真实类型<br>
|
||||||
* 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型<br>
|
* 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型<br>
|
||||||
*
|
*
|
||||||
* @param type 真实类型所在类,此类中记录了泛型参数对应的实际类型
|
* @param type 真实类型所在类,此类中记录了泛型参数对应的实际类型
|
||||||
* @param typeVariables 泛型变量,需要的实际类型对应的泛型参数
|
* @param typeVariables 泛型变量,需要的实际类型对应的泛型参数
|
||||||
* @return 给定泛型参数对应的实际类型,如果无对应类型,对应位置返回null
|
* @return 给定泛型参数对应的实际类型,如果无对应类型,对应位置返回null
|
||||||
*/
|
*/
|
||||||
@ -85,8 +111,8 @@ public class ActualTypeMapperPool {
|
|||||||
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++) {
|
||||||
result[i] = (typeVariables[i] instanceof TypeVariable)
|
result[i] = (typeVariables[i] instanceof TypeVariable)
|
||||||
? getActualType(type, (TypeVariable<?>) typeVariables[i])
|
? getActualType(type, (TypeVariable<?>) typeVariables[i])
|
||||||
: typeVariables[i];
|
: typeVariables[i];
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -109,7 +135,7 @@ public class ActualTypeMapperPool {
|
|||||||
// 如果传入的非Class,例如TypeReference,获取到泛型参数中实际的泛型对象类,继续按照类处理
|
// 如果传入的非Class,例如TypeReference,获取到泛型参数中实际的泛型对象类,继续按照类处理
|
||||||
while (null != type) {
|
while (null != type) {
|
||||||
final ParameterizedType parameterizedType = TypeUtil.toParameterizedType(type);
|
final ParameterizedType parameterizedType = TypeUtil.toParameterizedType(type);
|
||||||
if(null == parameterizedType){
|
if (null == parameterizedType) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
final Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
final Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||||
@ -120,7 +146,7 @@ public class ActualTypeMapperPool {
|
|||||||
for (int i = 0; i < typeParameters.length; i++) {
|
for (int i = 0; i < typeParameters.length; i++) {
|
||||||
value = typeArguments[i];
|
value = typeArguments[i];
|
||||||
// 跳过泛型变量对应泛型变量的情况
|
// 跳过泛型变量对应泛型变量的情况
|
||||||
if(!(value instanceof TypeVariable)){
|
if (!(value instanceof TypeVariable)) {
|
||||||
typeMap.put(typeParameters[i], value);
|
typeMap.put(typeParameters[i], value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -426,10 +426,13 @@ public class TypeUtil {
|
|||||||
if (typeVariable instanceof ParameterizedType) {
|
if (typeVariable instanceof ParameterizedType) {
|
||||||
return getActualType(type, (ParameterizedType) typeVariable);
|
return getActualType(type, (ParameterizedType) typeVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeVariable instanceof TypeVariable) {
|
if (typeVariable instanceof TypeVariable) {
|
||||||
return getActualType(type, (TypeVariable<?>) typeVariable);
|
return getActualType(type, (TypeVariable<?>) typeVariable);
|
||||||
}
|
}
|
||||||
|
// pr#3876 解决泛型数组泛型类型无法识别问题
|
||||||
|
if (typeVariable instanceof GenericArrayType) {
|
||||||
|
return ActualTypeMapperPool.getActualType(type, (GenericArrayType) typeVariable);
|
||||||
|
}
|
||||||
|
|
||||||
// 没有需要替换的泛型变量,原样输出
|
// 没有需要替换的泛型变量,原样输出
|
||||||
return typeVariable;
|
return typeVariable;
|
||||||
|
@ -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<Index> deserialize = JSONUtil.toBean(json, JSONConfig.of(), (new TypeReference<Results<Index>>() {}));
|
||||||
|
|
||||||
|
assertEquals(Results.class, deserialize.getClass());
|
||||||
|
assertEquals(ArrayUtil.getArrayType(Index.class), deserialize.results.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Results<T> {
|
||||||
|
public T[] results;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Index {
|
||||||
|
public String uid;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user