一、前言
通过apache提供的开源commons-beanutils(1.8.3)包org.apache.commons.beanutils.MethodUtils方法工具类,实现基本对象方法静态调用invokeMethod、静态方法调用invokeExactStaticMethod、类公共方法获取getAccessibleMethod、父类方法获取getAccessibleMethodFromSuperclass等。
二、源码说明
package org.apache.commons.beanutils;@b@@b@import java.lang.ref.Reference;@b@import java.lang.ref.WeakReference;@b@import java.lang.reflect.InvocationTargetException;@b@import java.lang.reflect.Method;@b@import java.lang.reflect.Modifier;@b@import java.util.Arrays;@b@import java.util.Collections;@b@import java.util.Map;@b@import java.util.WeakHashMap;@b@import org.apache.commons.logging.Log;@b@import org.apache.commons.logging.LogFactory;@b@@b@public class MethodUtils@b@{@b@ private static boolean loggedAccessibleWarning = false;@b@ private static boolean CACHE_METHODS = true;@b@ private static final Class[] EMPTY_CLASS_PARAMETERS = new Class[0];@b@ private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];@b@ private static final Map cache = Collections.synchronizedMap(new WeakHashMap());@b@@b@ public static synchronized void setCacheMethods(boolean cacheMethods)@b@ {@b@ CACHE_METHODS = cacheMethods;@b@ if (!(CACHE_METHODS))@b@ clearCache();@b@ }@b@@b@ public static synchronized int clearCache()@b@ {@b@ int size = cache.size();@b@ cache.clear();@b@ return size;@b@ }@b@@b@ public static Object invokeMethod(Object object, String methodName, Object arg)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ Object[] args = { arg };@b@ return invokeMethod(object, methodName, args);@b@ }@b@@b@ public static Object invokeMethod(Object object, String methodName, Object[] args)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ if (args == null)@b@ args = EMPTY_OBJECT_ARRAY;@b@@b@ int arguments = args.length;@b@ Class[] parameterTypes = new Class[arguments];@b@ for (int i = 0; i < arguments; ++i)@b@ parameterTypes[i] = args[i].getClass();@b@@b@ return invokeMethod(object, methodName, args, parameterTypes);@b@ }@b@@b@ public static Object invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ if (parameterTypes == null)@b@ parameterTypes = EMPTY_CLASS_PARAMETERS;@b@@b@ if (args == null) {@b@ args = EMPTY_OBJECT_ARRAY;@b@ }@b@@b@ Method method = getMatchingAccessibleMethod(object.getClass(), methodName, parameterTypes);@b@@b@ if (method == null) {@b@ throw new NoSuchMethodException("No such accessible method: " + methodName + "() on object: " + object.getClass().getName());@b@ }@b@@b@ return method.invoke(object, args);@b@ }@b@@b@ public static Object invokeExactMethod(Object object, String methodName, Object arg)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ Object[] args = { arg };@b@ return invokeExactMethod(object, methodName, args);@b@ }@b@@b@ public static Object invokeExactMethod(Object object, String methodName, Object[] args)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ if (args == null)@b@ args = EMPTY_OBJECT_ARRAY;@b@@b@ int arguments = args.length;@b@ Class[] parameterTypes = new Class[arguments];@b@ for (int i = 0; i < arguments; ++i)@b@ parameterTypes[i] = args[i].getClass();@b@@b@ return invokeExactMethod(object, methodName, args, parameterTypes);@b@ }@b@@b@ public static Object invokeExactMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ if (args == null) {@b@ args = EMPTY_OBJECT_ARRAY;@b@ }@b@@b@ if (parameterTypes == null) {@b@ parameterTypes = EMPTY_CLASS_PARAMETERS;@b@ }@b@@b@ Method method = getAccessibleMethod(object.getClass(), methodName, parameterTypes);@b@@b@ if (method == null) {@b@ throw new NoSuchMethodException("No such accessible method: " + methodName + "() on object: " + object.getClass().getName());@b@ }@b@@b@ return method.invoke(object, args);@b@ }@b@@b@ public static Object invokeExactStaticMethod(Class objectClass, String methodName, Object[] args, Class[] parameterTypes)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ if (args == null) {@b@ args = EMPTY_OBJECT_ARRAY;@b@ }@b@@b@ if (parameterTypes == null) {@b@ parameterTypes = EMPTY_CLASS_PARAMETERS;@b@ }@b@@b@ Method method = getAccessibleMethod(objectClass, methodName, parameterTypes);@b@@b@ if (method == null) {@b@ throw new NoSuchMethodException("No such accessible method: " + methodName + "() on class: " + objectClass.getName());@b@ }@b@@b@ return method.invoke(null, args);@b@ }@b@@b@ public static Object invokeStaticMethod(Class objectClass, String methodName, Object arg)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ Object[] args = { arg };@b@ return invokeStaticMethod(objectClass, methodName, args);@b@ }@b@@b@ public static Object invokeStaticMethod(Class objectClass, String methodName, Object[] args)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ if (args == null)@b@ args = EMPTY_OBJECT_ARRAY;@b@@b@ int arguments = args.length;@b@ Class[] parameterTypes = new Class[arguments];@b@ for (int i = 0; i < arguments; ++i)@b@ parameterTypes[i] = args[i].getClass();@b@@b@ return invokeStaticMethod(objectClass, methodName, args, parameterTypes);@b@ }@b@@b@ public static Object invokeStaticMethod(Class objectClass, String methodName, Object[] args, Class[] parameterTypes)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ if (parameterTypes == null)@b@ parameterTypes = EMPTY_CLASS_PARAMETERS;@b@@b@ if (args == null) {@b@ args = EMPTY_OBJECT_ARRAY;@b@ }@b@@b@ Method method = getMatchingAccessibleMethod(objectClass, methodName, parameterTypes);@b@@b@ if (method == null) {@b@ throw new NoSuchMethodException("No such accessible method: " + methodName + "() on class: " + objectClass.getName());@b@ }@b@@b@ return method.invoke(null, args);@b@ }@b@@b@ public static Object invokeExactStaticMethod(Class objectClass, String methodName, Object arg)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ Object[] args = { arg };@b@ return invokeExactStaticMethod(objectClass, methodName, args);@b@ }@b@@b@ public static Object invokeExactStaticMethod(Class objectClass, String methodName, Object[] args)@b@ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException@b@ {@b@ if (args == null)@b@ args = EMPTY_OBJECT_ARRAY;@b@@b@ int arguments = args.length;@b@ Class[] parameterTypes = new Class[arguments];@b@ for (int i = 0; i < arguments; ++i)@b@ parameterTypes[i] = args[i].getClass();@b@@b@ return invokeExactStaticMethod(objectClass, methodName, args, parameterTypes);@b@ }@b@@b@ public static Method getAccessibleMethod(Class clazz, String methodName, Class parameterType)@b@ {@b@ Class[] parameterTypes = { parameterType };@b@ return getAccessibleMethod(clazz, methodName, parameterTypes);@b@ }@b@@b@ public static Method getAccessibleMethod(Class clazz, String methodName, Class[] parameterTypes)@b@ {@b@ MethodDescriptor md;@b@ try@b@ {@b@ md = new MethodDescriptor(clazz, methodName, parameterTypes, true);@b@@b@ Method method = getCachedMethod(md);@b@ if (method != null) {@b@ return method;@b@ }@b@@b@ method = getAccessibleMethod(clazz, clazz.getMethod(methodName, parameterTypes));@b@@b@ cacheMethod(md, method);@b@ return method; } catch (NoSuchMethodException e) {@b@ }@b@ return null;@b@ }@b@@b@ public static Method getAccessibleMethod(Method method)@b@ {@b@ if (method == null) {@b@ return null;@b@ }@b@@b@ return getAccessibleMethod(method.getDeclaringClass(), method);@b@ }@b@@b@ public static Method getAccessibleMethod(Class clazz, Method method)@b@ {@b@ if (method == null) {@b@ return null;@b@ }@b@@b@ if (!(Modifier.isPublic(method.getModifiers()))) {@b@ return null;@b@ }@b@@b@ boolean sameClass = true;@b@ if (clazz == null) {@b@ clazz = method.getDeclaringClass();@b@ } else {@b@ sameClass = clazz.equals(method.getDeclaringClass());@b@ if (!(method.getDeclaringClass().isAssignableFrom(clazz))) {@b@ throw new IllegalArgumentException(clazz.getName() + " is not assignable from " + method.getDeclaringClass().getName());@b@ }@b@@b@ }@b@@b@ if (Modifier.isPublic(clazz.getModifiers())) {@b@ if ((!(sameClass)) && (!(Modifier.isPublic(method.getDeclaringClass().getModifiers()))))@b@ setMethodAccessible(method);@b@@b@ return method;@b@ }@b@@b@ String methodName = method.getName();@b@ Class[] parameterTypes = method.getParameterTypes();@b@@b@ method = getAccessibleMethodFromInterfaceNest(clazz, methodName, parameterTypes);@b@@b@ if (method == null) {@b@ method = getAccessibleMethodFromSuperclass(clazz, methodName, parameterTypes);@b@ }@b@@b@ return method;@b@ }@b@@b@ private static Method getAccessibleMethodFromSuperclass(Class clazz, String methodName, Class[] parameterTypes)@b@ {@b@ Class parentClazz = clazz.getSuperclass();@b@ while (parentClazz != null) {@b@ if (Modifier.isPublic(parentClazz.getModifiers()))@b@ try {@b@ return parentClazz.getMethod(methodName, parameterTypes);@b@ } catch (NoSuchMethodException e) {@b@ return null;@b@ }@b@@b@ parentClazz = parentClazz.getSuperclass();@b@ }@b@ return null;@b@ }@b@@b@ private static Method getAccessibleMethodFromInterfaceNest(Class clazz, String methodName, Class[] parameterTypes)@b@ {@b@ Method method = null;@b@@b@ for (; clazz != null; clazz = clazz.getSuperclass())@b@ {@b@ Class[] interfaces = clazz.getInterfaces();@b@ for (int i = 0; i < interfaces.length; ++i)@b@ {@b@ if (!(Modifier.isPublic(interfaces[i].getModifiers()))) {@b@ break label79:@b@ }@b@@b@ try@b@ {@b@ method = interfaces[i].getDeclaredMethod(methodName, parameterTypes);@b@ }@b@ catch (NoSuchMethodException e)@b@ {@b@ }@b@@b@ if (method != null) {@b@ return method;@b@ }@b@@b@ method = getAccessibleMethodFromInterfaceNest(interfaces[i], methodName, parameterTypes);@b@@b@ label79: if (method != null) {@b@ return method;@b@ }@b@@b@ }@b@@b@ }@b@@b@ return null;@b@ }@b@@b@ public static Method getMatchingAccessibleMethod(Class clazz, String methodName, Class[] parameterTypes)@b@ {@b@ Method bestMatch;@b@ Log log = LogFactory.getLog(MethodUtils.class);@b@ if (log.isTraceEnabled())@b@ log.trace("Matching name=" + methodName + " on " + clazz);@b@@b@ MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, false);@b@ try@b@ {@b@ Method method = getCachedMethod(md);@b@ if (method != null) {@b@ return method;@b@ }@b@@b@ method = clazz.getMethod(methodName, parameterTypes);@b@ if (log.isTraceEnabled()) {@b@ log.trace("Found straight match: " + method);@b@ log.trace("isPublic:" + Modifier.isPublic(method.getModifiers()));@b@ }@b@@b@ setMethodAccessible(method);@b@@b@ cacheMethod(md, method);@b@ return method;@b@ }@b@ catch (NoSuchMethodException paramSize)@b@ {@b@ int paramSize = parameterTypes.length;@b@ bestMatch = null;@b@ Method[] methods = clazz.getMethods();@b@ float bestMatchCost = 3.4028235E+38F;@b@ float myCost = 3.4028235E+38F;@b@ int i = 0; for (int size = methods.length; i < size; ++i)@b@ if (methods[i].getName().equals(methodName))@b@ {@b@ if (log.isTraceEnabled()) {@b@ log.trace("Found matching name:");@b@ log.trace(methods[i]);@b@ }@b@@b@ Class[] methodsParams = methods[i].getParameterTypes();@b@ int methodParamSize = methodsParams.length;@b@ if (methodParamSize == paramSize) {@b@ boolean match = true;@b@ for (int n = 0; n < methodParamSize; ++n) {@b@ if (log.isTraceEnabled()) {@b@ log.trace("Param=" + parameterTypes[n].getName());@b@ log.trace("Method=" + methodsParams[n].getName());@b@ }@b@ if (!(isAssignmentCompatible(methodsParams[n], parameterTypes[n]))) {@b@ if (log.isTraceEnabled()) {@b@ log.trace(methodsParams[n] + " is not assignable from " + parameterTypes[n]);@b@ }@b@@b@ match = false;@b@ break;@b@ }@b@ }@b@@b@ if (match)@b@ {@b@ Method method = getAccessibleMethod(clazz, methods[i]);@b@ if (method != null) {@b@ if (log.isTraceEnabled()) {@b@ log.trace(method + " accessible version of " + methods[i]);@b@ }@b@@b@ setMethodAccessible(method);@b@ myCost = getTotalTransformationCost(parameterTypes, method.getParameterTypes());@b@ if (myCost < bestMatchCost) {@b@ bestMatch = method;@b@ bestMatchCost = myCost;@b@ }@b@ }@b@@b@ log.trace("Couldn't find accessible method.");@b@ }@b@ }@b@ }@b@@b@ if (bestMatch != null) {@b@ cacheMethod(md, bestMatch);@b@ }@b@ else@b@ log.trace("No match found.");@b@ }@b@@b@ return bestMatch;@b@ }@b@@b@ private static void setMethodAccessible(Method method)@b@ {@b@ try@b@ {@b@ if (!(method.isAccessible()))@b@ method.setAccessible(true);@b@@b@ }@b@ catch (SecurityException se)@b@ {@b@ Log log = LogFactory.getLog(MethodUtils.class);@b@ if (!(loggedAccessibleWarning)) {@b@ boolean vulnerableJVM = false;@b@ try {@b@ String specVersion = System.getProperty("java.specification.version");@b@ if ((specVersion.charAt(0) == '1') && (((specVersion.charAt(2) == '0') || (specVersion.charAt(2) == '1') || (specVersion.charAt(2) == '2') || (specVersion.charAt(2) == '3'))))@b@ {@b@ vulnerableJVM = true;@b@ }@b@ }@b@ catch (SecurityException e) {@b@ vulnerableJVM = true;@b@ }@b@ if (vulnerableJVM) {@b@ log.warn("Current Security Manager restricts use of workarounds for reflection bugs in pre-1.4 JVMs.");@b@ }@b@@b@ loggedAccessibleWarning = true;@b@ }@b@ log.debug("Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.", se);@b@ }@b@ }@b@@b@ private static float getTotalTransformationCost(Class[] srcArgs, Class[] destArgs)@b@ {@b@ float totalCost = 0.0F;@b@ for (int i = 0; i < srcArgs.length; ++i)@b@ {@b@ Class srcClass = srcArgs[i];@b@ Class destClass = destArgs[i];@b@ totalCost += getObjectTransformationCost(srcClass, destClass);@b@ }@b@@b@ return totalCost;@b@ }@b@@b@ private static float getObjectTransformationCost(Class srcClass, Class destClass)@b@ {@b@ float cost = 0.0F;@b@ while ((destClass != null) && (!(destClass.equals(srcClass)))) {@b@ if ((destClass.isInterface()) && (isAssignmentCompatible(destClass, srcClass)))@b@ {@b@ cost += 0.25F;@b@ break;@b@ }@b@ cost += 1.0F;@b@ destClass = destClass.getSuperclass();@b@ }@b@@b@ if (destClass == null) {@b@ cost += 1.5F;@b@ }@b@@b@ return cost;@b@ }@b@@b@ public static final boolean isAssignmentCompatible(Class parameterType, Class parameterization)@b@ {@b@ if (parameterType.isAssignableFrom(parameterization)) {@b@ return true;@b@ }@b@@b@ if (parameterType.isPrimitive())@b@ {@b@ Class parameterWrapperClazz = getPrimitiveWrapper(parameterType);@b@ if (parameterWrapperClazz != null)@b@ return parameterWrapperClazz.equals(parameterization);@b@@b@ }@b@@b@ return false;@b@ }@b@@b@ public static Class getPrimitiveWrapper(Class primitiveType)@b@ {@b@ if (Boolean.TYPE.equals(primitiveType))@b@ return Boolean.class;@b@ if (Float.TYPE.equals(primitiveType))@b@ return Float.class;@b@ if (Long.TYPE.equals(primitiveType))@b@ return Long.class;@b@ if (Integer.TYPE.equals(primitiveType))@b@ return Integer.class;@b@ if (Short.TYPE.equals(primitiveType))@b@ return Short.class;@b@ if (Byte.TYPE.equals(primitiveType))@b@ return Byte.class;@b@ if (Double.TYPE.equals(primitiveType))@b@ return Double.class;@b@ if (Character.TYPE.equals(primitiveType)) {@b@ return Character.class;@b@ }@b@@b@ return null;@b@ }@b@@b@ public static Class getPrimitiveType(Class wrapperType)@b@ {@b@ if (Boolean.class.equals(wrapperType))@b@ return Boolean.TYPE;@b@ if (Float.class.equals(wrapperType))@b@ return Float.TYPE;@b@ if (Long.class.equals(wrapperType))@b@ return Long.TYPE;@b@ if (Integer.class.equals(wrapperType))@b@ return Integer.TYPE;@b@ if (Short.class.equals(wrapperType))@b@ return Short.TYPE;@b@ if (Byte.class.equals(wrapperType))@b@ return Byte.TYPE;@b@ if (Double.class.equals(wrapperType))@b@ return Double.TYPE;@b@ if (Character.class.equals(wrapperType))@b@ return Character.TYPE;@b@@b@ Log log = LogFactory.getLog(MethodUtils.class);@b@ if (log.isDebugEnabled())@b@ log.debug("Not a known primitive wrapper class: " + wrapperType);@b@@b@ return null;@b@ }@b@@b@ public static Class toNonPrimitiveClass(Class clazz)@b@ {@b@ if (clazz.isPrimitive()) {@b@ Class primitiveClazz = getPrimitiveWrapper(clazz);@b@@b@ if (primitiveClazz != null)@b@ return primitiveClazz;@b@@b@ return clazz;@b@ }@b@@b@ return clazz;@b@ }@b@@b@ private static Method getCachedMethod(MethodDescriptor md)@b@ {@b@ if (CACHE_METHODS) {@b@ Reference methodRef = (Reference)cache.get(md);@b@ if (methodRef != null)@b@ return ((Method)methodRef.get());@b@ }@b@@b@ return null;@b@ }@b@@b@ private static void cacheMethod(MethodDescriptor md, Method method)@b@ {@b@ if ((CACHE_METHODS) && @b@ (method != null))@b@ cache.put(md, new WeakReference(method));@b@ }@b@@b@ static Class[] access$000()@b@ {@b@ return EMPTY_CLASS_PARAMETERS;@b@ }@b@@b@ private static class MethodDescriptor@b@ {@b@ private Class cls;@b@ private String methodName;@b@ private Class[] paramTypes;@b@ private boolean exact;@b@ private int hashCode;@b@@b@ public MethodDescriptor(Class cls, String methodName, Class[] paramTypes, boolean exact)@b@ {@b@ if (cls == null)@b@ throw new IllegalArgumentException("Class cannot be null");@b@@b@ if (methodName == null)@b@ throw new IllegalArgumentException("Method Name cannot be null");@b@@b@ if (paramTypes == null) {@b@ paramTypes = MethodUtils.access$000();@b@ }@b@@b@ this.cls = cls;@b@ this.methodName = methodName;@b@ this.paramTypes = paramTypes;@b@ this.exact = exact;@b@@b@ this.hashCode = methodName.length();@b@ }@b@@b@ public boolean equals(Object obj)@b@ {@b@ if (!(obj instanceof MethodDescriptor))@b@ return false;@b@@b@ MethodDescriptor md = (MethodDescriptor)obj;@b@@b@ return ((this.exact == md.exact) && (this.methodName.equals(md.methodName)) && (this.cls.equals(md.cls)) && (Arrays.equals(this.paramTypes, md.paramTypes)));@b@ }@b@@b@ public int hashCode()@b@ {@b@ return this.hashCode;@b@ }@b@ }@b@}
对象字符串重写toString()
@Override@b@public String toString() {@b@ try {@b@ return BeanUtils.describe(this).toString();@b@ } catch (Exception e) {@b@ }@b@ return "";@b@}