[英]How to dry run Method.invoke()
java.lang.reflect.Method.invoke()
文档指出它引发了IllegalArgumentException
IllegalArgumentException
如果该方法是一个实例方法,并且指定的对象参数不是声明基础方法(或其子类或实现者)的类或接口的实例; 如果实际参数和形式参数的数量不同; 如果原始参数的展开转换失败; 或者在可能的解包之后,无法通过方法调用转换将参数值转换为相应的形式参数类型。
有没有一种方法可以测试方法是否在不调用给定参数的情况下抛出IllegalArgumentException
?
可以手动检查实例,方法和参数数量的正确性,并可以通过搭载本机Java机制来检查参数的可分配性。
public class Methods {
public static boolean isInvocable(Method method, Object instance,
Object... arguments) {
return correctInstance(instance, method)
&& correctArguments(arguments, method);
}
private static boolean correctInstance(Object instance, Method method) {
return Modifier.isStatic(method.getModifiers())
|| method.getDeclaringClass().isInstance(instance);
}
private static boolean correctArguments(Object[] arguments, Method method) {
Class<?>[] parameters = method.getParameterTypes();
if (parameters.length != arguments.length) {
return false;
}
for (int i = 0; i < parameters.length; i++) {
if (!correctArgument(arguments[i], parameters[i])) {
return false;
}
}
return true;
}
private static boolean correctArgument(Object instance, Class<?> type) {
return type.isPrimitive()
? correctPrimitive(instance, type)
: instance == null || type.isAssignableFrom(instance.getClass());
}
private static boolean correctPrimitive(Object argument, Class<?> type) {
try {
Method method = Overloading.class.getDeclaredMethod("method", type);
method.setAccessible(true);
method.invoke(null, argument);
return true;
} catch (IllegalArgumentException e) {
return false;
} catch (NoSuchMethodException e) {
throw new Error(e);
} catch (IllegalAccessException e) {
throw new Error(e);
} catch (InvocationTargetException e) {
throw new Error(e);
}
}
@SuppressWarnings("unused")
private static class Overloading {
private static void method(byte argument) {}
private static void method(short argument) {}
private static void method(int argument) {}
private static void method(long argument) {}
private static void method(float argument) {}
private static void method(double argument) {}
private static void method(boolean argument) {}
private static void method(char argument) {}
}
}
是的,您可以使用Reflection API中的getDeclaredMethod
来验证是否声明了具有给定签名的特定方法。 可以在文档(位于底部)中找到一个示例: http : //docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html
尽管我没有对其进行测试,但这可能会按原样工作:
public boolean hasMethod( Class<?> clazz, String methodName, Class[] argTypes ) {
try {
clazz.getDeclaredMethod( methodName, argTypes );
return true;
} catch( NoSuchMethodException e ) {
return false;
} catch( Exception e ) {
// something else went wrong
// you definitely wanna handle this case more gracefully
throw new IllegalStateException( "Uh-Oh!", e );
}
}
// example call for a method named someMethod that takes an array of strings
// as its only argument
Class[] argTypes = new Class[] { String[].class };
boolean hasMethod = hasMethod( yourClass, "someMethod", argTypes );
你在问什么
在运行时,首先创建方法,实例和参数列表,仅在一段时间后在代码中的其他位置调用它。 我想及早发现问题,而不是浪费时间并使用非信息性堆栈跟踪报告异常。
不可能。 对于一些
IllegalArgumentException-如果该方法是一个实例方法,并且指定的对象参数不是声明基础方法(或其子类或实现者)的类或接口的实例; 如果实际参数和形式参数的数量不同; 如果原始参数的展开转换失败; 或者在可能的解包之后,无法通过方法调用转换将参数值转换为相应的形式参数类型。
您可以检查一下自己。 例如,您可以在instanceof
上执行instanceof,或者在其上使用Class#isInstance()
。 您可以比较您拥有的参数数量和该方法所需的参数数量。 对于基元的类型转换,要进行测试有些困难,并且可能取决于实际知道要转换的类型。
最好的选择是在需要并处理IllegalArgumentException
时invoke
它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.