Sam Brannen opened SPR-8644 and commented

Status Quo

ReflectionUtils.findMethod(Class<?>, String, Class<?>...) currently only finds methods with exact matches for supplied the argument types. findMethod() also does not find methods that accept variable arguments (see ReflectionUtilsTests.findMethodWithVarArgs() for an example of a failing test).

MethodInvoker on the other hand finds methods with compatible argument types.

As an aside, invokeMethod(Object, String, Object...) in ReflectionTestUtils could not be implemented using ReflectionUtils due to these limitations.

Deliverable

Either modify ReflectionUtils.findMethod(Class<?>, String, Class<?>...) or introduce a new method in ReflectionUtils to provide support for finding methods with compatible argument lists, specifically:

  1. for methods that accepts var-args
  2. for example, a call to findMethod(clazz, "add", int.class, int.class, int.class) should find a a method named "add" with a parameter declaration of (int... args).
  3. of course, a call to findMethod(clazz, "add", new int[] {int.class, int.class, int.class}) will find the var-args method, but this requires specific knowledge of the implementation and therefore does not lend itself to dynamic, reflective use cases.
  4. with regard to type conversion, either due automatic boxing and unboxing of primitives or due to inheritance.
  5. for example, a call to findMethod(clazz, "foo", Integer.class) should find a method named "foo" that accepts an int. For example, the following unit test should pass.
public class Test {

    public void foo(int a) {
        System.out.println("a = " + a);
    }

    @Test
    public void testFoo() {
        Method method = ReflectionUtils.findMethod(getClass(), "foo", Integer.class);
        assertNotNull(method);
    }
}
  • similarly, a call to findMethod(clazz, "foo", Integer.class) should find a method named "foo" that accepts a Number if there is no "foo" method that accepts an Integer.

Affects: 3.0.6

Attachments: - ReflectionUtils.java.patch (3.31 kB)

Issue Links: - #13275 Introduce a generic method for invoking any non-public method in ReflectionTestUtils

Referenced from: commits https://github.com/spring-projects/spring-framework/commit/16fb3cb4b3fe6db341277889b20a2e4f774e2cc4, https://github.com/spring-projects/spring-framework/commit/1a34f6459d0e49e4fd60aa3644ad17fa117854d9

2 votes, 3 watchers

Comment From: spring-projects-issues

Sean Patrick Floyd commented

Here's a patch that implements this functionality. I have often missed this myself.

Comment From: spring-projects-issues

Sean Patrick Floyd commented

Of course I would also welcome if this line vanished from the Apidocs: "Only intended for internal use."

I think ReflectionUtils is great, and I know of no equivalent Utility class for Reflection in the usual utility libraries.

Comment From: spring-projects-issues

Sam Brannen commented

Sean,

Thanks for submitting the patch; we'll consider it. Note, however, that Spring's MethodInvoker already has this functionality.

Also, your implementation handles case #2 above (i.e., assignable from), but it does not support var-args. I've modified this issue to address var-args as well; however, it may turn out that support for var-args warrants a separate issue.

Cheers,

Sam

Comment From: spring-projects-issues

Sean Patrick Floyd commented

Sam,

I agree, the code in MethodInvoker is better. Perhaps you should refactor that to make it accessible in static way (and move the code to ReflectionUtils or ClassUtils).

Sean

Comment From: spring-projects-issues

Juergen Hoeller commented

Closing groups of outdated issues. Please reopen if still relevant.