MethodUtils.java
0001 /*
0002  * Licensed to the Apache Software Foundation (ASF) under one or more
0003  * contributor license agreements.  See the NOTICE file distributed with
0004  * this work for additional information regarding copyright ownership.
0005  * The ASF licenses this file to You under the Apache License, Version 2.0
0006  * (the "License"); you may not use this file except in compliance with
0007  * the License.  You may obtain a copy of the License at
0008  *
0009  *      http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS,
0013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014  * See the License for the specific language governing permissions and
0015  * limitations under the License.
0016  */
0017 
0018 package griffon.util;
0019 
0020 
0021 import java.lang.ref.Reference;
0022 import java.lang.ref.WeakReference;
0023 import java.lang.reflect.InvocationTargetException;
0024 import java.lang.reflect.Method;
0025 import java.lang.reflect.Modifier;
0026 import java.util.Collections;
0027 import java.util.Map;
0028 import java.util.WeakHashMap;
0029 
0030 
0031 /**
0032  <p> Utility reflection methods focussed on methods in general rather than properties in particular. </p>
0033  <p/>
0034  <p><b>Copied from commons-beanutils, removed dependencies to commons-logging</b></p>
0035  <p/>
0036  <h3>Known Limitations</h3>
0037  <h4>Accessing Public Methods In A Default Access Superclass</h4>
0038  <p>There is an issue when invoking public methods contained in a default access superclass.
0039  * Reflection locates these methods fine and correctly assigns them as public.
0040  * However, an <code>IllegalAccessException</code> is thrown if the method is invoked.</p>
0041  <p/>
0042  <p><code>MethodUtils</code> contains a workaround for this situation.
0043  * It will attempt to call <code>setAccessible</code> on this method.
0044  * If this call succeeds, then the method can be invoked as normal.
0045  * This call will only succeed when the application has sufficient security privilages.
0046  *
0047  @author Craig R. McClanahan
0048  @author Ralph Schaer
0049  @author Chris Audley
0050  @author Rey Fran&#231;ois
0051  @author Gregor Ra&#253;man
0052  @author Jan Sorensen
0053  @author Robert Burrell Donkin
0054  */
0055 
0056 @SuppressWarnings({"unchecked""rawtypes"})
0057 public class MethodUtils {
0058 
0059     // --------------------------------------------------------- Private Methods
0060 
0061     /**
0062      * Indicates whether methods should be cached for improved performance.
0063      <p/>
0064      * Note that when this class is deployed via a shared classloader in
0065      * a container, this will affect all webapps. However making this
0066      * configurable per webapp would mean having a map keyed by context classloader
0067      * which may introduce memory-leak problems.
0068      */
0069     private static boolean CACHE_METHODS = true;
0070 
0071     /**
0072      * An empty class array
0073      */
0074     private static final Class[] EMPTY_CLASS_PARAMETERS = new Class[0];
0075     /**
0076      * An empty object array
0077      */
0078     private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
0079 
0080     /**
0081      * Stores a cache of MethodDescriptor -> Method in a WeakHashMap.
0082      <p/>
0083      * The keys into this map only ever exist as temporary variables within
0084      * methods of this class, and are never exposed to users of this class.
0085      * This means that the WeakHashMap is used only as a mechanism for
0086      * limiting the size of the cache, ie a way to tell the garbage collector
0087      * that the contents of the cache can be completely garbage-collected
0088      * whenever it needs the memory. Whether this is a good approach to
0089      * this problem is doubtful; something like the commons-collections
0090      * LRUMap may be more appropriate (though of course selecting an
0091      * appropriate size is an issue).
0092      <p/>
0093      * This static variable is safe even when this code is deployed via a
0094      * shared classloader because it is keyed via a MethodDescriptor object
0095      * which has a Class as one of its members and that member is used in
0096      * the MethodDescriptor.equals method. So two components that load the same
0097      * class via different classloaders will generate non-equal MethodDescriptor
0098      * objects and hence end up with different entries in the map.
0099      */
0100     private static final Map cache = Collections.synchronizedMap(new WeakHashMap());
0101 
0102     // --------------------------------------------------------- Public Methods
0103 
0104     /**
0105      * Set whether methods should be cached for greater performance or not,
0106      * default is <code>true</code>.
0107      *
0108      @param cacheMethods <code>true</code> if methods should be
0109      *                     cached for greater performance, otherwise <code>false</code>
0110      @since 1.8.0
0111      */
0112     public static synchronized void setCacheMethods(boolean cacheMethods) {
0113         CACHE_METHODS = cacheMethods;
0114         if (!CACHE_METHODS) {
0115             clearCache();
0116         }
0117     }
0118 
0119     /**
0120      * Clear the method cache.
0121      *
0122      @return the number of cached methods cleared
0123      @since 1.8.0
0124      */
0125     public static synchronized int clearCache() {
0126         int size = cache.size();
0127         cache.clear();
0128         return size;
0129     }
0130 
0131     /**
0132      <p>Invoke a named method whose parameter type matches the object type.</p>
0133      <p/>
0134      <p>The behaviour of this method is less deterministic
0135      * than <code>invokeExactMethod()</code>.
0136      * It loops through all methods with names that match
0137      * and then executes the first it finds with compatable parameters.</p>
0138      <p/>
0139      <p>This method supports calls to methods taking primitive parameters
0140      * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
0141      * would match a <code>boolean</code> primitive.</p>
0142      <p/>
0143      <p> This is a convenient wrapper for
0144      {@link #invokeMethod(Object object, String methodName, Object [] args)}.
0145      </p>
0146      *
0147      @param object     invoke method on this object
0148      @param methodName get method with this name
0149      @param arg        use this argument
0150      @return The value returned by the invoked method
0151      @throws NoSuchMethodException     if there is no such accessible method
0152      @throws InvocationTargetException wraps an exception thrown by the
0153      *                                   method invoked
0154      @throws IllegalAccessException    if the requested method is not accessible
0155      *                                   via reflection
0156      */
0157     public static Object invokeMethod(
0158         Object object,
0159         String methodName,
0160         Object arg)
0161         throws
0162         NoSuchMethodException,
0163         IllegalAccessException,
0164         InvocationTargetException {
0165 
0166         Object[] args = {arg};
0167         return invokeMethod(object, methodName, args);
0168 
0169     }
0170 
0171 
0172     /**
0173      <p>Invoke a named method whose parameter type matches the object type.</p>
0174      <p/>
0175      <p>The behaviour of this method is less deterministic
0176      * than {@link #invokeExactMethod(Object object, String methodName, Object [] args)}.
0177      * It loops through all methods with names that match
0178      * and then executes the first it finds with compatable parameters.</p>
0179      <p/>
0180      <p>This method supports calls to methods taking primitive parameters
0181      * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
0182      * would match a <code>boolean</code> primitive.</p>
0183      <p/>
0184      <p> This is a convenient wrapper for
0185      {@link #invokeMethod(Object object, String methodName, Object [] args, Class[] parameterTypes)}.
0186      </p>
0187      *
0188      @param object     invoke method on this object
0189      @param methodName get method with this name
0190      @param args       use these arguments - treat null as empty array
0191      @return The value returned by the invoked method
0192      @throws NoSuchMethodException     if there is no such accessible method
0193      @throws InvocationTargetException wraps an exception thrown by the
0194      *                                   method invoked
0195      @throws IllegalAccessException    if the requested method is not accessible
0196      *                                   via reflection
0197      */
0198     public static Object invokeMethod(
0199         Object object,
0200         String methodName,
0201         Object[] args)
0202         throws
0203         NoSuchMethodException,
0204         IllegalAccessException,
0205         InvocationTargetException {
0206 
0207         if (args == null) {
0208             args = EMPTY_OBJECT_ARRAY;
0209         }
0210         int arguments = args.length;
0211         Class[] parameterTypes = new Class[arguments];
0212         for (int i = 0; i < arguments; i++) {
0213             parameterTypes[i= args[i!= null ? args[i].getClass() : Object.class;
0214         }
0215         return invokeMethod(object, methodName, args, parameterTypes);
0216 
0217     }
0218 
0219 
0220     /**
0221      <p>Invoke a named method whose parameter type matches the object type.</p>
0222      <p/>
0223      <p>The behaviour of this method is less deterministic
0224      * than {@link
0225      * #invokeExactMethod(Object object, String methodName, Object [] args, Class[] parameterTypes)}.
0226      * It loops through all methods with names that match
0227      * and then executes the first it finds with compatable parameters.</p>
0228      <p/>
0229      <p>This method supports calls to methods taking primitive parameters
0230      * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
0231      * would match a <code>boolean</code> primitive.</p>
0232      *
0233      @param object         invoke method on this object
0234      @param methodName     get method with this name
0235      @param args           use these arguments - treat null as empty array
0236      @param parameterTypes match these parameters - treat null as empty array
0237      @return The value returned by the invoked method
0238      @throws NoSuchMethodException     if there is no such accessible method
0239      @throws InvocationTargetException wraps an exception thrown by the
0240      *                                   method invoked
0241      @throws IllegalAccessException    if the requested method is not accessible
0242      *                                   via reflection
0243      */
0244     public static Object invokeMethod(
0245         Object object,
0246         String methodName,
0247         Object[] args,
0248         Class[] parameterTypes)
0249         throws
0250         NoSuchMethodException,
0251         IllegalAccessException,
0252         InvocationTargetException {
0253 
0254         if (parameterTypes == null) {
0255             parameterTypes = EMPTY_CLASS_PARAMETERS;
0256         }
0257         if (args == null) {
0258             args = EMPTY_OBJECT_ARRAY;
0259         }
0260 
0261         Method method = getMatchingAccessibleMethod(
0262             object.getClass(),
0263             methodName,
0264             parameterTypes);
0265         if (method == null) {
0266             throw new NoSuchMethodException("No such accessible method: " +
0267                 methodName + "() on object: " + object.getClass().getName());
0268         }
0269         return method.invoke(object, args);
0270     }
0271 
0272 
0273     /**
0274      <p>Invoke a method whose parameter type matches exactly the object
0275      * type.</p>
0276      <p/>
0277      <p> This is a convenient wrapper for
0278      {@link #invokeExactMethod(Object object, String methodName, Object [] args)}.
0279      </p>
0280      *
0281      @param object     invoke method on this object
0282      @param methodName get method with this name
0283      @param arg        use this argument
0284      @return The value returned by the invoked method
0285      @throws NoSuchMethodException     if there is no such accessible method
0286      @throws InvocationTargetException wraps an exception thrown by the
0287      *                                   method invoked
0288      @throws IllegalAccessException    if the requested method is not accessible
0289      *                                   via reflection
0290      */
0291     public static Object invokeExactMethod(
0292         Object object,
0293         String methodName,
0294         Object arg)
0295         throws
0296         NoSuchMethodException,
0297         IllegalAccessException,
0298         InvocationTargetException {
0299 
0300         Object[] args = {arg};
0301         return invokeExactMethod(object, methodName, args);
0302 
0303     }
0304 
0305 
0306     /**
0307      <p>Invoke a method whose parameter types match exactly the object
0308      * types.</p>
0309      <p/>
0310      <p> This uses reflection to invoke the method obtained from a call to
0311      <code>getAccessibleMethod()</code>.</p>
0312      *
0313      @param object     invoke method on this object
0314      @param methodName get method with this name
0315      @param args       use these arguments - treat null as empty array
0316      @return The value returned by the invoked method
0317      @throws NoSuchMethodException     if there is no such accessible method
0318      @throws InvocationTargetException wraps an exception thrown by the
0319      *                                   method invoked
0320      @throws IllegalAccessException    if the requested method is not accessible
0321      *                                   via reflection
0322      */
0323     public static Object invokeExactMethod(
0324         Object object,
0325         String methodName,
0326         Object[] args)
0327         throws
0328         NoSuchMethodException,
0329         IllegalAccessException,
0330         InvocationTargetException {
0331         if (args == null) {
0332             args = EMPTY_OBJECT_ARRAY;
0333         }
0334         int arguments = args.length;
0335         Class[] parameterTypes = new Class[arguments];
0336         for (int i = 0; i < arguments; i++) {
0337             parameterTypes[i= args[i!= null ? args[i].getClass() : Object.class;
0338         }
0339         return invokeExactMethod(object, methodName, args, parameterTypes);
0340 
0341     }
0342 
0343 
0344     /**
0345      <p>Invoke a method whose parameter types match exactly the parameter
0346      * types given.</p>
0347      <p/>
0348      <p>This uses reflection to invoke the method obtained from a call to
0349      <code>getAccessibleMethod()</code>.</p>
0350      *
0351      @param object         invoke method on this object
0352      @param methodName     get method with this name
0353      @param args           use these arguments - treat null as empty array
0354      @param parameterTypes match these parameters - treat null as empty array
0355      @return The value returned by the invoked method
0356      @throws NoSuchMethodException     if there is no such accessible method
0357      @throws InvocationTargetException wraps an exception thrown by the
0358      *                                   method invoked
0359      @throws IllegalAccessException    if the requested method is not accessible
0360      *                                   via reflection
0361      */
0362     public static Object invokeExactMethod(
0363         Object object,
0364         String methodName,
0365         Object[] args,
0366         Class[] parameterTypes)
0367         throws
0368         NoSuchMethodException,
0369         IllegalAccessException,
0370         InvocationTargetException {
0371 
0372         if (args == null) {
0373             args = EMPTY_OBJECT_ARRAY;
0374         }
0375 
0376         if (parameterTypes == null) {
0377             parameterTypes = EMPTY_CLASS_PARAMETERS;
0378         }
0379 
0380         Method method = getAccessibleMethod(
0381             object.getClass(),
0382             methodName,
0383             parameterTypes);
0384         if (method == null) {
0385             throw new NoSuchMethodException("No such accessible method: " +
0386                 methodName + "() on object: " + object.getClass().getName());
0387         }
0388         return method.invoke(object, args);
0389 
0390     }
0391 
0392     /**
0393      <p>Invoke a static method whose parameter types match exactly the parameter
0394      * types given.</p>
0395      <p/>
0396      <p>This uses reflection to invoke the method obtained from a call to
0397      {@link #getAccessibleMethod(Class, String, Class[])}.</p>
0398      *
0399      @param objectClass    invoke static method on this class
0400      @param methodName     get method with this name
0401      @param args           use these arguments - treat null as empty array
0402      @param parameterTypes match these parameters - treat null as empty array
0403      @return The value returned by the invoked method
0404      @throws NoSuchMethodException     if there is no such accessible method
0405      @throws InvocationTargetException wraps an exception thrown by the
0406      *                                   method invoked
0407      @throws IllegalAccessException    if the requested method is not accessible
0408      *                                   via reflection
0409      @since 1.8.0
0410      */
0411     public static Object invokeExactStaticMethod(
0412         Class objectClass,
0413         String methodName,
0414         Object[] args,
0415         Class[] parameterTypes)
0416         throws
0417         NoSuchMethodException,
0418         IllegalAccessException,
0419         InvocationTargetException {
0420 
0421         if (args == null) {
0422             args = EMPTY_OBJECT_ARRAY;
0423         }
0424 
0425         if (parameterTypes == null) {
0426             parameterTypes = EMPTY_CLASS_PARAMETERS;
0427         }
0428 
0429         Method method = getAccessibleMethod(
0430             objectClass,
0431             methodName,
0432             parameterTypes);
0433         if (method == null) {
0434             throw new NoSuchMethodException("No such accessible method: " +
0435                 methodName + "() on class: " + objectClass.getName());
0436         }
0437         return method.invoke(null, args);
0438 
0439     }
0440 
0441     /**
0442      <p>Invoke a named static method whose parameter type matches the object type.</p>
0443      <p/>
0444      <p>The behaviour of this method is less deterministic
0445      * than {@link #invokeExactMethod(Object, String, Object[], Class[])}.
0446      * It loops through all methods with names that match
0447      * and then executes the first it finds with compatable parameters.</p>
0448      <p/>
0449      <p>This method supports calls to methods taking primitive parameters
0450      * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
0451      * would match a <code>boolean</code> primitive.</p>
0452      <p/>
0453      <p> This is a convenient wrapper for
0454      {@link #invokeStaticMethod(Class objectClass, String methodName, Object [] args)}.
0455      </p>
0456      *
0457      @param objectClass invoke static method on this class
0458      @param methodName  get method with this name
0459      @param arg         use this argument
0460      @return The value returned by the invoked method
0461      @throws NoSuchMethodException     if there is no such accessible method
0462      @throws InvocationTargetException wraps an exception thrown by the
0463      *                                   method invoked
0464      @throws IllegalAccessException    if the requested method is not accessible
0465      *                                   via reflection
0466      @since 1.8.0
0467      */
0468     public static Object invokeStaticMethod(
0469         Class objectClass,
0470         String methodName,
0471         Object arg)
0472         throws
0473         NoSuchMethodException,
0474         IllegalAccessException,
0475         InvocationTargetException {
0476 
0477         Object[] args = {arg};
0478         return invokeStaticMethod(objectClass, methodName, args);
0479 
0480     }
0481 
0482 
0483     /**
0484      <p>Invoke a named static method whose parameter type matches the object type.</p>
0485      <p/>
0486      <p>The behaviour of this method is less deterministic
0487      * than {@link #invokeExactMethod(Object object, String methodName, Object [] args)}.
0488      * It loops through all methods with names that match
0489      * and then executes the first it finds with compatable parameters.</p>
0490      <p/>
0491      <p>This method supports calls to methods taking primitive parameters
0492      * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
0493      * would match a <code>boolean</code> primitive.</p>
0494      <p/>
0495      <p> This is a convenient wrapper for
0496      {@link #invokeStaticMethod(Class objectClass, String methodName, Object [] args, Class[] parameterTypes)}.
0497      </p>
0498      *
0499      @param objectClass invoke static method on this class
0500      @param methodName  get method with this name
0501      @param args        use these arguments - treat null as empty array
0502      @return The value returned by the invoked method
0503      @throws NoSuchMethodException     if there is no such accessible method
0504      @throws InvocationTargetException wraps an exception thrown by the
0505      *                                   method invoked
0506      @throws IllegalAccessException    if the requested method is not accessible
0507      *                                   via reflection
0508      @since 1.8.0
0509      */
0510     public static Object invokeStaticMethod(
0511         Class objectClass,
0512         String methodName,
0513         Object[] args)
0514         throws
0515         NoSuchMethodException,
0516         IllegalAccessException,
0517         InvocationTargetException {
0518 
0519         if (args == null) {
0520             args = EMPTY_OBJECT_ARRAY;
0521         }
0522         int arguments = args.length;
0523         Class[] parameterTypes = new Class[arguments];
0524         for (int i = 0; i < arguments; i++) {
0525             parameterTypes[i= args[i!= null ? args[i].getClass() : Object.class;
0526         }
0527         return invokeStaticMethod(objectClass, methodName, args, parameterTypes);
0528 
0529     }
0530 
0531 
0532     /**
0533      <p>Invoke a named static method whose parameter type matches the object type.</p>
0534      <p/>
0535      <p>The behaviour of this method is less deterministic
0536      * than {@link
0537      * #invokeExactStaticMethod(Class objectClass, String methodName, Object [] args, Class[] parameterTypes)}.
0538      * It loops through all methods with names that match
0539      * and then executes the first it finds with compatable parameters.</p>
0540      <p/>
0541      <p>This method supports calls to methods taking primitive parameters
0542      * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
0543      * would match a <code>boolean</code> primitive.</p>
0544      *
0545      @param objectClass    invoke static method on this class
0546      @param methodName     get method with this name
0547      @param args           use these arguments - treat null as empty array
0548      @param parameterTypes match these parameters - treat null as empty array
0549      @return The value returned by the invoked method
0550      @throws NoSuchMethodException     if there is no such accessible method
0551      @throws InvocationTargetException wraps an exception thrown by the
0552      *                                   method invoked
0553      @throws IllegalAccessException    if the requested method is not accessible
0554      *                                   via reflection
0555      @since 1.8.0
0556      */
0557     public static Object invokeStaticMethod(
0558         Class objectClass,
0559         String methodName,
0560         Object[] args,
0561         Class[] parameterTypes)
0562         throws
0563         NoSuchMethodException,
0564         IllegalAccessException,
0565         InvocationTargetException {
0566 
0567         if (parameterTypes == null) {
0568             parameterTypes = EMPTY_CLASS_PARAMETERS;
0569         }
0570         if (args == null) {
0571             args = EMPTY_OBJECT_ARRAY;
0572         }
0573 
0574         Method method = getMatchingAccessibleMethod(
0575             objectClass,
0576             methodName,
0577             parameterTypes);
0578         if (method == null) {
0579             throw new NoSuchMethodException("No such accessible method: " +
0580                 methodName + "() on class: " + objectClass.getName());
0581         }
0582         return method.invoke(null, args);
0583     }
0584 
0585 
0586     /**
0587      <p>Invoke a static method whose parameter type matches exactly the object
0588      * type.</p>
0589      <p/>
0590      <p> This is a convenient wrapper for
0591      {@link #invokeExactStaticMethod(Class objectClass, String methodName, Object [] args)}.
0592      </p>
0593      *
0594      @param objectClass invoke static method on this class
0595      @param methodName  get method with this name
0596      @param arg         use this argument
0597      @return The value returned by the invoked method
0598      @throws NoSuchMethodException     if there is no such accessible method
0599      @throws InvocationTargetException wraps an exception thrown by the
0600      *                                   method invoked
0601      @throws IllegalAccessException    if the requested method is not accessible
0602      *                                   via reflection
0603      @since 1.8.0
0604      */
0605     public static Object invokeExactStaticMethod(
0606         Class objectClass,
0607         String methodName,
0608         Object arg)
0609         throws
0610         NoSuchMethodException,
0611         IllegalAccessException,
0612         InvocationTargetException {
0613 
0614         Object[] args = {arg};
0615         return invokeExactStaticMethod(objectClass, methodName, args);
0616 
0617     }
0618 
0619 
0620     /**
0621      <p>Invoke a static method whose parameter types match exactly the object
0622      * types.</p>
0623      <p/>
0624      <p> This uses reflection to invoke the method obtained from a call to
0625      {@link #getAccessibleMethod(Class, String, Class[])}.</p>
0626      *
0627      @param objectClass invoke static method on this class
0628      @param methodName  get method with this name
0629      @param args        use these arguments - treat null as empty array
0630      @return The value returned by the invoked method
0631      @throws NoSuchMethodException     if there is no such accessible method
0632      @throws InvocationTargetException wraps an exception thrown by the
0633      *                                   method invoked
0634      @throws IllegalAccessException    if the requested method is not accessible
0635      *                                   via reflection
0636      @since 1.8.0
0637      */
0638     public static Object invokeExactStaticMethod(
0639         Class objectClass,
0640         String methodName,
0641         Object[] args)
0642         throws
0643         NoSuchMethodException,
0644         IllegalAccessException,
0645         InvocationTargetException {
0646         if (args == null) {
0647             args = EMPTY_OBJECT_ARRAY;
0648         }
0649         int arguments = args.length;
0650         Class[] parameterTypes = new Class[arguments];
0651         for (int i = 0; i < arguments; i++) {
0652             parameterTypes[i= args[i!= null ? args[i].getClass() : Object.class;
0653         }
0654         return invokeExactStaticMethod(objectClass, methodName, args, parameterTypes);
0655 
0656     }
0657 
0658 
0659     /**
0660      <p>Return an accessible method (that is, one that can be invoked via
0661      * reflection) with given name and a single parameter.  If no such method
0662      * can be found, return <code>null</code>.
0663      * Basically, a convenience wrapper that constructs a <code>Class</code>
0664      * array for you.</p>
0665      *
0666      @param clazz         get method from this class
0667      @param methodName    get method with this name
0668      @param parameterType taking this type of parameter
0669      @return The accessible method
0670      */
0671     public static Method getAccessibleMethod(
0672         Class clazz,
0673         String methodName,
0674         Class parameterType) {
0675 
0676         Class[] parameterTypes = {parameterType};
0677         return getAccessibleMethod(clazz, methodName, parameterTypes);
0678 
0679     }
0680 
0681 
0682     /**
0683      <p>Return an accessible method (that is, one that can be invoked via
0684      * reflection) with given name and parameters.  If no such method
0685      * can be found, return <code>null</code>.
0686      * This is just a convenient wrapper for
0687      {@link #getAccessibleMethod(Method method)}.</p>
0688      *
0689      @param clazz          get method from this class
0690      @param methodName     get method with this name
0691      @param parameterTypes with these parameters types
0692      @return The accessible method
0693      */
0694     public static Method getAccessibleMethod(
0695         Class clazz,
0696         String methodName,
0697         Class[] parameterTypes) {
0698 
0699         try {
0700             MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, true);
0701             // Check the cache first
0702             Method method = getCachedMethod(md);
0703             if (method != null) {
0704                 return method;
0705             }
0706 
0707             method = getAccessibleMethod
0708                 (clazz, clazz.getMethod(methodName, parameterTypes));
0709             cacheMethod(md, method);
0710             return method;
0711         catch (NoSuchMethodException e) {
0712             return (null);
0713         }
0714 
0715     }
0716 
0717 
0718     /**
0719      <p>Return an accessible method (that is, one that can be invoked via
0720      * reflection) that implements the specified Method.  If no such method
0721      * can be found, return <code>null</code>.</p>
0722      *
0723      @param method The method that we wish to call
0724      @return The accessible method
0725      */
0726     public static Method getAccessibleMethod(Method method) {
0727 
0728         // Make sure we have a method to check
0729         if (method == null) {
0730             return (null);
0731         }
0732 
0733         return getAccessibleMethod(method.getDeclaringClass(), method);
0734 
0735     }
0736 
0737 
0738     /**
0739      <p>Return an accessible method (that is, one that can be invoked via
0740      * reflection) that implements the specified Method.  If no such method
0741      * can be found, return <code>null</code>.</p>
0742      *
0743      @param clazz  The class of the object
0744      @param method The method that we wish to call
0745      @return The accessible method
0746      @since 1.8.0
0747      */
0748     public static Method getAccessibleMethod(Class clazz, Method method) {
0749 
0750         // Make sure we have a method to check
0751         if (method == null) {
0752             return (null);
0753         }
0754 
0755         // If the requested method is not public we cannot call it
0756         if (!Modifier.isPublic(method.getModifiers())) {
0757             return (null);
0758         }
0759 
0760         boolean sameClass = true;
0761         if (clazz == null) {
0762             clazz = method.getDeclaringClass();
0763         else {
0764             sameClass = clazz.equals(method.getDeclaringClass());
0765             if (!method.getDeclaringClass().isAssignableFrom(clazz)) {
0766                 throw new IllegalArgumentException(clazz.getName() +
0767                     " is not assignable from " + method.getDeclaringClass().getName());
0768             }
0769         }
0770 
0771         // If the class is public, we are done
0772         if (Modifier.isPublic(clazz.getModifiers())) {
0773             if (!sameClass && !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
0774                 setMethodAccessible(method)// Default access superclass workaround
0775             }
0776             return (method);
0777         }
0778 
0779         String methodName = method.getName();
0780         Class[] parameterTypes = method.getParameterTypes();
0781 
0782         // Check the implemented interfaces and subinterfaces
0783         method =
0784             getAccessibleMethodFromInterfaceNest(clazz,
0785                 methodName,
0786                 parameterTypes);
0787 
0788         // Check the superclass chain
0789         if (method == null) {
0790             method = getAccessibleMethodFromSuperclass(clazz,
0791                 methodName,
0792                 parameterTypes);
0793         }
0794 
0795         return (method);
0796     }
0797 
0798 
0799     // -------------------------------------------------------- Private Methods
0800 
0801     /**
0802      <p>Return an accessible method (that is, one that can be invoked via
0803      * reflection) by scanning through the superclasses. If no such method
0804      * can be found, return <code>null</code>.</p>
0805      *
0806      @param clazz          Class to be checked
0807      @param methodName     Method name of the method we wish to call
0808      @param parameterTypes The parameter type signatures
0809      */
0810     private static Method getAccessibleMethodFromSuperclass
0811     (Class clazz, String methodName, Class[] parameterTypes) {
0812 
0813         Class parentClazz = clazz.getSuperclass();
0814         while (parentClazz != null) {
0815             if (Modifier.isPublic(parentClazz.getModifiers())) {
0816                 try {
0817                     return parentClazz.getMethod(methodName, parameterTypes);
0818                 catch (NoSuchMethodException e) {
0819                     return null;
0820                 }
0821             }
0822             parentClazz = parentClazz.getSuperclass();
0823         }
0824         return null;
0825     }
0826 
0827     /**
0828      <p>Return an accessible method (that is, one that can be invoked via
0829      * reflection) that implements the specified method, by scanning through
0830      * all implemented interfaces and subinterfaces.  If no such method
0831      * can be found, return <code>null</code>.</p>
0832      <p/>
0833      <p> There isn't any good reason why this method must be private.
0834      * It is because there doesn't seem any reason why other classes should
0835      * call this rather than the higher level methods.</p>
0836      *
0837      @param clazz          Parent class for the interfaces to be checked
0838      @param methodName     Method name of the method we wish to call
0839      @param parameterTypes The parameter type signatures
0840      */
0841     private static Method getAccessibleMethodFromInterfaceNest
0842     (Class clazz, String methodName, Class[] parameterTypes) {
0843 
0844         Method method = null;
0845 
0846         // Search up the superclass chain
0847         for (; clazz != null; clazz = clazz.getSuperclass()) {
0848 
0849             // Check the implemented interfaces of the parent class
0850             Class[] interfaces = clazz.getInterfaces();
0851             for (int i = 0; i < interfaces.length; i++) {
0852 
0853                 // Is this interface public?
0854                 if (!Modifier.isPublic(interfaces[i].getModifiers())) {
0855                     continue;
0856                 }
0857 
0858                 // Does the method exist on this interface?
0859                 try {
0860                     method = interfaces[i].getDeclaredMethod(methodName,
0861                         parameterTypes);
0862                 catch (NoSuchMethodException e) {
0863                     /* Swallow, if no method is found after the loop then this
0864                      * method returns null.
0865                      */
0866                 }
0867                 if (method != null) {
0868                     return method;
0869                 }
0870 
0871                 // Recursively check our parent interfaces
0872                 method =
0873                     getAccessibleMethodFromInterfaceNest(interfaces[i],
0874                         methodName,
0875                         parameterTypes);
0876                 if (method != null) {
0877                     return method;
0878                 }
0879 
0880             }
0881 
0882         }
0883 
0884         // We did not find anything
0885         return (null);
0886 
0887     }
0888 
0889     /**
0890      <p>Find an accessible method that matches the given name and has compatible parameters.
0891      * Compatible parameters mean that every method parameter is assignable from
0892      * the given parameters.
0893      * In other words, it finds a method with the given name
0894      * that will take the parameters given.<p>
0895      <p/>
0896      <p>This method is slightly undeterminstic since it loops
0897      * through methods names and return the first matching method.</p>
0898      <p/>
0899      <p>This method is used by
0900      {@link
0901      * #invokeMethod(Object object, String methodName, Object [] args, Class[] parameterTypes)}.
0902      <p/>
0903      <p>This method can match primitive parameter by passing in wrapper classes.
0904      * For example, a <code>Boolean</code> will match a primitive <code>boolean</code>
0905      * parameter.
0906      *
0907      @param clazz          find method in this class
0908      @param methodName     find method with this name
0909      @param parameterTypes find method with compatible parameters
0910      @return The accessible method
0911      */
0912     public static Method getMatchingAccessibleMethod(
0913         Class clazz,
0914         String methodName,
0915         Class[] parameterTypes) {
0916         MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, false);
0917 
0918         // see if we can find the method directly
0919         // most of the time this works and it's much faster
0920         try {
0921             // Check the cache first
0922             Method method = getCachedMethod(md);
0923             if (method != null) {
0924                 return method;
0925             }
0926 
0927             method = clazz.getMethod(methodName, parameterTypes);
0928 
0929             setMethodAccessible(method)// Default access superclass workaround
0930 
0931             cacheMethod(md, method);
0932             return method;
0933 
0934         catch (NoSuchMethodException e) { /* SWALLOW */ }
0935 
0936         // search through all methods 
0937         int paramSize = parameterTypes.length;
0938         Method bestMatch = null;
0939         Method[] methods = clazz.getMethods();
0940         float bestMatchCost = Float.MAX_VALUE;
0941         float myCost = Float.MAX_VALUE;
0942         for (int i = 0, size = methods.length; i < size; i++) {
0943             if (methods[i].getName().equals(methodName)) {
0944                 // compare parameters
0945                 Class[] methodsParams = methods[i].getParameterTypes();
0946                 int methodParamSize = methodsParams.length;
0947                 if (methodParamSize == paramSize) {
0948                     boolean match = true;
0949                     for (int n = 0; n < methodParamSize; n++) {
0950                         if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) {
0951                             match = false;
0952                             break;
0953                         }
0954                     }
0955 
0956                     if (match) {
0957                         // get accessible version of method
0958                         Method method = getAccessibleMethod(clazz, methods[i]);
0959                         if (method != null) {
0960                             setMethodAccessible(method)// Default access superclass workaround
0961                             myCost = getTotalTransformationCost(parameterTypes, method.getParameterTypes());
0962                             if (myCost < bestMatchCost) {
0963                                 bestMatch = method;
0964                                 bestMatchCost = myCost;
0965                             }
0966                         }
0967                     }
0968                 }
0969             }
0970         }
0971         if (bestMatch != null) { //find a match
0972             cacheMethod(md, bestMatch);
0973         }
0974         return bestMatch;
0975     }
0976 
0977     /**
0978      * Try to make the method accessible
0979      *
0980      @param method The source arguments
0981      */
0982     private static void setMethodAccessible(Method method) {
0983         try {
0984             //
0985             // XXX Default access superclass workaround
0986             //
0987             // When a public class has a default access superclass
0988             // with public methods, these methods are accessible.
0989             // Calling them from compiled code works fine.
0990             //
0991             // Unfortunately, using reflection to invoke these methods
0992             // seems to (wrongly) to prevent access even when the method
0993             // modifer is public.
0994             //
0995             // The following workaround solves the problem but will only
0996             // work from sufficiently privilages code. 
0997             //
0998             // Better workarounds would be greatfully accepted.
0999             //
1000             if (!method.isAccessible()) {
1001                 method.setAccessible(true);
1002             }
1003 
1004         catch (SecurityException se) {
1005             // ignore
1006         }
1007     }
1008 
1009     /**
1010      * Returns the sum of the object transformation cost for each class in the source
1011      * argument list.
1012      *
1013      @param srcArgs  The source arguments
1014      @param destArgs The destination arguments
1015      @return The total transformation cost
1016      */
1017     private static float getTotalTransformationCost(Class[] srcArgs, Class[] destArgs) {
1018 
1019         float totalCost = 0.0f;
1020         for (int i = 0; i < srcArgs.length; i++) {
1021             Class srcClass, destClass;
1022             srcClass = srcArgs[i];
1023             destClass = destArgs[i];
1024             totalCost += getObjectTransformationCost(srcClass, destClass);
1025         }
1026 
1027         return totalCost;
1028     }
1029 
1030     /**
1031      * Gets the number of steps required needed to turn the source class into the
1032      * destination class. This represents the number of steps in the object hierarchy
1033      * graph.
1034      *
1035      @param srcClass  The source class
1036      @param destClass The destination class
1037      @return The cost of transforming an object
1038      */
1039     private static float getObjectTransformationCost(Class srcClass, Class destClass) {
1040         float cost = 0.0f;
1041         while (destClass != null && !destClass.equals(srcClass)) {
1042             if (destClass.isInterface() && isAssignmentCompatible(destClass, srcClass)) {
1043                 // slight penalty for interface match. 
1044                 // we still want an exact match to override an interface match, but  
1045                 // an interface match should override anything where we have to get a 
1046                 // superclass.
1047                 cost += 0.25f;
1048                 break;
1049             }
1050             cost++;
1051             destClass = destClass.getSuperclass();
1052         }
1053 
1054         /*
1055          * If the destination class is null, we've travelled all the way up to 
1056          * an Object match. We'll penalize this by adding 1.5 to the cost.
1057          */
1058         if (destClass == null) {
1059             cost += 1.5f;
1060         }
1061 
1062         return cost;
1063     }
1064 
1065 
1066     /**
1067      <p>Determine whether a type can be used as a parameter in a method invocation.
1068      * This method handles primitive conversions correctly.</p>
1069      <p/>
1070      <p>In order words, it will match a <code>Boolean</code> to a <code>boolean</code>,
1071      * a <code>Long</code> to a <code>long</code>,
1072      * a <code>Float</code> to a <code>float</code>,
1073      * a <code>Integer</code> to a <code>int</code>,
1074      * and a <code>Double</code> to a <code>double</code>.
1075      * Now logic widening matches are allowed.
1076      * For example, a <code>Long</code> will not match a <code>int</code>.
1077      *
1078      @param parameterType    the type of parameter accepted by the method
1079      @param parameterization the type of parameter being tested
1080      @return true if the assignement is compatible.
1081      */
1082     public static boolean isAssignmentCompatible(Class<?> parameterType, Class<?> parameterization) {
1083         // try plain assignment
1084         if (parameterType.isAssignableFrom(parameterization)) {
1085             return true;
1086         }
1087 
1088         if (parameterType.isPrimitive()) {
1089             // this method does *not* do widening - you must specify exactly
1090             // is this the right behaviour?
1091             Class parameterWrapperClazz = getPrimitiveWrapper(parameterType);
1092             if (parameterWrapperClazz != null) {
1093                 return parameterWrapperClazz.equals(parameterization);
1094             }
1095         }
1096 
1097         return false;
1098     }
1099 
1100     /**
1101      * Gets the wrapper object class for the given primitive type class.
1102      * For example, passing <code>boolean.class</code> returns <code>Boolean.class</code>
1103      *
1104      @param primitiveType the primitive type class for which a match is to be found
1105      @return the wrapper type associated with the given primitive
1106      *         or null if no match is found
1107      */
1108     public static Class getPrimitiveWrapper(Class primitiveType) {
1109         // does anyone know a better strategy than comparing names?
1110         if (boolean.class.equals(primitiveType)) {
1111             return Boolean.class;
1112         else if (float.class.equals(primitiveType)) {
1113             return Float.class;
1114         else if (long.class.equals(primitiveType)) {
1115             return Long.class;
1116         else if (int.class.equals(primitiveType)) {
1117             return Integer.class;
1118         else if (short.class.equals(primitiveType)) {
1119             return Short.class;
1120         else if (byte.class.equals(primitiveType)) {
1121             return Byte.class;
1122         else if (double.class.equals(primitiveType)) {
1123             return Double.class;
1124         else if (char.class.equals(primitiveType)) {
1125             return Character.class;
1126         else {
1127 
1128             return null;
1129         }
1130     }
1131 
1132     /**
1133      * Gets the class for the primitive type corresponding to the primitive wrapper class given.
1134      * For example, an instance of <code>Boolean.class</code> returns a <code>boolean.class</code>.
1135      *
1136      @param wrapperType the
1137      @return the primitive type class corresponding to the given wrapper class,
1138      *         null if no match is found
1139      */
1140     public static Class getPrimitiveType(Class wrapperType) {
1141         // does anyone know a better strategy than comparing names?
1142         if (Boolean.class.equals(wrapperType)) {
1143             return boolean.class;
1144         else if (Float.class.equals(wrapperType)) {
1145             return float.class;
1146         else if (Long.class.equals(wrapperType)) {
1147             return long.class;
1148         else if (Integer.class.equals(wrapperType)) {
1149             return int.class;
1150         else if (Short.class.equals(wrapperType)) {
1151             return short.class;
1152         else if (Byte.class.equals(wrapperType)) {
1153             return byte.class;
1154         else if (Double.class.equals(wrapperType)) {
1155             return double.class;
1156         else if (Character.class.equals(wrapperType)) {
1157             return char.class;
1158         else {
1159             return null;
1160         }
1161     }
1162 
1163     /**
1164      * Find a non primitive representation for given primitive class.
1165      *
1166      @param clazz the class to find a representation for, not null
1167      @return the original class if it not a primitive. Otherwise the wrapper class. Not null
1168      */
1169     public static Class toNonPrimitiveClass(Class clazz) {
1170         if (clazz.isPrimitive()) {
1171             Class primitiveClazz = MethodUtils.getPrimitiveWrapper(clazz);
1172             // the above method returns 
1173             if (primitiveClazz != null) {
1174                 return primitiveClazz;
1175             else {
1176                 return clazz;
1177             }
1178         else {
1179             return clazz;
1180         }
1181     }
1182 
1183 
1184     /**
1185      * Return the method from the cache, if present.
1186      *
1187      @param md The method descriptor
1188      @return The cached method
1189      */
1190     private static Method getCachedMethod(MethodDescriptor md) {
1191         if (CACHE_METHODS) {
1192             Reference methodRef = (Referencecache.get(md);
1193             if (methodRef != null) {
1194                 return (MethodmethodRef.get();
1195             }
1196         }
1197         return null;
1198     }
1199 
1200     /**
1201      * Add a method to the cache.
1202      *
1203      @param md     The method descriptor
1204      @param method The method to cache
1205      */
1206     private static void cacheMethod(MethodDescriptor md, Method method) {
1207         if (CACHE_METHODS) {
1208             if (method != null) {
1209                 cache.put(md, new WeakReference(method));
1210             }
1211         }
1212     }
1213 
1214     public static Object invokeSafe(Method method, Object instance, Object[] args) {
1215         try {
1216             return method.invoke(instance, args);
1217         catch (IllegalAccessException e) {
1218             // ignore
1219         catch (InvocationTargetException e) {
1220             // ignore
1221         }
1222         return null;
1223     }
1224 
1225     /**
1226      * Represents the key to looking up a Method by reflection.
1227      */
1228     private static class MethodDescriptor {
1229         private Class cls;
1230         private String methodName;
1231         private Class[] paramTypes;
1232         private boolean exact;
1233         private int hashCode;
1234 
1235         /**
1236          * The sole constructor.
1237          *
1238          @param cls        the class to reflect, must not be null
1239          @param methodName the method name to obtain
1240          @param paramTypes the array of classes representing the paramater types
1241          @param exact      whether the match has to be exact.
1242          */
1243         public MethodDescriptor(Class cls, String methodName, Class[] paramTypes, boolean exact) {
1244             if (cls == null) {
1245                 throw new IllegalArgumentException("Class must not be null");
1246             }
1247             if (methodName == null) {
1248                 throw new IllegalArgumentException("Method Name must not be null");
1249             }
1250             if (paramTypes == null) {
1251                 paramTypes = EMPTY_CLASS_PARAMETERS;
1252             }
1253 
1254             this.cls = cls;
1255             this.methodName = methodName;
1256             this.paramTypes = paramTypes;
1257             this.exact = exact;
1258 
1259             this.hashCode = methodName.length();
1260         }
1261 
1262         /**
1263          * Checks for equality.
1264          *
1265          @param obj object to be tested for equality
1266          @return true, if the object describes the same Method.
1267          */
1268         public boolean equals(Object obj) {
1269             if (!(obj instanceof MethodDescriptor)) {
1270                 return false;
1271             }
1272             MethodDescriptor md = (MethodDescriptorobj;
1273 
1274             return (
1275                 exact == md.exact &&
1276                     methodName.equals(md.methodName&&
1277                     cls.equals(md.cls&&
1278                     java.util.Arrays.equals(paramTypes, md.paramTypes)
1279             );
1280         }
1281 
1282         /**
1283          * Returns the string length of method name. I.e. if the
1284          * hashcodes are different, the objects are different. If the
1285          * hashcodes are the same, need to use the equals method to
1286          * determine equality.
1287          *
1288          @return the string length of method name.
1289          */
1290         public int hashCode() {
1291             return hashCode;
1292         }
1293     }
1294 }