001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.beanutils;
019
020import java.lang.ref.Reference;
021import java.lang.ref.WeakReference;
022import java.lang.reflect.InvocationTargetException;
023import java.lang.reflect.Method;
024import java.lang.reflect.Modifier;
025import java.util.Collections;
026import java.util.Map;
027import java.util.WeakHashMap;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031
032/**
033 * <p>Utility reflection methods focused on methods in general rather than properties in particular.</p>
034 *
035 * <strong>Known Limitations: Accessing Public Methods In A Default Access Superclass</strong>
036 * <p>There is an issue when invoking public methods contained in a default access superclass.
037 * Reflection locates these methods fine and correctly assigns them as public.
038 * However, an <code>IllegalAccessException</code> is thrown if the method is invoked.</p>
039 *
040 * <p><code>MethodUtils</code> contains a workaround for this situation.
041 * It will attempt to call <code>setAccessible</code> on this method.
042 * If this call succeeds, then the method can be invoked as normal.
043 * This call will only succeed when the application has sufficient security privileges.
044 * If this call fails then a warning will be logged and the method may fail.</p>
045 *
046 */
047public class MethodUtils {
048
049    /**
050     * Represents the key to looking up a Method by reflection.
051     */
052    private static class MethodDescriptor {
053        private final Class<?> cls;
054        private final String methodName;
055        private final Class<?>[] paramTypes;
056        private final boolean exact;
057        private final int hashCode;
058
059        /**
060         * The sole constructor.
061         *
062         * @param cls  the class to reflect, must not be null
063         * @param methodName  the method name to obtain
064         * @param paramTypes the array of classes representing the parameter types
065         * @param exact whether the match has to be exact.
066         */
067        public MethodDescriptor(final Class<?> cls, final String methodName, Class<?>[] paramTypes, final boolean exact) {
068            if (cls == null) {
069                throw new IllegalArgumentException("Class cannot be null");
070            }
071            if (methodName == null) {
072                throw new IllegalArgumentException("Method Name cannot be null");
073            }
074            if (paramTypes == null) {
075                paramTypes = EMPTY_CLASS_PARAMETERS;
076            }
077
078            this.cls = cls;
079            this.methodName = methodName;
080            this.paramTypes = paramTypes;
081            this.exact= exact;
082
083            this.hashCode = methodName.length();
084        }
085        /**
086         * Checks for equality.
087         * @param obj object to be tested for equality
088         * @return true, if the object describes the same Method.
089         */
090        @Override
091        public boolean equals(final Object obj) {
092            if (!(obj instanceof MethodDescriptor)) {
093                return false;
094            }
095            final MethodDescriptor md = (MethodDescriptor)obj;
096
097            return exact == md.exact &&
098            methodName.equals(md.methodName) &&
099            cls.equals(md.cls) &&
100            java.util.Arrays.equals(paramTypes, md.paramTypes);
101        }
102        /**
103         * Returns the string length of method name. I.e. if the
104         * hashcodes are different, the objects are different. If the
105         * hashcodes are the same, need to use the equals method to
106         * determine equality.
107         * @return the string length of method name.
108         */
109        @Override
110        public int hashCode() {
111            return hashCode;
112        }
113    }
114
115    /**
116     * Only log warning about accessibility work around once.
117     * <p>
118     * Note that this is broken when this class is deployed via a shared
119     * classloader in a container, as the warning message will be emitted
120     * only once, not once per webapp. However making the warning appear
121     * once per webapp means having a map keyed by context classloader
122     * which introduces nasty memory-leak problems. As this warning is
123     * really optional we can ignore this problem; only one of the webapps
124     * will get the warning in its logs but that should be good enough.
125     */
126    private static boolean loggedAccessibleWarning;
127
128    /**
129     * Indicates whether methods should be cached for improved performance.
130     * <p>
131     * Note that when this class is deployed via a shared classloader in
132     * a container, this will affect all webapps. However making this
133     * configurable per webapp would mean having a map keyed by context classloader
134     * which may introduce memory-leak problems.
135     * </p>
136     */
137    private static boolean CACHE_METHODS = true;
138    /** An empty class array */
139    private static final Class<?>[] EMPTY_CLASS_PARAMETERS = new Class[0];
140
141    /** An empty object array */
142    private static final Object[] EMPTY_OBJECT_ARRAY = {};
143
144    /**
145     * Stores a cache of MethodDescriptor to Method in a WeakHashMap.
146     * <p>
147     * The keys into this map only ever exist as temporary variables within
148     * methods of this class, and are never exposed to users of this class.
149     * This means that the WeakHashMap is used only as a mechanism for
150     * limiting the size of the cache, ie a way to tell the garbage collector
151     * that the contents of the cache can be completely garbage-collected
152     * whenever it needs the memory. Whether this is a good approach to
153     * this problem is doubtful; something like the commons-collections
154     * LRUMap may be more appropriate (though of course selecting an
155     * appropriate size is an issue).
156     * </p>
157     * <p>
158     * This static variable is safe even when this code is deployed via a
159     * shared classloader because it is keyed via a MethodDescriptor object
160     * which has a Class as one of its members and that member is used in
161     * the MethodDescriptor.equals method. So two components that load the same
162     * class via different classloaders will generate non-equal MethodDescriptor
163     * objects and hence end up with different entries in the map.
164     * </p>
165     */
166    private static final Map<MethodDescriptor, Reference<Method>> cache = Collections
167            .synchronizedMap(new WeakHashMap<MethodDescriptor, Reference<Method>>());
168
169    /**
170     * Add a method to the cache.
171     *
172     * @param md The method descriptor
173     * @param method The method to cache
174     */
175    private static void cacheMethod(final MethodDescriptor md, final Method method) {
176        if (CACHE_METHODS && method != null) {
177            cache.put(md, new WeakReference<>(method));
178        }
179    }
180
181    /**
182     * Clear the method cache.
183     * @return the number of cached methods cleared
184     * @since 1.8.0
185     */
186    public static synchronized int clearCache() {
187        final int size = cache.size();
188        cache.clear();
189        return size;
190    }
191
192    /**
193     * <p>Return an accessible method (that is, one that can be invoked via
194     * reflection) that implements the specified Method.  If no such method
195     * can be found, return <code>null</code>.</p>
196     *
197     * @param clazz The class of the object
198     * @param method The method that we wish to call
199     * @return The accessible method
200     * @since 1.8.0
201     */
202    public static Method getAccessibleMethod(Class<?> clazz, Method method) {
203
204        // Make sure we have a method to check
205        // If the requested method is not public we cannot call it
206        if (method == null || !Modifier.isPublic(method.getModifiers())) {
207            return null;
208        }
209
210        boolean sameClass = true;
211        if (clazz == null) {
212            clazz = method.getDeclaringClass();
213        } else {
214            sameClass = clazz.equals(method.getDeclaringClass());
215            if (!method.getDeclaringClass().isAssignableFrom(clazz)) {
216                throw new IllegalArgumentException(clazz.getName() +
217                        " is not assignable from " + method.getDeclaringClass().getName());
218            }
219        }
220
221        // If the class is public, we are done
222        if (Modifier.isPublic(clazz.getModifiers())) {
223            if (!sameClass && !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
224                setMethodAccessible(method); // Default access superclass workaround
225            }
226            return method;
227        }
228
229        final String methodName      = method.getName();
230        final Class<?>[] parameterTypes = method.getParameterTypes();
231
232        // Check the implemented interfaces and subinterfaces
233        method =
234                getAccessibleMethodFromInterfaceNest(clazz,
235                        methodName,
236                        parameterTypes);
237
238        // Check the superclass chain
239        if (method == null) {
240            method = getAccessibleMethodFromSuperclass(clazz,
241                        methodName,
242                        parameterTypes);
243        }
244
245        return method;
246    }
247
248    /**
249     * <p>Return an accessible method (that is, one that can be invoked via
250     * reflection) with given name and a single parameter.  If no such method
251     * can be found, return <code>null</code>.
252     * Basically, a convenience wrapper that constructs a <code>Class</code>
253     * array for you.</p>
254     *
255     * @param clazz get method from this class
256     * @param methodName get method with this name
257     * @param parameterType taking this type of parameter
258     * @return The accessible method
259     */
260    public static Method getAccessibleMethod(
261            final Class<?> clazz,
262            final String methodName,
263            final Class<?> parameterType) {
264
265        final Class<?>[] parameterTypes = {parameterType};
266        return getAccessibleMethod(clazz, methodName, parameterTypes);
267    }
268
269    /**
270     * <p>Return an accessible method (that is, one that can be invoked via
271     * reflection) with given name and parameters.  If no such method
272     * can be found, return <code>null</code>.
273     * This is just a convenient wrapper for
274     * {@link #getAccessibleMethod(Method method)}.</p>
275     *
276     * @param clazz get method from this class
277     * @param methodName get method with this name
278     * @param parameterTypes with these parameters types
279     * @return The accessible method
280     */
281    public static Method getAccessibleMethod(
282            final Class<?> clazz,
283            final String methodName,
284            final Class<?>[] parameterTypes) {
285
286        try {
287            final MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, true);
288            // Check the cache first
289            Method method = getCachedMethod(md);
290            if (method != null) {
291                return method;
292            }
293
294            method =  getAccessibleMethod
295                    (clazz, clazz.getMethod(methodName, parameterTypes));
296            cacheMethod(md, method);
297            return method;
298        } catch (final NoSuchMethodException e) {
299            return null;
300        }
301    }
302
303    /**
304     * <p>Return an accessible method (that is, one that can be invoked via
305     * reflection) that implements the specified Method.  If no such method
306     * can be found, return <code>null</code>.</p>
307     *
308     * @param method The method that we wish to call
309     * @return The accessible method
310     */
311    public static Method getAccessibleMethod(final Method method) {
312
313        // Make sure we have a method to check
314        if (method == null) {
315            return null;
316        }
317
318        return getAccessibleMethod(method.getDeclaringClass(), method);
319    }
320
321    /**
322     * <p>Return an accessible method (that is, one that can be invoked via
323     * reflection) that implements the specified method, by scanning through
324     * all implemented interfaces and subinterfaces.  If no such method
325     * can be found, return <code>null</code>.</p>
326     *
327     * <p> There isn't any good reason why this method must be private.
328     * It is because there doesn't seem any reason why other classes should
329     * call this rather than the higher level methods.</p>
330     *
331     * @param clazz Parent class for the interfaces to be checked
332     * @param methodName Method name of the method we wish to call
333     * @param parameterTypes The parameter type signatures
334     */
335    private static Method getAccessibleMethodFromInterfaceNest
336            (Class<?> clazz, final String methodName, final Class<?>[] parameterTypes) {
337
338        Method method = null;
339
340        // Search up the superclass chain
341        for (; clazz != null; clazz = clazz.getSuperclass()) {
342
343            // Check the implemented interfaces of the parent class
344            final Class<?>[] interfaces = clazz.getInterfaces();
345            for (final Class<?> element : interfaces) {
346
347                // Is this interface public?
348                if (!Modifier.isPublic(element.getModifiers())) {
349                    continue;
350                }
351
352                // Does the method exist on this interface?
353                try {
354                    method = element.getDeclaredMethod(methodName,
355                            parameterTypes);
356                } catch (final NoSuchMethodException e) {
357                    /* Swallow, if no method is found after the loop then this
358                     * method returns null.
359                     */
360                }
361                if (method != null) {
362                    return method;
363                }
364
365                // Recursively check our parent interfaces
366                method =
367                        getAccessibleMethodFromInterfaceNest(element,
368                                methodName,
369                                parameterTypes);
370                if (method != null) {
371                    return method;
372                }
373
374            }
375
376        }
377
378        // We did not find anything
379        return null;
380    }
381
382    /**
383     * <p>Return an accessible method (that is, one that can be invoked via
384     * reflection) by scanning through the superclasses. If no such method
385     * can be found, return <code>null</code>.</p>
386     *
387     * @param clazz Class to be checked
388     * @param methodName Method name of the method we wish to call
389     * @param parameterTypes The parameter type signatures
390     */
391    private static Method getAccessibleMethodFromSuperclass
392            (final Class<?> clazz, final String methodName, final Class<?>[] parameterTypes) {
393
394        Class<?> parentClazz = clazz.getSuperclass();
395        while (parentClazz != null) {
396            if (Modifier.isPublic(parentClazz.getModifiers())) {
397                try {
398                    return parentClazz.getMethod(methodName, parameterTypes);
399                } catch (final NoSuchMethodException e) {
400                    return null;
401                }
402            }
403            parentClazz = parentClazz.getSuperclass();
404        }
405        return null;
406    }
407
408    /**
409     * Return the method from the cache, if present.
410     *
411     * @param md The method descriptor
412     * @return The cached method
413     */
414    private static Method getCachedMethod(final MethodDescriptor md) {
415        if (CACHE_METHODS) {
416            final Reference<Method> methodRef = cache.get(md);
417            if (methodRef != null) {
418                return methodRef.get();
419            }
420        }
421        return null;
422    }
423
424    /**
425     * <p>Find an accessible method that matches the given name and has compatible parameters.
426     * Compatible parameters mean that every method parameter is assignable from
427     * the given parameters.
428     * In other words, it finds a method with the given name
429     * that will take the parameters given.
430     * </p>
431     * <p>This method is slightly undeterministic since it loops
432     * through methods names and return the first matching method.</p>
433     * <p>This method is used by
434     * {@link
435     * #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
436     * </p>
437     * <p>This method can match primitive parameter by passing in wrapper classes.
438     * For example, a <code>Boolean</code> will match a primitive <code>boolean</code>
439     * parameter.
440     * </p>
441     *
442     * @param clazz find method in this class
443     * @param methodName find method with this name
444     * @param parameterTypes find method with compatible parameters
445     * @return The accessible method
446     */
447    public static Method getMatchingAccessibleMethod(
448                                                final Class<?> clazz,
449                                                final String methodName,
450                                                final Class<?>[] parameterTypes) {
451        // trace logging
452        final Log log = LogFactory.getLog(MethodUtils.class);
453        if (log.isTraceEnabled()) {
454            log.trace("Matching name=" + methodName + " on " + clazz);
455        }
456        final MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, false);
457
458        // see if we can find the method directly
459        // most of the time this works and it's much faster
460        try {
461            // Check the cache first
462            Method method = getCachedMethod(md);
463            if (method != null) {
464                return method;
465            }
466
467            method = clazz.getMethod(methodName, parameterTypes);
468            if (log.isTraceEnabled()) {
469                log.trace("Found straight match: " + method);
470                log.trace("isPublic:" + Modifier.isPublic(method.getModifiers()));
471            }
472
473            setMethodAccessible(method); // Default access superclass workaround
474
475            cacheMethod(md, method);
476            return method;
477
478        } catch (final NoSuchMethodException e) { /* SWALLOW */ }
479
480        // search through all methods
481        final int paramSize = parameterTypes.length;
482        Method bestMatch = null;
483        final Method[] methods = clazz.getMethods();
484        float bestMatchCost = Float.MAX_VALUE;
485        float myCost = Float.MAX_VALUE;
486        for (final Method method2 : methods) {
487            if (method2.getName().equals(methodName)) {
488                // log some trace information
489                if (log.isTraceEnabled()) {
490                    log.trace("Found matching name:");
491                    log.trace(method2);
492                }
493
494                // compare parameters
495                final Class<?>[] methodsParams = method2.getParameterTypes();
496                final int methodParamSize = methodsParams.length;
497                if (methodParamSize == paramSize) {
498                    boolean match = true;
499                    for (int n = 0 ; n < methodParamSize; n++) {
500                        if (log.isTraceEnabled()) {
501                            log.trace("Param=" + parameterTypes[n].getName());
502                            log.trace("Method=" + methodsParams[n].getName());
503                        }
504                        if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) {
505                            if (log.isTraceEnabled()) {
506                                log.trace(methodsParams[n] + " is not assignable from "
507                                            + parameterTypes[n]);
508                            }
509                            match = false;
510                            break;
511                        }
512                    }
513
514                    if (match) {
515                        // get accessible version of method
516                        final Method method = getAccessibleMethod(clazz, method2);
517                        if (method != null) {
518                            if (log.isTraceEnabled()) {
519                                log.trace(method + " accessible version of "
520                                            + method2);
521                            }
522                            setMethodAccessible(method); // Default access superclass workaround
523                            myCost = getTotalTransformationCost(parameterTypes,method.getParameterTypes());
524                            if (myCost < bestMatchCost) {
525                                bestMatch = method;
526                                bestMatchCost = myCost;
527                            }
528                        }
529
530                        log.trace("Couldn't find accessible method.");
531                    }
532                }
533            }
534        }
535        if (bestMatch != null) {
536            cacheMethod(md, bestMatch);
537        } else {
538            // didn't find a match
539            log.trace("No match found.");
540        }
541
542        return bestMatch;
543    }
544
545    /**
546     * Gets the number of steps required needed to turn the source class into the
547     * destination class. This represents the number of steps in the object hierarchy
548     * graph.
549     * @param srcClass The source class
550     * @param destClass The destination class
551     * @return The cost of transforming an object
552     */
553    private static float getObjectTransformationCost(Class<?> srcClass, final Class<?> destClass) {
554        float cost = 0.0f;
555        while (srcClass != null && !destClass.equals(srcClass)) {
556            if (destClass.isPrimitive()) {
557                final Class<?> destClassWrapperClazz = getPrimitiveWrapper(destClass);
558                if (destClassWrapperClazz != null && destClassWrapperClazz.equals(srcClass)) {
559                    cost += 0.25f;
560                    break;
561                }
562            }
563            if (destClass.isInterface() && isAssignmentCompatible(destClass,srcClass)) {
564                // slight penalty for interface match.
565                // we still want an exact match to override an interface match, but
566                // an interface match should override anything where we have to get a
567                // superclass.
568                cost += 0.25f;
569                break;
570            }
571            cost++;
572            srcClass = srcClass.getSuperclass();
573        }
574
575        /*
576         * If the destination class is null, we've travelled all the way up to
577         * an Object match. We'll penalize this by adding 1.5 to the cost.
578         */
579        if (srcClass == null) {
580            cost += 1.5f;
581        }
582
583        return cost;
584    }
585
586    /**
587     * Gets the class for the primitive type corresponding to the primitive wrapper class given.
588     * For example, an instance of <code>Boolean.class</code> returns a <code>boolean.class</code>.
589     * @param wrapperType the
590     * @return the primitive type class corresponding to the given wrapper class,
591     * null if no match is found
592     */
593    public static Class<?> getPrimitiveType(final Class<?> wrapperType) {
594        // does anyone know a better strategy?
595        if (Boolean.class.equals(wrapperType)) {
596            return boolean.class;
597        }
598        if (Float.class.equals(wrapperType)) {
599            return float.class;
600        }
601        if (Long.class.equals(wrapperType)) {
602            return long.class;
603        }
604        if (Integer.class.equals(wrapperType)) {
605            return int.class;
606        }
607        if (Short.class.equals(wrapperType)) {
608            return short.class;
609        }
610        if (Byte.class.equals(wrapperType)) {
611            return byte.class;
612        }
613        if (Double.class.equals(wrapperType)) {
614            return double.class;
615        }
616        if (Character.class.equals(wrapperType)) {
617            return char.class;
618        }
619        final Log log = LogFactory.getLog(MethodUtils.class);
620        if (log.isDebugEnabled()) {
621            log.debug("Not a known primitive wrapper class: " + wrapperType);
622        }
623        return null;
624    }
625
626    /**
627     * Gets the wrapper object class for the given primitive type class.
628     * For example, passing <code>boolean.class</code> returns <code>Boolean.class</code>
629     * @param primitiveType the primitive type class for which a match is to be found
630     * @return the wrapper type associated with the given primitive
631     * or null if no match is found
632     */
633    public static Class<?> getPrimitiveWrapper(final Class<?> primitiveType) {
634        // does anyone know a better strategy than comparing names?
635        if (boolean.class.equals(primitiveType)) {
636            return Boolean.class;
637        }
638        if (float.class.equals(primitiveType)) {
639            return Float.class;
640        }
641        if (long.class.equals(primitiveType)) {
642            return Long.class;
643        }
644        if (int.class.equals(primitiveType)) {
645            return Integer.class;
646        }
647        if (short.class.equals(primitiveType)) {
648            return Short.class;
649        }
650        if (byte.class.equals(primitiveType)) {
651            return Byte.class;
652        }
653        if (double.class.equals(primitiveType)) {
654            return Double.class;
655        }
656        if (char.class.equals(primitiveType)) {
657            return Character.class;
658        }
659        return null;
660    }
661
662    /**
663     * Returns the sum of the object transformation cost for each class in the source
664     * argument list.
665     * @param srcArgs The source arguments
666     * @param destArgs The destination arguments
667     * @return The total transformation cost
668     */
669    private static float getTotalTransformationCost(final Class<?>[] srcArgs, final Class<?>[] destArgs) {
670
671        float totalCost = 0.0f;
672        for (int i = 0; i < srcArgs.length; i++) {
673            Class<?> srcClass, destClass;
674            srcClass = srcArgs[i];
675            destClass = destArgs[i];
676            totalCost += getObjectTransformationCost(srcClass, destClass);
677        }
678
679        return totalCost;
680    }
681
682    /**
683     * <p>Invoke a method whose parameter type matches exactly the object
684     * type.</p>
685     *
686     * <p> This is a convenient wrapper for
687     * {@link #invokeExactMethod(Object object,String methodName,Object [] args)}.
688     * </p>
689     *
690     * @param object invoke method on this object
691     * @param methodName get method with this name
692     * @param arg use this argument. May be null (this will result in calling the
693     *  parameterless method with name {@code methodName}).
694     * @return The value returned by the invoked method
695     * @throws NoSuchMethodException if there is no such accessible method
696     * @throws InvocationTargetException wraps an exception thrown by the
697     *  method invoked
698     * @throws IllegalAccessException if the requested method is not accessible
699     *  via reflection
700     */
701    public static Object invokeExactMethod(
702            final Object object,
703            final String methodName,
704            final Object arg)
705            throws
706            NoSuchMethodException,
707            IllegalAccessException,
708            InvocationTargetException {
709
710        final Object[] args = toArray(arg);
711        return invokeExactMethod(object, methodName, args);
712    }
713
714    /**
715     * <p>Invoke a method whose parameter types match exactly the object
716     * types.</p>
717     *
718     * <p> This uses reflection to invoke the method obtained from a call to
719     * <code>getAccessibleMethod()</code>.</p>
720     *
721     * @param object invoke method on this object
722     * @param methodName get method with this name
723     * @param args use these arguments - treat null as empty array (passing null will
724     *  result in calling the parameterless method with name {@code methodName}).
725     * @return The value returned by the invoked method
726     * @throws NoSuchMethodException if there is no such accessible method
727     * @throws InvocationTargetException wraps an exception thrown by the
728     *  method invoked
729     * @throws IllegalAccessException if the requested method is not accessible
730     *  via reflection
731     */
732    public static Object invokeExactMethod(
733            final Object object,
734            final String methodName,
735            Object[] args)
736            throws
737            NoSuchMethodException,
738            IllegalAccessException,
739            InvocationTargetException {
740
741        if (args == null) {
742            args = EMPTY_OBJECT_ARRAY;
743        }
744        final int arguments = args.length;
745        final Class<?>[] parameterTypes = new Class[arguments];
746        for (int i = 0; i < arguments; i++) {
747            parameterTypes[i] = args[i].getClass();
748        }
749        return invokeExactMethod(object, methodName, args, parameterTypes);
750    }
751
752    /**
753     * <p>Invoke a method whose parameter types match exactly the parameter
754     * types given.</p>
755     *
756     * <p>This uses reflection to invoke the method obtained from a call to
757     * <code>getAccessibleMethod()</code>.</p>
758     *
759     * @param object invoke method on this object
760     * @param methodName get method with this name
761     * @param args use these arguments - treat null as empty array (passing null will
762     *  result in calling the parameterless method with name {@code methodName}).
763     * @param parameterTypes match these parameters - treat null as empty array
764     * @return The value returned by the invoked method
765     * @throws NoSuchMethodException if there is no such accessible method
766     * @throws InvocationTargetException wraps an exception thrown by the
767     *  method invoked
768     * @throws IllegalAccessException if the requested method is not accessible
769     *  via reflection
770     */
771    public static Object invokeExactMethod(
772            final Object object,
773            final String methodName,
774            Object[] args,
775            Class<?>[] parameterTypes)
776            throws
777            NoSuchMethodException,
778            IllegalAccessException,
779            InvocationTargetException {
780
781        if (args == null) {
782            args = EMPTY_OBJECT_ARRAY;
783        }
784
785        if (parameterTypes == null) {
786            parameterTypes = EMPTY_CLASS_PARAMETERS;
787        }
788
789        final Method method = getAccessibleMethod(
790                object.getClass(),
791                methodName,
792                parameterTypes);
793        if (method == null) {
794            throw new NoSuchMethodException("No such accessible method: " +
795                    methodName + "() on object: " + object.getClass().getName());
796        }
797        return method.invoke(object, args);
798    }
799
800    /**
801     * <p>Invoke a static method whose parameter type matches exactly the object
802     * type.</p>
803     *
804     * <p> This is a convenient wrapper for
805     * {@link #invokeExactStaticMethod(Class objectClass,String methodName,Object [] args)}.
806     * </p>
807     *
808     * @param objectClass invoke static method on this class
809     * @param methodName get method with this name
810     * @param arg use this argument. May be null (this will result in calling the
811     *  parameterless method with name {@code methodName}).
812     * @return The value returned by the invoked method
813     * @throws NoSuchMethodException if there is no such accessible method
814     * @throws InvocationTargetException wraps an exception thrown by the
815     *  method invoked
816     * @throws IllegalAccessException if the requested method is not accessible
817     *  via reflection
818     * @since 1.8.0
819     */
820    public static Object invokeExactStaticMethod(
821            final Class<?> objectClass,
822            final String methodName,
823            final Object arg)
824            throws
825            NoSuchMethodException,
826            IllegalAccessException,
827            InvocationTargetException {
828
829        final Object[] args = toArray(arg);
830        return invokeExactStaticMethod (objectClass, methodName, args);
831    }
832
833    /**
834     * <p>Invoke a static method whose parameter types match exactly the object
835     * types.</p>
836     *
837     * <p> This uses reflection to invoke the method obtained from a call to
838     * {@link #getAccessibleMethod(Class, String, Class[])}.</p>
839     *
840     * @param objectClass invoke static method on this class
841     * @param methodName get method with this name
842     * @param args use these arguments - treat null as empty array (passing null will
843     *  result in calling the parameterless method with name {@code methodName}).
844     * @return The value returned by the invoked method
845     * @throws NoSuchMethodException if there is no such accessible method
846     * @throws InvocationTargetException wraps an exception thrown by the
847     *  method invoked
848     * @throws IllegalAccessException if the requested method is not accessible
849     *  via reflection
850     * @since 1.8.0
851     */
852    public static Object invokeExactStaticMethod(
853            final Class<?> objectClass,
854            final String methodName,
855            Object[] args)
856            throws
857            NoSuchMethodException,
858            IllegalAccessException,
859            InvocationTargetException {
860
861        if (args == null) {
862            args = EMPTY_OBJECT_ARRAY;
863        }
864        final int arguments = args.length;
865        final Class<?>[] parameterTypes = new Class[arguments];
866        for (int i = 0; i < arguments; i++) {
867            parameterTypes[i] = args[i].getClass();
868        }
869        return invokeExactStaticMethod(objectClass, methodName, args, parameterTypes);
870    }
871
872    /**
873     * <p>Invoke a static method whose parameter types match exactly the parameter
874     * types given.</p>
875     *
876     * <p>This uses reflection to invoke the method obtained from a call to
877     * {@link #getAccessibleMethod(Class, String, Class[])}.</p>
878     *
879     * @param objectClass invoke static method on this class
880     * @param methodName get method with this name
881     * @param args use these arguments - treat null as empty array (passing null will
882     *  result in calling the parameterless method with name {@code methodName}).
883     * @param parameterTypes match these parameters - treat null as empty array
884     * @return The value returned by the invoked method
885     * @throws NoSuchMethodException if there is no such accessible method
886     * @throws InvocationTargetException wraps an exception thrown by the
887     *  method invoked
888     * @throws IllegalAccessException if the requested method is not accessible
889     *  via reflection
890     * @since 1.8.0
891     */
892    public static Object invokeExactStaticMethod(
893            final Class<?> objectClass,
894            final String methodName,
895            Object[] args,
896            Class<?>[] parameterTypes)
897            throws
898            NoSuchMethodException,
899            IllegalAccessException,
900            InvocationTargetException {
901
902        if (args == null) {
903            args = EMPTY_OBJECT_ARRAY;
904        }
905
906        if (parameterTypes == null) {
907            parameterTypes = EMPTY_CLASS_PARAMETERS;
908        }
909
910        final Method method = getAccessibleMethod(
911                objectClass,
912                methodName,
913                parameterTypes);
914        if (method == null) {
915            throw new NoSuchMethodException("No such accessible method: " +
916                    methodName + "() on class: " + objectClass.getName());
917        }
918        return method.invoke(null, args);
919    }
920
921    /**
922     * <p>Invoke a named method whose parameter type matches the object type.</p>
923     *
924     * <p>The behavior of this method is less deterministic
925     * than <code>invokeExactMethod()</code>.
926     * It loops through all methods with names that match
927     * and then executes the first it finds with compatible parameters.</p>
928     *
929     * <p>This method supports calls to methods taking primitive parameters
930     * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
931     * would match a <code>boolean</code> primitive.</p>
932     *
933     * <p> This is a convenient wrapper for
934     * {@link #invokeMethod(Object object,String methodName,Object [] args)}.
935     * </p>
936     *
937     * @param object invoke method on this object
938     * @param methodName get method with this name
939     * @param arg use this argument. May be null (this will result in calling the
940     *  parameterless method with name {@code methodName}).
941     * @return The value returned by the invoked method
942     * @throws NoSuchMethodException if there is no such accessible method
943     * @throws InvocationTargetException wraps an exception thrown by the
944     *  method invoked
945     * @throws IllegalAccessException if the requested method is not accessible
946     *  via reflection
947     */
948    public static Object invokeMethod(
949            final Object object,
950            final String methodName,
951            final Object arg)
952            throws
953            NoSuchMethodException,
954            IllegalAccessException,
955            InvocationTargetException {
956
957        final Object[] args = toArray(arg);
958        return invokeMethod(object, methodName, args);
959    }
960
961    /**
962     * <p>Invoke a named method whose parameter type matches the object type.</p>
963     *
964     * <p>The behavior of this method is less deterministic
965     * than {@link #invokeExactMethod(Object object,String methodName,Object [] args)}.
966     * It loops through all methods with names that match
967     * and then executes the first it finds with compatible parameters.</p>
968     *
969     * <p>This method supports calls to methods taking primitive parameters
970     * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
971     * would match a <code>boolean</code> primitive.</p>
972     *
973     * <p> This is a convenient wrapper for
974     * {@link #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
975     * </p>
976     *
977     * @param object invoke method on this object
978     * @param methodName get method with this name
979     * @param args use these arguments - treat null as empty array (passing null will
980     *  result in calling the parameterless method with name {@code methodName}).
981     * @return The value returned by the invoked method
982     * @throws NoSuchMethodException if there is no such accessible method
983     * @throws InvocationTargetException wraps an exception thrown by the
984     *  method invoked
985     * @throws IllegalAccessException if the requested method is not accessible
986     *  via reflection
987     */
988    public static Object invokeMethod(
989            final Object object,
990            final String methodName,
991            Object[] args)
992            throws
993            NoSuchMethodException,
994            IllegalAccessException,
995            InvocationTargetException {
996
997        if (args == null) {
998            args = EMPTY_OBJECT_ARRAY;
999        }
1000        final int arguments = args.length;
1001        final Class<?>[] parameterTypes = new Class[arguments];
1002        for (int i = 0; i < arguments; i++) {
1003            parameterTypes[i] = args[i].getClass();
1004        }
1005        return invokeMethod(object, methodName, args, parameterTypes);
1006    }
1007
1008    /**
1009     * <p>Invoke a named method whose parameter type matches the object type.</p>
1010     *
1011     * <p>The behavior of this method is less deterministic
1012     * than {@link
1013     * #invokeExactMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
1014     * It loops through all methods with names that match
1015     * and then executes the first it finds with compatible parameters.</p>
1016     *
1017     * <p>This method supports calls to methods taking primitive parameters
1018     * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
1019     * would match a <code>boolean</code> primitive.</p>
1020     *
1021     *
1022     * @param object invoke method on this object
1023     * @param methodName get method with this name
1024     * @param args use these arguments - treat null as empty array (passing null will
1025     *  result in calling the parameterless method with name {@code methodName}).
1026     * @param parameterTypes match these parameters - treat null as empty array
1027     * @return The value returned by the invoked method
1028     * @throws NoSuchMethodException if there is no such accessible method
1029     * @throws InvocationTargetException wraps an exception thrown by the
1030     *  method invoked
1031     * @throws IllegalAccessException if the requested method is not accessible
1032     *  via reflection
1033     */
1034    public static Object invokeMethod(
1035            final Object object,
1036            final String methodName,
1037            Object[] args,
1038            Class<?>[] parameterTypes)
1039                throws
1040                    NoSuchMethodException,
1041                    IllegalAccessException,
1042                    InvocationTargetException {
1043
1044        if (parameterTypes == null) {
1045            parameterTypes = EMPTY_CLASS_PARAMETERS;
1046        }
1047        if (args == null) {
1048            args = EMPTY_OBJECT_ARRAY;
1049        }
1050
1051        final Method method = getMatchingAccessibleMethod(
1052                object.getClass(),
1053                methodName,
1054                parameterTypes);
1055        if (method == null) {
1056            throw new NoSuchMethodException("No such accessible method: " +
1057                    methodName + "() on object: " + object.getClass().getName());
1058        }
1059        return method.invoke(object, args);
1060    }
1061
1062    /**
1063     * <p>Invoke a named static method whose parameter type matches the object type.</p>
1064     *
1065     * <p>The behavior of this method is less deterministic
1066     * than {@link #invokeExactMethod(Object, String, Object[], Class[])}.
1067     * It loops through all methods with names that match
1068     * and then executes the first it finds with compatible parameters.</p>
1069     *
1070     * <p>This method supports calls to methods taking primitive parameters
1071     * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
1072     * would match a <code>boolean</code> primitive.</p>
1073     *
1074     * <p> This is a convenient wrapper for
1075     * {@link #invokeStaticMethod(Class objectClass,String methodName,Object [] args)}.
1076     * </p>
1077     *
1078     * @param objectClass invoke static method on this class
1079     * @param methodName get method with this name
1080     * @param arg use this argument. May be null (this will result in calling the
1081     *  parameterless method with name {@code methodName}).
1082     * @return The value returned by the invoked method
1083     * @throws NoSuchMethodException if there is no such accessible method
1084     * @throws InvocationTargetException wraps an exception thrown by the
1085     *  method invoked
1086     * @throws IllegalAccessException if the requested method is not accessible
1087     *  via reflection
1088     * @since 1.8.0
1089     */
1090    public static Object invokeStaticMethod(
1091            final Class<?> objectClass,
1092            final String methodName,
1093            final Object arg)
1094            throws
1095            NoSuchMethodException,
1096            IllegalAccessException,
1097            InvocationTargetException {
1098
1099        final Object[] args = toArray(arg);
1100        return invokeStaticMethod (objectClass, methodName, args);
1101    }
1102
1103    /**
1104     * <p>Invoke a named static method whose parameter type matches the object type.</p>
1105     *
1106     * <p>The behavior of this method is less deterministic
1107     * than {@link #invokeExactMethod(Object object,String methodName,Object [] args)}.
1108     * It loops through all methods with names that match
1109     * and then executes the first it finds with compatible parameters.</p>
1110     *
1111     * <p>This method supports calls to methods taking primitive parameters
1112     * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
1113     * would match a <code>boolean</code> primitive.</p>
1114     *
1115     * <p> This is a convenient wrapper for
1116     * {@link #invokeStaticMethod(Class objectClass,String methodName,Object [] args,Class[] parameterTypes)}.
1117     * </p>
1118     *
1119     * @param objectClass invoke static method on this class
1120     * @param methodName get method with this name
1121     * @param args use these arguments - treat null as empty array (passing null will
1122     *  result in calling the parameterless method with name {@code methodName}).
1123     * @return The value returned by the invoked method
1124     * @throws NoSuchMethodException if there is no such accessible method
1125     * @throws InvocationTargetException wraps an exception thrown by the
1126     *  method invoked
1127     * @throws IllegalAccessException if the requested method is not accessible
1128     *  via reflection
1129     * @since 1.8.0
1130     */
1131    public static Object invokeStaticMethod(
1132            final Class<?> objectClass,
1133            final String methodName,
1134            Object[] args)
1135            throws
1136            NoSuchMethodException,
1137            IllegalAccessException,
1138            InvocationTargetException {
1139
1140        if (args == null) {
1141            args = EMPTY_OBJECT_ARRAY;
1142        }
1143        final int arguments = args.length;
1144        final Class<?>[] parameterTypes = new Class[arguments];
1145        for (int i = 0; i < arguments; i++) {
1146            parameterTypes[i] = args[i].getClass();
1147        }
1148        return invokeStaticMethod (objectClass, methodName, args, parameterTypes);
1149    }
1150
1151    /**
1152     * <p>Invoke a named static method whose parameter type matches the object type.</p>
1153     *
1154     * <p>The behavior of this method is less deterministic
1155     * than {@link
1156     * #invokeExactStaticMethod(Class objectClass,String methodName,Object [] args,Class[] parameterTypes)}.
1157     * It loops through all methods with names that match
1158     * and then executes the first it finds with compatible parameters.</p>
1159     *
1160     * <p>This method supports calls to methods taking primitive parameters
1161     * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
1162     * would match a <code>boolean</code> primitive.</p>
1163     *
1164     *
1165     * @param objectClass invoke static method on this class
1166     * @param methodName get method with this name
1167     * @param args use these arguments - treat null as empty array (passing null will
1168     *  result in calling the parameterless method with name {@code methodName}).
1169     * @param parameterTypes match these parameters - treat null as empty array
1170     * @return The value returned by the invoked method
1171     * @throws NoSuchMethodException if there is no such accessible method
1172     * @throws InvocationTargetException wraps an exception thrown by the
1173     *  method invoked
1174     * @throws IllegalAccessException if the requested method is not accessible
1175     *  via reflection
1176     * @since 1.8.0
1177     */
1178    public static Object invokeStaticMethod(
1179            final Class<?> objectClass,
1180            final String methodName,
1181            Object[] args,
1182            Class<?>[] parameterTypes)
1183                throws
1184                    NoSuchMethodException,
1185                    IllegalAccessException,
1186                    InvocationTargetException {
1187
1188        if (parameterTypes == null) {
1189            parameterTypes = EMPTY_CLASS_PARAMETERS;
1190        }
1191        if (args == null) {
1192            args = EMPTY_OBJECT_ARRAY;
1193        }
1194
1195        final Method method = getMatchingAccessibleMethod(
1196                objectClass,
1197                methodName,
1198                parameterTypes);
1199        if (method == null) {
1200            throw new NoSuchMethodException("No such accessible method: " +
1201                    methodName + "() on class: " + objectClass.getName());
1202        }
1203        return method.invoke(null, args);
1204    }
1205
1206    /**
1207     * <p>Determine whether a type can be used as a parameter in a method invocation.
1208     * This method handles primitive conversions correctly.</p>
1209     *
1210     * <p>In order words, it will match a <code>Boolean</code> to a <code>boolean</code>,
1211     * a <code>Long</code> to a <code>long</code>,
1212     * a <code>Float</code> to a <code>float</code>,
1213     * a <code>Integer</code> to a <code>int</code>,
1214     * and a <code>Double</code> to a <code>double</code>.
1215     * Now logic widening matches are allowed.
1216     * For example, a <code>Long</code> will not match a <code>int</code>.
1217     *
1218     * @param parameterType the type of parameter accepted by the method
1219     * @param parameterization the type of parameter being tested
1220     * @return true if the assignment is compatible.
1221     */
1222    public static final boolean isAssignmentCompatible(final Class<?> parameterType, final Class<?> parameterization) {
1223        // try plain assignment
1224        if (parameterType.isAssignableFrom(parameterization)) {
1225            return true;
1226        }
1227
1228        if (parameterType.isPrimitive()) {
1229            // this method does *not* do widening - you must specify exactly
1230            // is this the right behavior?
1231            final Class<?> parameterWrapperClazz = getPrimitiveWrapper(parameterType);
1232            if (parameterWrapperClazz != null) {
1233                return parameterWrapperClazz.equals(parameterization);
1234            }
1235        }
1236
1237        return false;
1238    }
1239
1240    /**
1241     * Set whether methods should be cached for greater performance or not,
1242     * default is <code>true</code>.
1243     *
1244     * @param cacheMethods <code>true</code> if methods should be
1245     * cached for greater performance, otherwise <code>false</code>
1246     * @since 1.8.0
1247     */
1248    public static synchronized void setCacheMethods(final boolean cacheMethods) {
1249        CACHE_METHODS = cacheMethods;
1250        if (!CACHE_METHODS) {
1251            clearCache();
1252        }
1253    }
1254
1255    /**
1256     * Try to make the method accessible
1257     * @param method The source arguments
1258     */
1259    private static void setMethodAccessible(final Method method) {
1260        try {
1261            //
1262            // XXX Default access superclass workaround
1263            //
1264            // When a public class has a default access superclass
1265            // with public methods, these methods are accessible.
1266            // Calling them from compiled code works fine.
1267            //
1268            // Unfortunately, using reflection to invoke these methods
1269            // seems to (wrongly) to prevent access even when the method
1270            // modifer is public.
1271            //
1272            // The following workaround solves the problem but will only
1273            // work from sufficiently privileges code.
1274            //
1275            // Better workarounds would be greatfully accepted.
1276            //
1277            if (!method.isAccessible()) {
1278                method.setAccessible(true);
1279            }
1280
1281        } catch (final SecurityException se) {
1282            // log but continue just in case the method.invoke works anyway
1283            final Log log = LogFactory.getLog(MethodUtils.class);
1284            if (!loggedAccessibleWarning) {
1285                boolean vulnerableJVM = false;
1286                try {
1287                    final String specVersion = System.getProperty("java.specification.version");
1288                    if (specVersion.charAt(0) == '1' &&
1289                            (specVersion.charAt(2) == '0' ||
1290                             specVersion.charAt(2) == '1' ||
1291                             specVersion.charAt(2) == '2' ||
1292                             specVersion.charAt(2) == '3')) {
1293
1294                        vulnerableJVM = true;
1295                    }
1296                } catch (final SecurityException e) {
1297                    // don't know - so display warning
1298                    vulnerableJVM = true;
1299                }
1300                if (vulnerableJVM) {
1301                    log.warn(
1302                        "Current Security Manager restricts use of workarounds for reflection bugs "
1303                        + " in pre-1.4 JVMs.");
1304                }
1305                loggedAccessibleWarning = true;
1306            }
1307            log.debug("Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.", se);
1308        }
1309    }
1310
1311    private static Object[] toArray(final Object arg) {
1312        Object[] args = null;
1313        if (arg != null) {
1314            args = new Object[] { arg };
1315        }
1316        return args;
1317    }
1318
1319    /**
1320     * Find a non primitive representation for given primitive class.
1321     *
1322     * @param clazz the class to find a representation for, not null
1323     * @return the original class if it not a primitive. Otherwise the wrapper class. Not null
1324     */
1325    public static Class<?> toNonPrimitiveClass(final Class<?> clazz) {
1326        if (!clazz.isPrimitive()) {
1327            return clazz;
1328        }
1329        final Class<?> primitiveClazz = MethodUtils.getPrimitiveWrapper(clazz);
1330        // the above method returns
1331        if (primitiveClazz != null) {
1332            return primitiveClazz;
1333        }
1334        return clazz;
1335    }
1336
1337    /**
1338     * Deprecated, all methods are static.
1339     *
1340     * @deprecated Will be private in 2.0.
1341     */
1342    @Deprecated
1343    public MethodUtils() {
1344        // empty
1345    }
1346}