1

java.lang.reflect.Method.invoke()文档指出它抛出IllegalArgumentException

IllegalArgumentException- 如果方法是实例方法并且指定的对象参数不是声明底层方法的类或接口的实例(或其子类或实现者);如果实际参数和形式参数的数量不同;如果原始参数的展开转换失败;或者,如果在可能的展开之后,参数值不能通过方法调用转换转换为相应的形式参数类型。

有没有办法在IllegalArgumentException不调用给定参数的情况下测试方法是否抛出?

4

3 回答 3

1

可以手动检查实例、方法和参数数量的正确性,并通过搭载本机 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) {}
  }
}
于 2014-02-21T09:17:56.897 回答
0

是的,您可以使用getDeclaredMethod反射 API 来验证是否声明了具有给定签名的特定方法。可以在文档(底部)中找到一个示例: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 );
于 2013-09-08T14:07:11.710 回答
0

你在问什么

在运行时,首先会创建方法、实例和参数列表,然后在一段时间后在代码中的不同位置调用它。我想及早发现问题,而不是浪费时间并使用非信息性堆栈跟踪报告异常。

不可能。对于一些

IllegalArgumentException - 如果方法是实例方法并且指定的对象参数不是声明底层方法的类或接口的实例(或其子类或实现者);如果实际参数和形式参数的数量不同;如果原始参数的展开转换失败;或者,如果在可能的展开之后,参数值不能通过方法调用转换转换为相应的形式参数类型。

你可以自己检查。例如,您可以instanceof在实例上执行操作,或者更确切地说Class#isInstance()在其上使用。您可以比较您拥有的参数数量和方法所需的参数数量。对于原语的类型转换,测试起来有点困难,并且可能取决于实际知道哪些类型会被转换。

您最好的选择是invoke在您需要并处理IllegalArgumentException.

于 2013-09-08T14:24:10.950 回答