All Downloads are FREE. Search and download functionalities are using the official Maven repository.

panda.lang.reflect.Methods Maven / Gradle / Ivy

package panda.lang.reflect;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import panda.bean.Beans;
import panda.lang.Arrays;
import panda.lang.Asserts;
import panda.lang.Classes;
import panda.lang.Collections;
import panda.lang.collection.MultiKey;

/**
 * utility class for Method
 * 
 */
@SuppressWarnings("unchecked")
public class Methods {
	/**
	 * @param method method
	 * @param index parameter index
	 * @return generic parameter type or class
	 */
	public static Type getParameterType(Method method, int index) {
		Type type = method.getGenericParameterTypes()[index];
		if (type == null) {
			type = method.getParameterTypes()[index];
		}
		return type;
	}
	
	/**
	 * Gets all methods of the given class and its parents (if any).
	 * @param cls the class
	 * @return the method list
	 */
	public static List getAllMethods(Class cls) {
		List list = new ArrayList();
		while (null != cls) {
			Method[] ms = cls.getDeclaredMethods();
			for (Method m : ms) {
				list.add(m);
			}
			cls = cls.getSuperclass();
		}
		return list;
	}

	/**
	 * call getDeclaredMethods(xx, Object.class)
	 * @param cls the class
	 * @return the method list
	 */
	public static List getDeclaredMethods(Class cls) {
		return getDeclaredMethods(cls, Object.class);
	}

	/**
	 * Gets declared methods of the given class and its parents until top class.
	 * Discard duplicate method of parents.
	 * @param cls the class
	 * @param top the top base class
	 * @return the method list
	 */
	public static List getDeclaredMethods(Class cls, Class top) {
		return getDeclaredMethods(cls, top, null);
	}

	public static interface MethodFilter {
		boolean accept(Method m);
	}

	/**
	 * Gets declared methods of the given class and its parents until top class.
	 * Discard duplicate method of parents.
	 * @param cls the class
	 * @param top the top base class
	 * @param mf method filter
	 * @return the method list
	 */
	public static List getDeclaredMethods(Class cls, Class top, MethodFilter mf) {
		List dms = new ArrayList();
		Set set = new HashSet();
		List mi = new ArrayList();
		while (cls != top && cls != null) {
			Method[] ms = cls.getDeclaredMethods();
			for (Method m : ms) {
				if (mf != null && !mf.accept(m)) {
					continue;
				}
				
				mi.clear();
				mi.add(m.getName());
				Collections.addAll(mi, m.getParameterTypes());
				
				MultiKey key = new MultiKey(mi.toArray());
				if (set.contains(key)) {
					continue;
				}
				
				set.add(key);
				dms.add(m);
			}
			cls = cls.getSuperclass();
		}
		return dms;
	}

	public static Map getDeclaredGetterMethods(Class cls) {
		Map dms = new HashMap();
		while (cls != Object.class && cls != null) {
			Method[] ms = cls.getDeclaredMethods();
			for (Method m : ms) {
				String n = Beans.getGetterBeanName(m);
				if (n != null && !dms.containsKey(n)) {
					dms.put(n, m);
				}
			}
			cls = cls.getSuperclass();
		}
		return dms;
	}

	public static Map getDeclaredSetterMethods(Class cls) {
		Map dms = new HashMap();
		while (cls != Object.class && cls != null) {
			Method[] ms = cls.getDeclaredMethods();
			for (Method m : ms) {
				String n = Beans.getSetterBeanName(m);
				if (n != null && !dms.containsKey(n)) {
					dms.put(n, m);
				}
			}
			cls = cls.getSuperclass();
		}
		return dms;
	}
	
	/**
	 * @param cls the class
	 * @param ann annotation
	 * @return methods
	 */
	public static  List getAnnotationMethods(final Class cls, final Class ann) {
		return getDeclaredMethods(cls, Object.class, new MethodFilter() {
			@Override
			public boolean accept(Method m) {
				return m.isAnnotationPresent(ann);
			}
		});
	}

