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