I like @Radiodef's answer, but it is missing something: getDeclaredClass
only returns the methods declared in the Class
itself, not in its superclasses. Since superclass methods are typically also considered methods of the class, you need to search through them too.
Second, you when you specify a return type, you typically want to find a method that returns something that you can assign to that return type, not the exact return type. In Java, it is legal for a method that overrides a superclass method, to return a subclass of return type of the superclass. I.e. the superclass has Number myNumber()
, then the subclass may have @Override Integer myNumber()
.
If you take that into account as well, you arrive at this code:
public static Method findMethod(Class<?> returnType, Collection<? extends Class<?>> containingClasses, String functionName, Class<?>[] parameters) {
for (Class<?> containingClass : containingClasses) {
Method m = findMethodInClass(returnType, containingClass, functionName, parameters);
if (m != null)
return m;
}
return null;
}
private static Method findMethodInClass(Class<?> returnType, Class<?> containingClass, String functionName, Class<?>[] parameters) {
for (Method m : containingClass.getDeclaredMethods()) {
if (checkMethod(m, returnType, functionName, parameters))
return m;
}
if (containingClass.getSuperclass() != null)
return findMethodInClass(returnType, containingClass.getSuperclass(), functionName, parameters);
else
return null;
}
private static boolean checkMethod(Method method, Class<?> returnType, String functionName, Class<?>[] parameters) {
if (!method.getName().equals(functionName))
return false;
// Also allow overridden classes that return a subtype of the requested type
if (!returnType.isAssignableFrom(method.getReturnType()))
return false;
Class<?>[] actualParameters = method.getParameterTypes();
if (actualParameters.length != parameters.length)
return false;
for (int i = 0; i < actualParameters.length; i++) {
if (actualParameters[i] != parameters[i])
return false;
}
return true;
}
public static void main(String[] args) {
System.out.println(findMethod(Integer.TYPE, Collections.singleton(Integer.class), "intValue", new Class<?>[0]));
System.out.println(findMethod(String.class, Collections.singleton(Random.class), "toString", new Class<?>[0]));
}
I would advise against using any classes in the sun.*
packages for any reason, though; including sun.reflect.ReflectionFactory
. These classes are not part of the supported, public interface of Java and can be changed or removed at any time.
See: what happened to sun.* packages