首页

关于apache的commons-beanutils提供MethodUtils工具类实现类方法method及其常用的方法调用方式

标签:methodUtils,方法工具类,apache,reflect,commons-beanutils,BeanUtils.describe,toString     发布时间:2018-01-07   

一、前言

通过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@}