如何将带有泛型的类型转换为 java 中的 Class?
How to convert Type with generics into a Class in java?
我有一个方法对象。
我想用泛型提取 return Type
并将其转换为 Class
,以便将此类信息传递到 Spring PropertyResolver
。
Type type = myMethod.getGenericReturnType();
Class<?> returnType = /* ??? */;
environment.getProperty(key, returnType);
您可以使用变通方法将 Method.getGenericReturnType()
返回的 java.lang.reflect.Type
转换为泛型的 Class
。
字符串解析:
final String typeName = method.getGenericReturnType().getTypeName();
Pattern pattern = Pattern.compile("<(.*)>");
final Matcher matcher = pattern.matcher(typeName);
if (matcher.find()) {
String className = matcher.group(1);
Class<?> clazz = Class.forName(className);
}
您也可以将 java.lang.reflect.Type
向下转换为运行时使用的具体 class :sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
但我认为它可能会根据 JVM 发生变化。
final Type genericReturnType = method.getGenericReturnType();
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl typeImpl = (ParameterizedTypeImpl) genericReturnType;
String className = typeImpl.getActualTypeArguments()[0].getTypeName();
Class<?> clazz = Class.forName(className);
实际上 return Type
实例必须是以下之一:Class
(例如 String
),GenericArrayType
(例如 String[]
或 T[]
或 List<T>[]
)、TypeVariable
(例如 T
)或 ParametrizedType
(例如 List<String>
或 List<T>
)。另外Type
也可以是WildcardType
(例如List<?>
中的?
)但是这些不能直接作为return类型使用。
下面的代码尝试解析 class 给定的实例,该实例基于其在这 5 个中的子接口。很少有 Type
不会扩展 5 个中的任何一个,在这种情况下,我们只是说我们不能继续 UnsupportedOperationException
。例如,您可以创建自己的合成 Type
扩展 class 但您为什么要这样做呢?
public static Class<?> type2Class(Type type) {
if (type instanceof Class) {
return (Class<?>) type;
} else if (type instanceof GenericArrayType) {
// having to create an array instance to get the class is kinda nasty
// but apparently this is a current limitation of java-reflection concerning array classes.
return Array.newInstance(type2Class(((GenericArrayType)type).getGenericComponentType()), 0).getClass(); // E.g. T[] -> T -> Object.class if <T> or Number.class if <T extends Number & Comparable>
} else if (type instanceof ParameterizedType) {
return type2Class(((ParameterizedType) type).getRawType()); // Eg. List<T> would return List.class
} else if (type instanceof TypeVariable) {
Type[] bounds = ((TypeVariable<?>) type).getBounds();
return bounds.length == 0 ? Object.class : type2Class(bounds[0]); // erasure is to the left-most bound.
} else if (type instanceof WildcardType) {
Type[] bounds = ((WildcardType) type).getUpperBounds();
return bounds.length == 0 ? Object.class : type2Class(bounds[0]); // erasure is to the left-most upper bound.
} else {
throw new UnsupportedOperationException("cannot handle type class: " + type.getClass());
}
}
请注意,代码未经测试,因此可能包含编译错误。此外,我不确定 GenericArrayType
如何处理 T[][]
等多维数组类型(如果 Object[]
而不是 return Object[][]
=34=] 所以我们需要在这里做额外的工作)。如果需要任何更正,请告诉我。
最后我们在这里尝试做的是在给定 Type
的情况下计算擦除 class 我想知道是否有一些 "standard" 代码可以做到这一点,也许Sun/Oracle 编译器或代码分析器工具的一部分,您只需使用它们的实用程序,就可以省去编码和维护它的麻烦……我快速浏览了一下,没有找到任何东西。
我有一个方法对象。
我想用泛型提取 return Type
并将其转换为 Class
,以便将此类信息传递到 Spring PropertyResolver
。
Type type = myMethod.getGenericReturnType();
Class<?> returnType = /* ??? */;
environment.getProperty(key, returnType);
您可以使用变通方法将 Method.getGenericReturnType()
返回的 java.lang.reflect.Type
转换为泛型的 Class
。
字符串解析:
final String typeName = method.getGenericReturnType().getTypeName();
Pattern pattern = Pattern.compile("<(.*)>");
final Matcher matcher = pattern.matcher(typeName);
if (matcher.find()) {
String className = matcher.group(1);
Class<?> clazz = Class.forName(className);
}
您也可以将 java.lang.reflect.Type
向下转换为运行时使用的具体 class :sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
但我认为它可能会根据 JVM 发生变化。
final Type genericReturnType = method.getGenericReturnType();
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl typeImpl = (ParameterizedTypeImpl) genericReturnType;
String className = typeImpl.getActualTypeArguments()[0].getTypeName();
Class<?> clazz = Class.forName(className);
实际上 return Type
实例必须是以下之一:Class
(例如 String
),GenericArrayType
(例如 String[]
或 T[]
或 List<T>[]
)、TypeVariable
(例如 T
)或 ParametrizedType
(例如 List<String>
或 List<T>
)。另外Type
也可以是WildcardType
(例如List<?>
中的?
)但是这些不能直接作为return类型使用。
下面的代码尝试解析 class 给定的实例,该实例基于其在这 5 个中的子接口。很少有 Type
不会扩展 5 个中的任何一个,在这种情况下,我们只是说我们不能继续 UnsupportedOperationException
。例如,您可以创建自己的合成 Type
扩展 class 但您为什么要这样做呢?
public static Class<?> type2Class(Type type) {
if (type instanceof Class) {
return (Class<?>) type;
} else if (type instanceof GenericArrayType) {
// having to create an array instance to get the class is kinda nasty
// but apparently this is a current limitation of java-reflection concerning array classes.
return Array.newInstance(type2Class(((GenericArrayType)type).getGenericComponentType()), 0).getClass(); // E.g. T[] -> T -> Object.class if <T> or Number.class if <T extends Number & Comparable>
} else if (type instanceof ParameterizedType) {
return type2Class(((ParameterizedType) type).getRawType()); // Eg. List<T> would return List.class
} else if (type instanceof TypeVariable) {
Type[] bounds = ((TypeVariable<?>) type).getBounds();
return bounds.length == 0 ? Object.class : type2Class(bounds[0]); // erasure is to the left-most bound.
} else if (type instanceof WildcardType) {
Type[] bounds = ((WildcardType) type).getUpperBounds();
return bounds.length == 0 ? Object.class : type2Class(bounds[0]); // erasure is to the left-most upper bound.
} else {
throw new UnsupportedOperationException("cannot handle type class: " + type.getClass());
}
}
请注意,代码未经测试,因此可能包含编译错误。此外,我不确定 GenericArrayType
如何处理 T[][]
等多维数组类型(如果 Object[]
而不是 return Object[][]
=34=] 所以我们需要在这里做额外的工作)。如果需要任何更正,请告诉我。
最后我们在这里尝试做的是在给定 Type
的情况下计算擦除 class 我想知道是否有一些 "standard" 代码可以做到这一点,也许Sun/Oracle 编译器或代码分析器工具的一部分,您只需使用它们的实用程序,就可以省去编码和维护它的麻烦……我快速浏览了一下,没有找到任何东西。