16

When writing something like

doit(43, 44, "hello");

the compiler knows which overloaded method is to be called. When I want to do the same via reflection, I need to find out myself, that the method is

doit(Integer, double, CharSequence...);

and obtain it via something like

Class[] types = {Integer.class, double.class, CharSequence[].class};
declaringClass.getDeclaredMethod("doit", types);

I wonder if there's already something allowing me to write just

Method m = getMethod(declaringClass, "doit", 43, 44, "hello");

I wonder if somebody did this already, as the JLS is a bit complicated in this respect.


Actually, behaving exactly like the compiler is impossible as in Phase 1 the compiler accepts only methods matching without boxing and unboxing. When calling my hypothetical getMethod from above, the distinction between primitives and their wrappers is already lost (because of autoboxing when passing arguments via varargs). This problem seems to have no solution, so let's ignore it.

As suggested in an answer, BeanUtils.invokeMethod comes close. It's supposed to find the best match, whatever it means. Looking at MethodUtils.getMatchingAccessibleMethod shows that

  • it knows nothing about varargs
  • it's non-deterministic

so I'm looking for something better.

maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • Out of curiosity, for what reason do you want this? Is there a use case that applies? – Sotirios Delimanolis Apr 17 '14 at 01:40
  • @SotiriosDelimanolis: Not really. Once I needed a simple way for calling private methods (I didn't like to make them `@VisibleForTesting`), so I wrote a tiny utility class and found out it's far from perfect. It's good enough for what I need it for, but I became curious if it's possible to do it "right". – maaartinus Apr 17 '14 at 01:48

2 Answers2

1

Alternatively you could use Bean Utils from Apache Commons:

public static Method getAccessibleMethod(
        Class clazz,
        String methodName,
        Class[] parameterTypes)

According documentation:

Return an accessible method (that is, one that can be invoked via reflection) with given name and parameters. If no such method can be found, return null. This is just a convenient wrapper for getAccessibleMethod(Method method).

Parameters: clazz - get method from this class methodName - get method with this name parameterTypes - with these parameters types

The implementation get the accessible method and goes up in the hierarchy until it founds a match to it.

Direct to the Invocation

In order to perform invocation directly as you asked, you could use this method from the same API:

public static Object invokeExactMethod(
        Object object,
        String methodName,
        Object[] args,
        Class[] parameterTypes)
        throws
        NoSuchMethodException,
        IllegalAccessException,
        InvocationTargetException

or even

public static Object invokeExactMethod(
        Object object,
        String methodName,
        Object[] args)
        throws
        NoSuchMethodException,
        IllegalAccessException,
        InvocationTargetException

that first locates the method using getAccessibleMethod and later on invokes it.

Francisco Spaeth
  • 23,493
  • 7
  • 67
  • 106
  • This doesn't work: `getAccessibleMethod` requires parameter types, and finds nothing when given the real types of arguments. `invokeExactMethod` only uses `getAccessibleMethod`. I've found `invokeMethod`, which really tries to find the matching method, but it doesn't work either! – maaartinus Aug 25 '12 at 01:16
0

The MethodHandle is a new way to get a overloaded method using a signature (java 7):

Example:

static class A {
    public String get() {
        return "A";
    }
}

static class B extends A {
    public String get() {
        return "B";
    }
}

public static void main(String[] args) throws Throwable {

    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodType mt = MethodType.methodType(String.class);
    MethodHandle mh = lookup.findVirtual(A.class, "get", mt);;

    System.out.println(mh.invoke(new B()));
}

Outputs:

B
dacwe
  • 43,066
  • 12
  • 116
  • 140
  • 1
    You've answered a different question, namely "How to invoke an overridden method?", while I was asking "How to invoke the method *the compiler would choose* for my arguments?". Nonetheless, +1 as I learned something new and interesting. – maaartinus Aug 01 '12 at 21:18
  • Sorry, I didn't read the whole question.. I also just learned about the new `java.lang.invoke` package,but your in luck, I [answered just such a question](http://stackoverflow.com/questions/4188919/how-to-search-for-java-api-methods-by-type-signature) a long time ago (you need to add the variable argument thing, and remove the "all permutations of arguments" but that seems like a simple thing to do! :)) – dacwe Aug 01 '12 at 21:48
  • 1
    The linked answer may find *all* possibly applicable methods, but I want the one the *compiler chooses to invoke*. – maaartinus Aug 25 '12 at 01:19
  • the question is about overloaded methods not overriding. – Bahattin Ungormus Oct 02 '19 at 16:00