package me.ele.amigo.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodUtils {
public static Object invokeMethod(Object object, String methodName, Object[] args, Class<?>[]
parameterTypes) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
parameterTypes = Utils.nullToEmpty(parameterTypes);
args = Utils.nullToEmpty(args);
Method method = getMatchedMethod(object.getClass(), methodName, parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on object: "
+ object.getClass().getName());
}
method.setAccessible(true);
return method.invoke(object, args);
}
public static Object invokeStaticMethod(Class clazz, String methodName, Object[] args,
Class<?>[] parameterTypes) throws
NoSuchMethodException, IllegalAccessException, InvocationTargetException {
parameterTypes = Utils.nullToEmpty(parameterTypes);
args = Utils.nullToEmpty(args);
Method method = getMatchedMethod(clazz, methodName, parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on object: "
+ clazz.getName());
}
method.setAccessible(true);
return method.invoke(null, args);
}
public static Object invokeStaticMethod(Class clazz, String methodName, Object... args)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
args = Utils.nullToEmpty(args);
Class<?>[] parameterTypes = Utils.toClass(args);
return invokeStaticMethod(clazz, methodName, args, parameterTypes);
}
public static Object invokeMethod(Object object, String methodName, Object... args)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
args = Utils.nullToEmpty(args);
Class<?>[] parameterTypes = Utils.toClass(args);
return invokeMethod(object, methodName, args, parameterTypes);
}
public static Method getMatchedMethod(Class<?> cls, String methodName, Class<?>...
parameterTypes) throws NoSuchMethodException {
try {
final Method method = cls.getDeclaredMethod(methodName, parameterTypes);
MemberUtils.setAccessibleWorkaround(method);
return method;
} catch (final NoSuchMethodException e) {
//ignore
}
Method bestMatch = null;
while (cls != null) {
// search through all methods
final Method[] methods = cls.getDeclaredMethods();
for (final Method method : methods) {
// compare name and parameters
if (method.getName().equals(methodName) && MemberUtils.isAssignable
(parameterTypes, method.getParameterTypes(), true)) {
bestMatch = method;
final Method accessibleMethod = getMethodFromElse(method);
if (accessibleMethod != null && MemberUtils
.compareParameterTypes(
accessibleMethod.getParameterTypes(),
bestMatch.getParameterTypes(),
parameterTypes) < 0) {
bestMatch = accessibleMethod;
break;
}
}
}
if (bestMatch == null) {
cls = cls.getSuperclass();
} else {
break;
}
}
if (bestMatch != null) {
MemberUtils.setAccessibleWorkaround(bestMatch);
}
return bestMatch;
}
private static Method getMethodFromElse(Method method) {
// If the declaring class is public, we are done
final Class<?> cls = method.getDeclaringClass();
final String methodName = method.getName();
final Class<?>[] parameterTypes = method.getParameterTypes();
// Check the implemented interfaces and subinterfaces
method = getAccessibleMethodFromInterfaceNest(cls, methodName, parameterTypes);
// Check the superclass chain
if (method == null) {
method = getAccessibleMethodFromSuperclass(cls, methodName, parameterTypes);
}
return method;
}
private static Method getAccessibleMethodFromSuperclass(final Class<?> cls, final String
methodName, final Class<?>... parameterTypes) {
Class<?> parentClass = cls.getSuperclass();
while (parentClass != null) {
try {
return parentClass.getDeclaredMethod(methodName, parameterTypes);
} catch (final NoSuchMethodException e) {
}
parentClass = parentClass.getSuperclass();
}
return null;
}
private static Method getAccessibleMethodFromInterfaceNest(Class<?> cls, final String
methodName, final Class<?>... parameterTypes) {
// Search up the superclass chain
for (; cls != null; cls = cls.getSuperclass()) {
// Check the implemented interfaces of the parent class
final Class<?>[] interfaces = cls.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
// Is this interface public?
// Does the method exist on this interface?
try {
return interfaces[i].getDeclaredMethod(methodName, parameterTypes);
} catch (final NoSuchMethodException e) { // NOPMD
/*
* Swallow, if no method is found after the loop then this
* method returns null.
*/
}
// Recursively check our parent interfaces
Method method = getAccessibleMethodFromInterfaceNest(interfaces[i], methodName,
parameterTypes);
if (method != null) {
return method;
}
}
}
return null;
}
}