	/**
	 * 

* Invoke a named method. *

* * @param object object * @param methodName get method with this name * @return The value returned by the invoked method */ public static Object safeCall(Object object, String methodName) { try { return invokeMethod(object, methodName); } catch (Exception e) { return null; } } /** *

* Invoke a named method whose parameter type matches the object type. *

*

* The behaviour of this method is less deterministic than invokeExactMethod(). It * loops through all methods with names that match and then executes the first it finds with * compatable parameters. *

*

* This method supports calls to methods taking primitive parameters via passing in wrapping * classes. So, for example, a Boolean class would match a boolean * primitive. *

*

* This is a convenient wrapper for * {@link #invokeMethod(Object object,String methodName,Object [] args)}. *

* * @param object invoke method on this object * @param methodName get method with this name * @param arg use this argument * @return The value returned by the invoked method */ public static Object safeCall(Object object, String methodName, Object arg) { try { return invokeMethod(object, methodName, arg); } catch (Exception e) { return null; } } /** *

* Invoke a named method whose parameter type matches the object type. *

*

* The behaviour of this method is less deterministic than * {@link #invokeExactMethod(Object object,String methodName,Object [] args)}. It loops through * all methods with names that match and then executes the first it finds with compatable * parameters. *

*

* This method supports calls to methods taking primitive parameters via passing in wrapping * classes. So, for example, a Boolean class would match a boolean * primitive. *

*

* This is a convenient wrapper for * {@link #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}. *

* * @param object invoke method on this object * @param methodName get method with this name * @param args use these arguments - treat null as empty array * @return The value returned by the invoked method */ public static Object safeCall(Object object, String methodName, Object[] args) { try { return invokeMethod(object, methodName, args); } catch (Exception e) { return null; } } /** *

* Invoke a named method whose parameter type matches the object type. *

*

* The behaviour of this method is less deterministic than * {@link #invokeExactMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)} * . It loops through all methods with names that match and then executes the first it finds * with compatable parameters. *

*

* This method supports calls to methods taking primitive parameters via passing in wrapping * classes. So, for example, a Boolean class would match a boolean * primitive. *

* * @param object invoke method on this object * @param methodName get method with this name * @param args use these arguments - treat null as empty array * @param parameterTypes match these parameters - treat null as empty array * @return The value returned by the invoked method */ public static Object safeCall(Object object, String methodName, Object[] args, Class[] parameterTypes) { try { return invokeMethod(object, methodName, args, parameterTypes); } catch (Exception e) { return null; } } /** *

* Invoke a named method. *

* * @param object object * @param methodName get method with this name * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeMethod(Object object, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { return invokeMethod(object, methodName, Arrays.EMPTY_OBJECT_ARRAY); } /** *

* Invoke a named method whose parameter type matches the object type. *

*

* The behaviour of this method is less deterministic than invokeExactMethod(). It * loops through all methods with names that match and then executes the first it finds with * compatable parameters. *

*

* This method supports calls to methods taking primitive parameters via passing in wrapping * classes. So, for example, a Boolean class would match a boolean * primitive. *

*

* This is a convenient wrapper for * {@link #invokeMethod(Object object,String methodName,Object [] args)}. *

* * @param object invoke method on this object * @param methodName get method with this name * @param arg use this argument * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeMethod(Object object, String methodName, Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Object[] args = { arg }; return invokeMethod(object, methodName, args); } /** *

* Invoke a named method whose parameter type matches the object type. *

*

* The behaviour of this method is less deterministic than * {@link #invokeExactMethod(Object object,String methodName,Object [] args)}. It loops through * all methods with names that match and then executes the first it finds with compatable * parameters. *

*

* This method supports calls to methods taking primitive parameters via passing in wrapping * classes. So, for example, a Boolean class would match a boolean * primitive. *

*

* This is a convenient wrapper for * {@link #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}. *

* * @param object invoke method on this object * @param methodName get method with this name * @param args use these arguments - treat null as empty array * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeMethod(Object object, String methodName, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { args = Arrays.nullToEmpty(args); final Class[] parameterTypes = Classes.toClass(args); return invokeMethod(object, methodName, args, parameterTypes); } /** *

* Invoke a named method whose parameter type matches the object type. *

*

* The behaviour of this method is less deterministic than * {@link #invokeExactMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)} * . It loops through all methods with names that match and then executes the first it finds * with compatable parameters. *

*

* This method supports calls to methods taking primitive parameters via passing in wrapping * classes. So, for example, a Boolean class would match a boolean * primitive. *

* * @param object invoke method on this object * @param methodName get method with this name * @param args use these arguments - treat null as empty array * @param parameterTypes match these parameters - treat null as empty array * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { parameterTypes = Arrays.nullToEmpty(parameterTypes); args = Arrays.nullToEmpty(args); final Method method = getMatchingAccessibleMethod(object.getClass(), methodName, parameterTypes); if (method == null) { throw new NoSuchMethodException("No such accessible method: " + methodName + "() on object: " + object.getClass().getName()); } return method.invoke(object, args); } /** *

* Invoke a method whose parameter type matches exactly the object type. *

*

* This is a convenient wrapper for * {@link #invokeExactMethod(Object object,String methodName,Object [] args)}. *

* * @param object invoke method on this object * @param methodName get method with this name * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeExactMethod(Object object, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { return invokeExactMethod(object, methodName, null); } /** *

* Invoke a method whose parameter type matches exactly the object type. *

*

* This is a convenient wrapper for * {@link #invokeExactMethod(Object object,String methodName,Object [] args)}. *

* * @param object invoke method on this object * @param methodName get method with this name * @param arg use this argument * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeExactMethod(Object object, String methodName, Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Object[] args = { arg }; return invokeExactMethod(object, methodName, args); } /** *

* Invoke a method whose parameter types match exactly the object types. *

*

* This uses reflection to invoke the method obtained from a call to * getAccessibleMethod(). *

* * @param object invoke method on this object * @param methodName get method with this name * @param args use these arguments - treat null as empty array * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeExactMethod(Object object, String methodName, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { args = Arrays.nullToEmpty(args); final Class[] parameterTypes = Classes.toClass(args); return invokeExactMethod(object, methodName, args, parameterTypes); } /** *

* Invoke a method whose parameter types match exactly the parameter types given. *

*

* This uses reflection to invoke the method obtained from a call to * getAccessibleMethod(). *

* * @param object invoke method on this object * @param methodName get method with this name * @param args use these arguments - treat null as empty array * @param parameterTypes match these parameters - treat null as empty array * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeExactMethod(Object object, String methodName, Object[] args, Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { args = Arrays.nullToEmpty(args); parameterTypes = Arrays.nullToEmpty(parameterTypes); Method method = getAccessibleMethod(object.getClass(), methodName, parameterTypes); if (method == null) { throw new NoSuchMethodException("No such accessible method: " + methodName + "() on object: " + object.getClass().getName()); } return method.invoke(object, args); } /** *

* Invoke a static method whose parameter types match exactly the parameter types given. *

*

* This uses reflection to invoke the method obtained from a call to * {@link #getAccessibleMethod(Class, String, Class[])}. *

* * @param cls invoke static method on this class * @param methodName get method with this name * @param args use these arguments - treat null as empty array * @param parameterTypes match these parameters - treat null as empty array * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeExactStaticMethod(Class cls, String methodName, Object[] args, Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { args = Arrays.nullToEmpty(args); parameterTypes = Arrays.nullToEmpty(parameterTypes); Method method = getAccessibleMethod(cls, methodName, parameterTypes); if (method == null) { throw new NoSuchMethodException("No such accessible method: " + methodName + "() on class: " + cls.getName()); } return method.invoke(null, args); } /** *

* Invoke a named static method. *

* * @param method the method such as java.util.Calendar@getInstance * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection * @throws ClassNotFoundException if the class is not found */ public static Object invokeStaticMethod(String method) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { String[] ss = method.split("@"); Class cls = Classes.getClass(ss[0]); return invokeStaticMethod(cls, ss[1]); } /** *

* Invoke a named static method. *

* * @param cls invoke static method on this class * @param methodName get method with this name * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeStaticMethod(Class cls, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { return invokeStaticMethod(cls, methodName, new Object[0]); } /** *

* Invoke a named static method whose parameter type matches the object type. *

*

* The behaviour of this method is less deterministic than * {@link #invokeExactMethod(Object, String, Object[], Class[])}. It loops through all methods * with names that match and then executes the first it finds with compatable parameters. *

*

* This method supports calls to methods taking primitive parameters via passing in wrapping * classes. So, for example, a Boolean class would match a boolean * primitive. *

*

* This is a convenient wrapper for * {@link #invokeStaticMethod(Class cls,String methodName,Object [] args)}. *

* * @param cls invoke static method on this class * @param methodName get method with this name * @param arg use this argument * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeStaticMethod(Class cls, String methodName, Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Object[] args = { arg }; return invokeStaticMethod(cls, methodName, args); } /** *

* Invoke a named static method whose parameter type matches the object type. *

*

* The behaviour of this method is less deterministic than * {@link #invokeExactMethod(Object object,String methodName,Object [] args)}. It loops through * all methods with names that match and then executes the first it finds with compatable * parameters. *

*

* This method supports calls to methods taking primitive parameters via passing in wrapping * classes. So, for example, a Boolean class would match a boolean * primitive. *

*

* This is a convenient wrapper for * {@link #invokeStaticMethod(Class cls,String methodName,Object [] args,Class[] parameterTypes)} * . *

* * @param cls invoke static method on this class * @param methodName get method with this name * @param args use these arguments - treat null as empty array * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeStaticMethod(Class cls, String methodName, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { args = Arrays.nullToEmpty(args); Class[] parameterTypes = Classes.toClass(args); return invokeStaticMethod(cls, methodName, args, parameterTypes); } /** *

* Invoke a named static method whose parameter type matches the object type. *

*

* The behaviour of this method is less deterministic than * {@link #invokeExactStaticMethod(Class cls,String methodName,Object [] args,Class[] parameterTypes)} * . It loops through all methods with names that match and then executes the first it finds * with compatable parameters. *

*

* This method supports calls to methods taking primitive parameters via passing in wrapping * classes. So, for example, a Boolean class would match a boolean * primitive. *

* * @param cls invoke static method on this class * @param methodName get method with this name * @param args use these arguments - treat null as empty array * @param parameterTypes match these parameters - treat null as empty array * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeStaticMethod(Class cls, String methodName, Object[] args, final Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { args = Arrays.nullToEmpty(args); Method method = getMatchingAccessibleMethod(cls, methodName, parameterTypes); if (method == null) { throw new NoSuchMethodException("No such accessible method: " + methodName + "() on class: " + cls.getName()); } return method.invoke(null, args); } /** *

* Invoke a static method whose parameter type matches exactly the object type. *

*

* This is a convenient wrapper for * {@link #invokeExactStaticMethod(Class cls,String methodName,Object [] args)}. *

* * @param cls invoke static method on this class * @param methodName get method with this name * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeExactStaticMethod(Class cls, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { return invokeExactStaticMethod(cls, methodName, null, null); } /** *

* Invoke a static method whose parameter type matches exactly the object type. *

*

* This is a convenient wrapper for * {@link #invokeExactStaticMethod(Class cls,String methodName,Object [] args)}. *

* * @param cls invoke static method on this class * @param methodName get method with this name * @param arg use this argument * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeExactStaticMethod(Class cls, String methodName, Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Object[] args = { arg }; return invokeExactStaticMethod(cls, methodName, args); } /** *

* Invoke a static method whose parameter types match exactly the object types. *

*

* This uses reflection to invoke the method obtained from a call to * {@link #getAccessibleMethod(Class, String, Class[])}. *

* * @param cls invoke static method on this class * @param methodName get method with this name * @param args use these arguments - treat null as empty array * @return The value returned by the invoked method * @throws NoSuchMethodException if there is no such accessible method * @throws InvocationTargetException wraps an exception thrown by the method invoked * @throws IllegalAccessException if the requested method is not accessible via reflection */ public static Object invokeExactStaticMethod(Class cls, String methodName, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { args = Arrays.nullToEmpty(args); final Class[] parameterTypes = Classes.toClass(args); return invokeExactStaticMethod(cls, methodName, args, parameterTypes); } /** *

* 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 {@link #getAccessibleMethod(Method method)}. *

* * @param cls get method from this class * @param methodName get method with this name * @param parameterTypes with these parameters types * @return The accessible method */ public static Method getAccessibleMethod(final Class cls, final String methodName, final Class ... parameterTypes) { try { return getAccessibleMethod(cls.getMethod(methodName, parameterTypes)); } catch (final NoSuchMethodException e) { return null; } } /** *

* Return an accessible method (that is, one that can be invoked via reflection) that implements * the specified Method. If no such method can be found, return null. *

* * @param method The method that we wish to call * @return The accessible method */ public static Method getAccessibleMethod(Method method) { if (!Members.isAccessible(method)) { return null; } // If the declaring class is public, we are done final Class cls = method.getDeclaringClass(); if (Modifier.isPublic(cls.getModifiers())) { return method; } 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 Methods /** *

* Return an accessible method (that is, one that can be invoked via reflection) by scanning * through the superclasses. If no such method can be found, return null. *

* * @param cls Class to be checked * @param methodName Method name of the method we wish to call * @param parameterTypes The parameter type signatures */ private static Method getAccessibleMethodFromSuperclass(Class cls, String methodName, Class[] parameterTypes) { Class parentClazz = cls.getSuperclass(); while (parentClazz != null) { if (Modifier.isPublic(parentClazz.getModifiers())) { try { return parentClazz.getMethod(methodName, parameterTypes); } catch (NoSuchMethodException e) { return null; } } parentClazz = parentClazz.getSuperclass(); } return null; } /** *

* Return an accessible method (that is, one that can be invoked via reflection) that implements * the specified method, by scanning through all implemented interfaces and subinterfaces. If no * such method can be found, return null. *

*

* There isn't any good reason why this method must be private. It is because there doesn't seem * any reason why other classes should call this rather than the higher level methods. *

* * @param cls Parent class for the interfaces to be checked * @param methodName Method name of the method we wish to call * @param parameterTypes The parameter type signatures */ private static Method getAccessibleMethodFromInterfaceNest(Class cls, String methodName, Class[] parameterTypes) { // Search up the superclass chain for (; cls != null; cls = cls.getSuperclass()) { // Check the implemented interfaces of the parent class Class[] interfaces = cls.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { // Is this interface public? if (!Modifier.isPublic(interfaces[i].getModifiers())) { continue; } // Does the method exist on this interface? try { return interfaces[i].getDeclaredMethod(methodName, parameterTypes); } catch (NoSuchMethodException e) { /* * 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; } } } // We did not find anything return null; } public static Method getMatchingAccessibleMethod(Class cls, final String methodName, final Object... args) { Class[] pts = Classes.toClass(args); return getMatchingAccessibleMethod(cls, methodName, pts); } /** *

* Find an accessible method that matches the given name and has compatible parameters. * Compatible parameters mean that every method parameter is assignable from the given * parameters. In other words, it finds a method with the given name that will take the * parameters given. *

*

* This method is slightly undeterminstic since it loops through methods names and return the * first matching method. *

*

* This method is used by * {@link #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}. *

* This method can match primitive parameter by passing in wrapper classes. For example, a * Boolean will match a primitive boolean parameter. * * @param cls find method in this class * @param methodName find method with this name * @param parameterTypes find method with compatible parameters * @return The accessible method */ public static Method getMatchingAccessibleMethod(Class cls, final String methodName, final Class... parameterTypes) { try { final Method method = cls.getMethod(methodName, parameterTypes); Members.setAccessibleWorkaround(method); return method; } catch (final NoSuchMethodException e) { // NOPMD - Swallow the exception } // search through all methods Method bestMatch = null; final Method[] methods = cls.getMethods(); for (final Method method : methods) { // compare name and parameters if (method.getName().equals(methodName) && Classes.isAssignable(parameterTypes, method.getParameterTypes(), true)) { // get accessible version of method final Method accessibleMethod = getAccessibleMethod(method); if (accessibleMethod != null && (bestMatch == null || Members.compareParameterTypes( accessibleMethod.getParameterTypes(), bestMatch.getParameterTypes(), parameterTypes) < 0)) { bestMatch = accessibleMethod; } } } if (bestMatch != null) { Members.setAccessibleWorkaround(bestMatch); } if (bestMatch != null && bestMatch.isVarArgs() && bestMatch.getParameterTypes().length > 0 && parameterTypes.length > 0) { final Class[] methodParameterTypes = bestMatch.getParameterTypes(); final Class methodParameterComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); final String methodParameterComponentTypeName = Classes.primitiveToWrapper(methodParameterComponentType).getName(); final String parameterTypeName = parameterTypes[parameterTypes.length - 1].getName(); final String parameterTypeSuperClassName = parameterTypes[parameterTypes.length - 1].getSuperclass().getName(); if (!methodParameterComponentTypeName.equals(parameterTypeName) && !methodParameterComponentTypeName.equals(parameterTypeSuperClassName)) { return null; } } return bestMatch; } public static Method getMatchingAccessibleMethod(Class cls, final String methodName, final int parameterLength) { // search through all methods Method match = null; final Method[] methods = cls.getMethods(); for (final Method method : methods) { // compare name and parameters if (method.getName().equals(methodName) && parameterLength == method.getParameterTypes().length) { // get accessible version of method match = getAccessibleMethod(method); if (match != null) { break; } } } if (match != null) { Members.setAccessibleWorkaround(match); } return match; } /** * Return the qualified name of the given method, consisting of * fully qualified interface/class name + "." + method name. * @param method the method * @return the qualified name of the method */ public static String getQualifiedName(Method method) { Asserts.notNull(method, "Method must not be null"); return method.getDeclaringClass().getName() + "." + method.getName(); } public static String toSimpleString(Method method) { try { StringBuilder sb = new StringBuilder(); sb.append(Classes.getShortClassName(method.getReturnType()) + " "); sb.append(getQualifiedName(method)); sb.append("("); Class[] params = method.getParameterTypes(); for (int j = 0; j < params.length; j++) { sb.append(Classes.getShortClassName(params[j])); if (j < (params.length - 1)) sb.append(","); } sb.append(")"); return sb.toString(); } catch (Exception e) { return "<" + e + ">"; } } }