Mic*_*hal 15 java generics reflection
测试(使用反射)的最简单方法是什么,给定方法(即java.lang.Method实例)是否具有返回类型,可以安全地转换为List <String>?
请考虑以下代码段:
public static class StringList extends ArrayList<String> {}
public List<String> method1();
public ArrayList<String> method2();
public StringList method3();
Run Code Online (Sandbox Code Playgroud)
所有方法1,2,3都满足要求.为method1测试它很容易(通过getGenericReturnType(),它返回ParameterizedType的实例),但对于方法2和3,它并不那么明显.我想,通过遍历所有getGenericSuperclass()和getGenericInterfaces(),我们可以非常接近,但我没有看到,如何匹配List <E>中的TypeVariable(它发生在超类接口中的某处)与实际type参数(即此E与String匹配的位置).
或者是否有一种完全不同(更容易)的方式,我忽略了?
编辑:对于那些正在研究它的人,这里是method4,它也满足了要求,并显示了一些必须调查的案例:
public interface Parametrized<T extends StringList> {
T method4();
}
Run Code Online (Sandbox Code Playgroud)
我尝试了这个代码,它返回实际的泛型类,所以似乎可以检索类型信息.但是这只适用于方法1和2.方法3似乎没有返回列表类型的字符串,因为海报假定因此失败.
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
try{
Method m = Main.class.getDeclaredMethod("method1", new Class[]{});
instanceOf(m, List.class, String.class);
m = Main.class.getDeclaredMethod("method2", new Class[]{});
instanceOf(m, List.class, String.class);
m = Main.class.getDeclaredMethod("method3", new Class[]{});
instanceOf(m, List.class, String.class);
m = Main.class.getDeclaredMethod("method4", new Class[]{});
instanceOf(m, StringList.class);
}catch(Exception e){
System.err.println(e.toString());
}
}
public static boolean instanceOf (
Method m,
Class<?> returnedBaseClass,
Class<?> ... genericParameters) {
System.out.println("Testing method: " + m.getDeclaringClass().getName()+"."+ m.getName());
boolean instanceOf = false;
instanceOf = returnedBaseClass.isAssignableFrom(m.getReturnType());
System.out.println("\tReturn type test succesfull: " + instanceOf + " (expected '"+returnedBaseClass.getName()+"' found '"+m.getReturnType().getName()+"')");
System.out.print("\tNumber of generic parameters matches: ");
Type t = m.getGenericReturnType();
if(t instanceof ParameterizedType){
ParameterizedType pt = (ParameterizedType)t;
Type[] actualGenericParameters = pt.getActualTypeArguments();
instanceOf = instanceOf
&& actualGenericParameters.length == genericParameters.length;
System.out.println("" + instanceOf + " (expected "+ genericParameters.length +", found " + actualGenericParameters.length+")");
for (int i = 0; instanceOf && i < genericParameters.length; i++) {
if (actualGenericParameters[i] instanceof Class) {
instanceOf = instanceOf
&& genericParameters[i].isAssignableFrom(
(Class) actualGenericParameters[i]);
System.out.println("\tGeneric parameter no. " + (i+1) + " matches: " + instanceOf + " (expected '"+genericParameters[i].getName()+"' found '"+((Class) actualGenericParameters[i]).getName()+"')");
} else {
instanceOf = false;
System.out.println("\tFailure generic parameter is not a class");
}
}
} else {
System.out.println("" + true + " 0 parameters");
}
return instanceOf;
}
public List<String> method1() {
return null;
}
public ArrayList<String> method2() {
return new ArrayList<String>();
}
public StringList method3() {
return null;
}
public <T extends StringList> T method4() {
return null;
}
Run Code Online (Sandbox Code Playgroud)
这输出:
Testing method: javaapplication2.Main.method1 Return type test succesfull: true (expected 'java.util.List' found 'java.util.List') Number of generic parameters matches: true (expected 1, found 1) Generic parameter no. 1 matches: true (expected 'java.lang.String' found 'java.lang.String') Testing method: javaapplication2.Main.method2 Return type test succesfull: true (expected 'java.util.List' found 'java.util.ArrayList') Number of generic parameters matches: true (expected 1, found 1) Generic parameter no. 1 matches: true (expected 'java.lang.String' found 'java.lang.String') Testing method: javaapplication2.Main.method3 Return type test succesfull: false (expected 'java.util.List' found 'com.sun.org.apache.xerces.internal.xs.StringList') Number of generic parameters matches: true 0 parameters Testing method: javaapplication2.Main.method4 Return type test succesfull: true (expected 'com.sun.org.apache.xerces.internal.xs.StringList' found 'com.sun.org.apache.xerces.internal.xs.StringList') Number of generic parameters matches: true 0 parameters
一般来说,仅使用 Java 本身提供的工具来解决这个问题确实不容易。有很多特殊情况(嵌套类、类型参数边界……)需要处理。这就是为什么我编写了一个库来使泛型类型反射更容易:gentyref。我添加了示例代码(以 JUnit 测试的形式)来展示如何使用它来解决此问题:StackoverflowQ182872Test.java。基本上,您只需调用GenericTypeReflector.isSuperType
using a (来自Neil Gafter 的TypeToken
想法)来查看是否是返回类型的超类型。List<String>
我还添加了第五个测试用例,以表明GenericTypeReflector.getExactReturnType
有时需要对返回类型 ( ) 进行额外转换,以将类型参数替换为其值。
归档时间: |
|
查看次数: |
14630 次 |
最近记录: |