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