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.
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
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.