如何获取形式方法参数类型的参数?
How do I get the argument of the formal method parameter type?
我的方法只有一个 Event<Something>
类型的参数,需要提取 Something
或其原始类型。它可能看起来像
void method1(Event<MyEnum1> event) {}
<E extends Enum<E>> method2(Event<E> event) {}
<K, V> method3(Event<Map<K, V>> event) {}
我想要一个函数映射
method1 -> MyEnum.class
method2 -> Enum.class
method3 -> Map.class
对于method1
,使用(ParameterizedType) method.getGenericParameterTypes()
很容易。对于 method2
,我可以使用 Guava
TypeToken.of(method.getDeclaringClass())
.method(method)
.getTypeParameters()[0]
.getBounds()
获得Type
和
TypeToken.of(method.getDeclaringClass())
.method(method)
.getParameters()
.get(0)
获得Parameter
。我想,我需要使用 Type
来解决 Parameter
,但我被困在这里了。
我不太关心 method3
,但了解一般方法会很好。我不关心实际参数的类型(我知道擦除)。
您不需要 TypeToken
。 java.lang.reflect
提供您需要的一切。
您需要考虑多种情况。我将假设所提供的任何方法的第一个参数始终是 Event
类型(或者实际上是参数化类型)。
您需要处理 Type
的 5 种子类型。从您的示例中,您需要检查类型参数是具体类型(MyEnum
)、类型变量(E
受 Enum
限制)还是参数化类型(Map<K,V>
).
此外,还有 WildcardType
可以像类型变量和提取边界一样处理。最后,您必须处理具有 GenericArrayType
(Event<T[]>
或 Event<List<String>[]>
)的泛型数组类型。我已将这些排除在外,但它只是对其他类型重新应用相同的规则。
我假设,对于类型变量的情况,边界可能是一些其他类型的变量,所以我们需要重复直到找到具体的边界。
// get raw type argument of first parameter
public static Class<?> getRawTypeArgument(Method method) {
Parameter parameter = method.getParameters()[0];
Type type = parameter.getParameterizedType();
/// assume it's parameterized
ParameterizedType parameterizedType = (ParameterizedType) type;
// assume there's one type argument
Type typeArgument = parameterizedType.getActualTypeArguments()[0];
if (typeArgument instanceof TypeVariable<?>) {
TypeVariable<?> typeVariableArgument = (TypeVariable<?>) typeArgument;
return recursivelyExtractBound(typeVariableArgument);
} else if (typeArgument instanceof Class<?>) {
return (Class<?>) typeArgument;
} else if (typeArgument instanceof ParameterizedType) {
ParameterizedType parameterizedTypeArgument = (ParameterizedType) typeArgument;
return (Class<?>) parameterizedTypeArgument.getRawType();
}
throw new AssertionError("Consider wildcard and generic type");
}
private static Class<?> recursivelyExtractBound(TypeVariable<?> typeVariable) {
// assume first
Type bound = typeVariable.getBounds()[0];
if (bound instanceof Class<?>) {
return (Class<?>) bound;
} else if (bound instanceof TypeVariable<?>) {
TypeVariable<?> nested = (TypeVariable<?>) bound;
return recursivelyExtractBound(nested);
} else if (bound instanceof ParameterizedType) {
ParameterizedType parameterizedTypeArgument = (ParameterizedType) bound;
return (Class<?>) parameterizedTypeArgument.getRawType();
}
throw new AssertionError("Are there others?");
}
附带小驱动程序
public static void main(String[] args) throws Exception {
Class<?> clazz = Example.class;
for (Method method : clazz.getDeclaredMethods()) {
if (!method.getName().startsWith("method")) {
continue;
}
System.out.println("Method '" + method + "' -> " + getRawTypeArgument(method));
}
}
以上打印出来
Method 'java.lang.Object com.example.Example.method3(com.example.root.Event)' -> interface java.util.Map
Method 'java.lang.Object com.example.Example.method2(com.example.root.Event)' -> class java.lang.Enum
Method 'void com.example.Example.method1(com.example.Event)' -> class com.example.MyEnum1
我的方法只有一个 Event<Something>
类型的参数,需要提取 Something
或其原始类型。它可能看起来像
void method1(Event<MyEnum1> event) {}
<E extends Enum<E>> method2(Event<E> event) {}
<K, V> method3(Event<Map<K, V>> event) {}
我想要一个函数映射
method1 -> MyEnum.class
method2 -> Enum.class
method3 -> Map.class
对于method1
,使用(ParameterizedType) method.getGenericParameterTypes()
很容易。对于 method2
,我可以使用 Guava
TypeToken.of(method.getDeclaringClass())
.method(method)
.getTypeParameters()[0]
.getBounds()
获得Type
和
TypeToken.of(method.getDeclaringClass())
.method(method)
.getParameters()
.get(0)
获得Parameter
。我想,我需要使用 Type
来解决 Parameter
,但我被困在这里了。
我不太关心 method3
,但了解一般方法会很好。我不关心实际参数的类型(我知道擦除)。
您不需要 TypeToken
。 java.lang.reflect
提供您需要的一切。
您需要考虑多种情况。我将假设所提供的任何方法的第一个参数始终是 Event
类型(或者实际上是参数化类型)。
您需要处理 Type
的 5 种子类型。从您的示例中,您需要检查类型参数是具体类型(MyEnum
)、类型变量(E
受 Enum
限制)还是参数化类型(Map<K,V>
).
此外,还有 WildcardType
可以像类型变量和提取边界一样处理。最后,您必须处理具有 GenericArrayType
(Event<T[]>
或 Event<List<String>[]>
)的泛型数组类型。我已将这些排除在外,但它只是对其他类型重新应用相同的规则。
我假设,对于类型变量的情况,边界可能是一些其他类型的变量,所以我们需要重复直到找到具体的边界。
// get raw type argument of first parameter
public static Class<?> getRawTypeArgument(Method method) {
Parameter parameter = method.getParameters()[0];
Type type = parameter.getParameterizedType();
/// assume it's parameterized
ParameterizedType parameterizedType = (ParameterizedType) type;
// assume there's one type argument
Type typeArgument = parameterizedType.getActualTypeArguments()[0];
if (typeArgument instanceof TypeVariable<?>) {
TypeVariable<?> typeVariableArgument = (TypeVariable<?>) typeArgument;
return recursivelyExtractBound(typeVariableArgument);
} else if (typeArgument instanceof Class<?>) {
return (Class<?>) typeArgument;
} else if (typeArgument instanceof ParameterizedType) {
ParameterizedType parameterizedTypeArgument = (ParameterizedType) typeArgument;
return (Class<?>) parameterizedTypeArgument.getRawType();
}
throw new AssertionError("Consider wildcard and generic type");
}
private static Class<?> recursivelyExtractBound(TypeVariable<?> typeVariable) {
// assume first
Type bound = typeVariable.getBounds()[0];
if (bound instanceof Class<?>) {
return (Class<?>) bound;
} else if (bound instanceof TypeVariable<?>) {
TypeVariable<?> nested = (TypeVariable<?>) bound;
return recursivelyExtractBound(nested);
} else if (bound instanceof ParameterizedType) {
ParameterizedType parameterizedTypeArgument = (ParameterizedType) bound;
return (Class<?>) parameterizedTypeArgument.getRawType();
}
throw new AssertionError("Are there others?");
}
附带小驱动程序
public static void main(String[] args) throws Exception {
Class<?> clazz = Example.class;
for (Method method : clazz.getDeclaredMethods()) {
if (!method.getName().startsWith("method")) {
continue;
}
System.out.println("Method '" + method + "' -> " + getRawTypeArgument(method));
}
}
以上打印出来
Method 'java.lang.Object com.example.Example.method3(com.example.root.Event)' -> interface java.util.Map
Method 'java.lang.Object com.example.Example.method2(com.example.root.Event)' -> class java.lang.Enum
Method 'void com.example.Example.method1(com.example.Event)' -> class com.example.MyEnum1