You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mb...@apache.org on 2008/03/19 15:54:09 UTC
svn commit: r638851 - in
/commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang:
ConstructorUtils.java MethodUtils.java
Author: mbenson
Date: Wed Mar 19 07:54:06 2008
New Revision: 638851
URL: http://svn.apache.org/viewvc?rev=638851&view=rev
Log:
Langify
Modified:
commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/ConstructorUtils.java
commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/MethodUtils.java
Modified: commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/ConstructorUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/ConstructorUtils.java?rev=638851&r1=638850&r2=638851&view=diff
==============================================================================
--- commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/ConstructorUtils.java (original)
+++ commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/ConstructorUtils.java Wed Mar 19 07:54:06 2008
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.commons.beanutils;
+package org.apache.commons.lang;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -44,17 +44,22 @@
* @author Jan Sorensen
* @author Robert Burrell Donkin
* @author Rodney Waldhoff
- * @version $Revision$ $Date$
+ * @since 2.5
+ * @version $Id$
*/
public class ConstructorUtils {
- // --------------------------------------------------------- Private Members
- /** An empty class array */
- private static final Class[] EMPTY_CLASS_PARAMETERS = new Class[0];
- /** An empty object array */
- private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
-
- // --------------------------------------------------------- Public Methods
+ /**
+ * <p>ConstructorUtils instances should NOT be constructed in standard programming.
+ * Instead, the class should be used as
+ * <code>ConstructorUtils.invokeConstructor(cls, args)</code>.</p>
+ *
+ * <p>This constructor is public to permit tools that require a JavaBean
+ * instance to operate.</p>
+ */
+ public ConstructorUtils() {
+ super();
+ }
/**
* <p>Convenience method returning new instance of <code>klazz</code> using a single argument constructor.
@@ -63,7 +68,7 @@
*
* <p>The signatures should be assignment compatible.</p>
*
- * @param klass the class to be constructed.
+ * @param cls the class to be constructed.
* @param arg the actual argument
* @return new instance of <code>klazz</code>
*
@@ -74,16 +79,10 @@
*
* @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
- public static Object invokeConstructor(Class klass, Object arg)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException,
- InstantiationException {
-
- Object[] args = { arg };
- return invokeConstructor(klass, args);
-
+ public static Object invokeConstructor(Class cls, Object arg)
+ throws NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException, InstantiationException {
+ return invokeConstructor(cls, new Object[] { arg });
}
/**
@@ -93,7 +92,7 @@
*
* <p>The signatures should be assignment compatible.</p>
*
- * @param klass the class to be constructed.
+ * @param cls the class to be constructed.
* @param args actual argument array
* @return new instance of <code>klazz</code>
*
@@ -104,23 +103,17 @@
*
* @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
- public static Object invokeConstructor(Class klass, Object[] args)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException,
- InstantiationException {
-
+ public static Object invokeConstructor(Class cls, Object[] args)
+ throws NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException, InstantiationException {
if (null == args) {
- args = EMPTY_OBJECT_ARRAY;
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
- int arguments = args.length;
- Class parameterTypes[] = new Class[arguments];
- for (int i = 0; i < arguments; i++) {
+ Class parameterTypes[] = new Class[args.length];
+ for (int i = 0; i < args.length; i++) {
parameterTypes[i] = args[i].getClass();
}
- return invokeConstructor(klass, args, parameterTypes);
-
+ return invokeConstructor(cls, args, parameterTypes);
}
/**
@@ -129,7 +122,7 @@
*
* <p>The signatures should be assignment compatible.</p>
*
- * @param klass the class to be constructed.
+ * @param cls the class to be constructed.
* @param args actual argument array
* @param parameterTypes parameter types array
* @return new instance of <code>klazz</code>
@@ -140,33 +133,25 @@
* @throws InstantiationException thrown on the constructor's invocation
* @see Constructor#newInstance
*/
- public static Object invokeConstructor(
- Class klass,
- Object[] args,
- Class[] parameterTypes)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException,
+ public static Object invokeConstructor(Class cls, Object[] args,
+ Class[] parameterTypes) throws NoSuchMethodException,
+ IllegalAccessException, InvocationTargetException,
InstantiationException {
-
if (parameterTypes == null) {
- parameterTypes = EMPTY_CLASS_PARAMETERS;
+ parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
if (args == null) {
- args = EMPTY_OBJECT_ARRAY;
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
-
- Constructor ctor =
- getMatchingAccessibleConstructor(klass, parameterTypes);
+ Constructor ctor = getMatchingAccessibleConstructor(cls, parameterTypes);
if (null == ctor) {
throw new NoSuchMethodException(
- "No such accessible constructor on object: " + klass.getName());
+ "No such accessible constructor on object: "
+ + cls.getName());
}
return ctor.newInstance(args);
}
-
/**
* <p>Convenience method returning new instance of <code>klazz</code> using a single argument constructor.
* The formal parameter type is inferred from the actual values of <code>arg</code>.
@@ -174,7 +159,7 @@
*
* <p>The signatures should match exactly.</p>
*
- * @param klass the class to be constructed.
+ * @param cls the class to be constructed.
* @param arg the actual argument
* @return new instance of <code>klazz</code>
*
@@ -185,16 +170,10 @@
*
* @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
- public static Object invokeExactConstructor(Class klass, Object arg)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException,
- InstantiationException {
-
- Object[] args = { arg };
- return invokeExactConstructor(klass, args);
-
+ public static Object invokeExactConstructor(Class cls, Object arg)
+ throws NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException, InstantiationException {
+ return invokeExactConstructor(cls, new Object[] { arg });
}
/**
@@ -204,7 +183,7 @@
*
* <p>The signatures should match exactly.</p>
*
- * @param klass the class to be constructed.
+ * @param cls the class to be constructed.
* @param args actual argument array
* @return new instance of <code>klazz</code>
*
@@ -215,22 +194,18 @@
*
* @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
- public static Object invokeExactConstructor(Class klass, Object[] args)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException,
- InstantiationException {
+ public static Object invokeExactConstructor(Class cls, Object[] args)
+ throws NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException, InstantiationException {
if (null == args) {
- args = EMPTY_OBJECT_ARRAY;
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class parameterTypes[] = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
- return invokeExactConstructor(klass, args, parameterTypes);
-
+ return invokeExactConstructor(cls, args, parameterTypes);
}
/**
@@ -240,7 +215,7 @@
*
* <p>The signatures should match exactly.</p>
*
- * @param klass the class to be constructed.
+ * @param cls the class to be constructed.
* @param args actual argument array
* @param parameterTypes parameter types array
* @return new instance of <code>klazz</code>
@@ -251,69 +226,53 @@
* @throws InstantiationException thrown on the constructor's invocation
* @see Constructor#newInstance
*/
- public static Object invokeExactConstructor(
- Class klass,
- Object[] args,
- Class[] parameterTypes)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException,
+ public static Object invokeExactConstructor(Class cls, Object[] args,
+ Class[] parameterTypes) throws NoSuchMethodException,
+ IllegalAccessException, InvocationTargetException,
InstantiationException {
-
if (args == null) {
- args = EMPTY_OBJECT_ARRAY;
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
-
if (parameterTypes == null) {
- parameterTypes = EMPTY_CLASS_PARAMETERS;
+ parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
-
- Constructor ctor = getAccessibleConstructor(klass, parameterTypes);
+ Constructor ctor = getAccessibleConstructor(cls, parameterTypes);
if (null == ctor) {
throw new NoSuchMethodException(
- "No such accessible constructor on object: " + klass.getName());
+ "No such accessible constructor on object: "
+ + cls.getName());
}
return ctor.newInstance(args);
-
}
/**
* Returns a constructor with single argument.
- * @param klass the class to be constructed
+ * @param cls the class to be constructed
* @param parameterType The constructor parameter type
* @return null if matching accessible constructor can not be found.
* @see Class#getConstructor
* @see #getAccessibleConstructor(java.lang.reflect.Constructor)
*/
- public static Constructor getAccessibleConstructor(
- Class klass,
- Class parameterType) {
-
- Class[] parameterTypes = { parameterType };
- return getAccessibleConstructor(klass, parameterTypes);
-
+ public static Constructor getAccessibleConstructor(Class cls,
+ Class parameterType) {
+ return getAccessibleConstructor(cls, new Class[] { parameterType });
}
/**
* Returns a constructor given a class and signature.
- * @param klass the class to be constructed
+ * @param cls the class to be constructed
* @param parameterTypes the parameter array
* @return null if matching accessible constructor can not be found
* @see Class#getConstructor
* @see #getAccessibleConstructor(java.lang.reflect.Constructor)
*/
- public static Constructor getAccessibleConstructor(
- Class klass,
- Class[] parameterTypes) {
-
+ public static Constructor getAccessibleConstructor(Class cls,
+ Class[] parameterTypes) {
try {
- return getAccessibleConstructor(
- klass.getConstructor(parameterTypes));
+ return getAccessibleConstructor(cls.getConstructor(parameterTypes));
} catch (NoSuchMethodException e) {
return (null);
}
-
}
/**
@@ -323,29 +282,11 @@
* @see java.lang.SecurityManager
*/
public static Constructor getAccessibleConstructor(Constructor ctor) {
-
- // Make sure we have a method to check
- if (ctor == null) {
- return (null);
- }
-
- // If the requested method is not public we cannot call it
- if (!Modifier.isPublic(ctor.getModifiers())) {
- return (null);
- }
-
- // If the declaring class is public, we are done
- Class clazz = ctor.getDeclaringClass();
- if (Modifier.isPublic(clazz.getModifiers())) {
- return (ctor);
- }
-
- // what else can we do?
- return null;
-
+ return MemberUtils.isAccessible(ctor)
+ && Modifier.isPublic(ctor.getDeclaringClass().getModifiers()) ? ctor
+ : null;
}
- // -------------------------------------------------------- Private Methods
/**
* <p>Find an accessible constructor with compatible parameters.
* Compatible parameters mean that every method parameter is assignable from
@@ -357,80 +298,41 @@
* are assignment compatible with the parameter types.
* The first matching constructor is returned.</p>
*
- * @param clazz find constructor for this class
+ * @param cls find constructor for this class
* @param parameterTypes find method with compatible parameters
* @return a valid Constructor object. If there's no matching constructor, returns <code>null</code>.
*/
- private static Constructor getMatchingAccessibleConstructor(
- Class clazz,
- Class[] parameterTypes) {
- // see if we can find the method directly
+ public static Constructor getMatchingAccessibleConstructor(Class cls,
+ Class[] parameterTypes) {
+ // see if we can find the constructor directly
// most of the time this works and it's much faster
try {
- Constructor ctor = clazz.getConstructor(parameterTypes);
- try {
- //
- // XXX Default access superclass workaround
- //
- // When a public class has a default access superclass
- // with public methods, these methods are accessible.
- // Calling them from compiled code works fine.
- //
- // Unfortunately, using reflection to invoke these methods
- // seems to (wrongly) to prevent access even when the method
- // modifer is public.
- //
- // The following workaround solves the problem but will only
- // work from sufficiently privilages code.
- //
- // Better workarounds would be greatfully accepted.
- //
- ctor.setAccessible(true);
- } catch (SecurityException se) {
- /* SWALLOW, if workaround fails don't fret. */
- }
+ Constructor ctor = cls.getConstructor(parameterTypes);
+ MemberUtils.setAccessibleWorkaround(ctor);
return ctor;
-
} catch (NoSuchMethodException e) { /* SWALLOW */
}
-
- // search through all methods
- int paramSize = parameterTypes.length;
- Constructor[] ctors = clazz.getConstructors();
- for (int i = 0, size = ctors.length; i < size; i++) {
+ Constructor result = null;
+ // search through all constructors
+ Constructor[] ctors = cls.getConstructors();
+ for (int i = 0; i < ctors.length; i++) {
// compare parameters
- Class[] ctorParams = ctors[i].getParameterTypes();
- int ctorParamSize = ctorParams.length;
- if (ctorParamSize == paramSize) {
- boolean match = true;
- for (int n = 0; n < ctorParamSize; n++) {
- if (!MethodUtils
- .isAssignmentCompatible(
- ctorParams[n],
- parameterTypes[n])) {
- match = false;
- break;
- }
- }
-
- if (match) {
- // get accessible version of method
- Constructor ctor = getAccessibleConstructor(ctors[i]);
- if (ctor != null) {
- try {
- ctor.setAccessible(true);
- } catch (SecurityException se) {
- /* Swallow SecurityException
- * TODO: Why?
- */
- }
- return ctor;
+ if (ClassUtils.isAssignable(parameterTypes, ctors[i]
+ .getParameterTypes(), true)) {
+ // get accessible version of method
+ Constructor ctor = getAccessibleConstructor(ctors[i]);
+ if (ctor != null) {
+ MemberUtils.setAccessibleWorkaround(ctor);
+ if (result == null
+ || MemberUtils.compareParameterTypes(ctor
+ .getParameterTypes(), result
+ .getParameterTypes(), parameterTypes) < 0) {
+ result = ctor;
}
}
}
}
-
- return null;
+ return result;
}
}
Modified: commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/MethodUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/MethodUtils.java?rev=638851&r1=638850&r2=638851&view=diff
==============================================================================
--- commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/MethodUtils.java (original)
+++ commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/MethodUtils.java Wed Mar 19 07:54:06 2008
@@ -14,34 +14,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package org.apache.commons.beanutils;
-
+package org.apache.commons.lang;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
import java.util.WeakHashMap;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-
/**
- * <p> Utility reflection methods focussed on methods in general rather than properties in particular. </p>
+ * <p> Utility reflection methods focused on methods, originally from Commons BeanUtils.
+ * Differences from the BeanUtils version may be noted, especially where similar functionality
+ * already existed within Lang.
+ * </p>
*
* <h3>Known Limitations</h3>
* <h4>Accessing Public Methods In A Default Access Superclass</h4>
- * <p>There is an issue when invoking public methods contained in a default access superclass.
+ * <p>There is an issue when invoking public methods contained in a default access superclass on JREs prior to 1.4.
* Reflection locates these methods fine and correctly assigns them as public.
* However, an <code>IllegalAccessException</code> is thrown if the method is invoked.</p>
*
* <p><code>MethodUtils</code> contains a workaround for this situation.
* It will attempt to call <code>setAccessible</code> on this method.
* If this call succeeds, then the method can be invoked as normal.
- * This call will only succeed when the application has sufficient security privilages.
- * If this call fails then a warning will be logged and the method may fail.</p>
+ * This call will only succeed when the application has sufficient security privileges.
+ * If this call fails then the method may fail.</p>
*
* @author Craig R. McClanahan
* @author Ralph Schaer
@@ -50,40 +48,13 @@
* @author Gregor Raýman
* @author Jan Sorensen
* @author Robert Burrell Donkin
+ * @author Niall Pemberton
+ * @author Matt Benson
+ * @since 2.5
+ * @version $Id$
*/
-
public class MethodUtils {
- // --------------------------------------------------------- Private Methods
-
- /**
- * Only log warning about accessibility work around once.
- * <p>
- * Note that this is broken when this class is deployed via a shared
- * classloader in a container, as the warning message will be emitted
- * only once, not once per webapp. However making the warning appear
- * once per webapp means having a map keyed by context classloader
- * which introduces nasty memory-leak problems. As this warning is
- * really optional we can ignore this problem; only one of the webapps
- * will get the warning in its logs but that should be good enough.
- */
- private static boolean loggedAccessibleWarning = false;
-
- /**
- * Indicates whether methods should be cached for improved performance.
- * <p>
- * Note that when this class is deployed via a shared classloader in
- * a container, this will affect all webapps. However making this
- * configurable per webapp would mean having a map keyed by context classloader
- * which may introduce memory-leak problems.
- */
- private static boolean CACHE_METHODS = true;
-
- /** An empty class array */
- private static final Class[] EMPTY_CLASS_PARAMETERS = new Class[0];
- /** An empty object array */
- private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
-
/**
* Stores a cache of MethodDescriptor -> Method in a WeakHashMap.
* <p>
@@ -104,9 +75,29 @@
* class via different classloaders will generate non-equal MethodDescriptor
* objects and hence end up with different entries in the map.
*/
- private static WeakHashMap cache = new WeakHashMap();
-
- // --------------------------------------------------------- Public Methods
+ private static final WeakHashMap/* <MethodDescriptor, Method> */cache = new WeakHashMap();
+
+ /**
+ * Indicates whether methods should be cached for improved performance.
+ * <p>
+ * Note that when this class is deployed via a shared classloader in
+ * a container, this will affect all webapps. However making this
+ * configurable per webapp would mean having a map keyed by context classloader
+ * which may introduce memory-leak problems.
+ */
+ private static boolean cacheMethods = true;
+
+ /**
+ * <p>MethodUtils instances should NOT be constructed in standard programming.
+ * Instead, the class should be used as
+ * <code>MethodUtils.getAccessibleMethod(method)</code>.</p>
+ *
+ * <p>This constructor is public to permit tools that require a JavaBean
+ * instance to operate.</p>
+ */
+ public MethodUtils() {
+ super();
+ }
/**
* Set whether methods should be cached for greater performance or not,
@@ -116,8 +107,8 @@
* cached for greater performance, otherwise <code>false</code>
*/
public static synchronized void setCacheMethods(boolean cacheMethods) {
- CACHE_METHODS = cacheMethods;
- if (!CACHE_METHODS) {
+ MethodUtils.cacheMethods = cacheMethods;
+ if (!MethodUtils.cacheMethods) {
clearCache();
}
}
@@ -131,21 +122,18 @@
cache.clear();
return size;
}
-
+
/**
* <p>Invoke a named method whose parameter type matches the object type.</p>
*
- * <p>The behaviour of this method is less deterministic
- * than <code>invokeExactMethod()</code>.
- * It loops through all methods with names that match
- * and then executes the first it finds with compatable parameters.</p>
+ * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
- * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
+ * via passing in wrapping classes. So, for example, a <code>Boolean</code> object
* would match a <code>boolean</code> primitive.</p>
*
* <p> This is a convenient wrapper for
- * {@link #invokeMethod(Object object,String methodName,Object [] args)}.
+ * {@link #invokeMethod(Object object, String methodName, Object[] args)}.
* </p>
*
* @param object invoke method on this object
@@ -154,40 +142,26 @@
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
- * @throws InvocationTargetException wraps an exception thrown by the
- * method invoked
- * @throws IllegalAccessException if the requested method is not accessible
- * via reflection
+ * @throws InvocationTargetException wraps an exception thrown by the method invoked
+ * @throws IllegalAccessException if the requested method is not accessible via reflection
*/
- public static Object invokeMethod(
- Object object,
- String methodName,
- Object arg)
- throws
- NoSuchMethodException,
- IllegalAccessException,
+ public static Object invokeMethod(Object object, String methodName,
+ Object arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
-
- Object[] args = {arg};
- return invokeMethod(object, methodName, args);
-
+ return invokeMethod(object, methodName, new Object[] { arg });
}
-
/**
* <p>Invoke a named method whose parameter type matches the object type.</p>
*
- * <p>The behaviour of this method is less deterministic
- * than {@link #invokeExactMethod(Object object,String methodName,Object [] args)}.
- * It loops through all methods with names that match
- * and then executes the first it finds with compatable parameters.</p>
+ * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
- * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
+ * via passing in wrapping classes. So, for example, a <code>Boolean</code> object
* would match a <code>boolean</code> primitive.</p>
*
* <p> This is a convenient wrapper for
- * {@link #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
+ * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}.
* </p>
*
* @param object invoke method on this object
@@ -196,47 +170,32 @@
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
- * @throws InvocationTargetException wraps an exception thrown by the
- * method invoked
- * @throws IllegalAccessException if the requested method is not accessible
- * via reflection
+ * @throws InvocationTargetException wraps an exception thrown by the method invoked
+ * @throws IllegalAccessException if the requested method is not accessible via reflection
*/
- public static Object invokeMethod(
- Object object,
- String methodName,
- Object[] args)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
-
+ public static Object invokeMethod(Object object, String methodName,
+ Object[] args) throws NoSuchMethodException,
+ IllegalAccessException, InvocationTargetException {
if (args == null) {
- args = EMPTY_OBJECT_ARRAY;
- }
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
+ }
int arguments = args.length;
Class[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeMethod(object, methodName, args, parameterTypes);
-
}
-
/**
* <p>Invoke a named method whose parameter type matches the object type.</p>
*
- * <p>The behaviour of this method is less deterministic
- * than {@link
- * #invokeExactMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
- * It loops through all methods with names that match
- * and then executes the first it finds with compatable parameters.</p>
+ * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
- * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
+ * via passing in wrapping classes. So, for example, a <code>Boolean</code> object
* would match a <code>boolean</code> primitive.</p>
*
- *
* @param object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
@@ -244,40 +203,29 @@
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
- * @throws InvocationTargetException wraps an exception thrown by the
- * method invoked
- * @throws IllegalAccessException if the requested method is not accessible
- * via reflection
+ * @throws InvocationTargetException wraps an exception thrown by the method invoked
+ * @throws IllegalAccessException if the requested method is not accessible via reflection
*/
- public static Object invokeMethod(
- Object object,
- String methodName,
- Object[] args,
- Class[] parameterTypes)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
-
+ public static Object invokeMethod(Object object, String methodName,
+ Object[] args, Class[] parameterTypes)
+ throws NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException {
if (parameterTypes == null) {
- parameterTypes = EMPTY_CLASS_PARAMETERS;
- }
+ parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
+ }
if (args == null) {
- args = EMPTY_OBJECT_ARRAY;
- }
-
- Method method = getMatchingAccessibleMethod(
- object.getClass(),
- methodName,
- parameterTypes);
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
+ }
+ Method method = getMatchingAccessibleMethod(object.getClass(),
+ methodName, parameterTypes);
if (method == null) {
- throw new NoSuchMethodException("No such accessible method: " +
- methodName + "() on object: " + object.getClass().getName());
+ throw new NoSuchMethodException("No such accessible method: "
+ + methodName + "() on object: "
+ + object.getClass().getName());
}
return method.invoke(object, args);
}
-
/**
* <p>Invoke a method whose parameter type matches exactly the object
* type.</p>
@@ -297,21 +245,12 @@
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
- public static Object invokeExactMethod(
- Object object,
- String methodName,
- Object arg)
- throws
- NoSuchMethodException,
- IllegalAccessException,
+ public static Object invokeExactMethod(Object object, String methodName,
+ Object arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
-
- Object[] args = {arg};
- return invokeExactMethod(object, methodName, args);
-
+ return invokeExactMethod(object, methodName, new Object[] { arg });
}
-
/**
* <p>Invoke a method whose parameter types match exactly the object
* types.</p>
@@ -330,27 +269,20 @@
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
- public static Object invokeExactMethod(
- Object object,
- String methodName,
- Object[] args)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
+ public static Object invokeExactMethod(Object object, String methodName,
+ Object[] args) throws NoSuchMethodException,
+ IllegalAccessException, InvocationTargetException {
if (args == null) {
- args = EMPTY_OBJECT_ARRAY;
- }
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
+ }
int arguments = args.length;
Class[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeExactMethod(object, methodName, args, parameterTypes);
-
}
-
/**
* <p>Invoke a method whose parameter types match exactly the parameter
* types given.</p>
@@ -370,34 +302,24 @@
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
- public static Object invokeExactMethod(
- Object object,
- String methodName,
- Object[] args,
- Class[] parameterTypes)
- throws
- NoSuchMethodException,
- IllegalAccessException,
+ public static Object invokeExactMethod(Object object, String methodName,
+ Object[] args, Class[] parameterTypes)
+ throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
-
if (args == null) {
- args = EMPTY_OBJECT_ARRAY;
- }
-
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
+ }
if (parameterTypes == null) {
- parameterTypes = EMPTY_CLASS_PARAMETERS;
+ parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
-
- Method method = getAccessibleMethod(
- object.getClass(),
- methodName,
+ Method method = getAccessibleMethod(object.getClass(), methodName,
parameterTypes);
if (method == null) {
- throw new NoSuchMethodException("No such accessible method: " +
- methodName + "() on object: " + object.getClass().getName());
+ throw new NoSuchMethodException("No such accessible method: "
+ + methodName + "() on object: "
+ + object.getClass().getName());
}
return method.invoke(object, args);
-
}
/**
@@ -407,7 +329,7 @@
* <p>This uses reflection to invoke the method obtained from a call to
* {@link #getAccessibleMethod(Class, String, Class[])}.</p>
*
- * @param objectClass invoke static method on this class
+ * @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
@@ -419,43 +341,28 @@
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
- public static Object invokeExactStaticMethod(
- Class objectClass,
- String methodName,
- Object[] args,
- Class[] parameterTypes)
- throws
- NoSuchMethodException,
- IllegalAccessException,
+ public static Object invokeExactStaticMethod(Class cls, String methodName,
+ Object[] args, Class[] parameterTypes)
+ throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
-
if (args == null) {
- args = EMPTY_OBJECT_ARRAY;
- }
-
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
+ }
if (parameterTypes == null) {
- parameterTypes = EMPTY_CLASS_PARAMETERS;
+ parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
-
- Method method = getAccessibleMethod(
- objectClass,
- methodName,
- parameterTypes);
+ Method method = getAccessibleMethod(cls, methodName, parameterTypes);
if (method == null) {
- throw new NoSuchMethodException("No such accessible method: " +
- methodName + "() on class: " + objectClass.getName());
+ throw new NoSuchMethodException("No such accessible method: "
+ + methodName + "() on class: " + cls.getName());
}
return method.invoke(null, args);
-
}
/**
* <p>Invoke a named static method whose parameter type matches the object type.</p>
*
- * <p>The behaviour of this method is less deterministic
- * than {@link #invokeExactMethod(Object, String, Object[], Class[])}.
- * It loops through all methods with names that match
- * and then executes the first it finds with compatable parameters.</p>
+ * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> class
@@ -465,7 +372,7 @@
* {@link #invokeStaticMethod(Class objectClass,String methodName,Object [] args)}.
* </p>
*
- * @param objectClass invoke static method on this class
+ * @param cls invoke static method on this class
* @param methodName get method with this name
* @param arg use this argument
* @return The value returned by the invoked method
@@ -476,28 +383,16 @@
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
- public static Object invokeStaticMethod(
- Class objectClass,
- String methodName,
- Object arg)
- throws
- NoSuchMethodException,
- IllegalAccessException,
+ public static Object invokeStaticMethod(Class cls, String methodName,
+ Object arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
-
- Object[] args = {arg};
- return invokeStaticMethod (objectClass, methodName, args);
-
+ return invokeStaticMethod(cls, methodName, new Object[] { arg });
}
-
/**
* <p>Invoke a named static method whose parameter type matches the object type.</p>
*
- * <p>The behaviour of this method is less deterministic
- * than {@link #invokeExactMethod(Object object,String methodName,Object [] args)}.
- * It loops through all methods with names that match
- * and then executes the first it finds with compatable parameters.</p>
+ * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> class
@@ -507,7 +402,7 @@
* {@link #invokeStaticMethod(Class objectClass,String methodName,Object [] args,Class[] parameterTypes)}.
* </p>
*
- * @param objectClass invoke static method on this class
+ * @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
@@ -518,43 +413,31 @@
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
- public static Object invokeStaticMethod(
- Class objectClass,
- String methodName,
- Object[] args)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
-
+ public static Object invokeStaticMethod(Class cls, String methodName,
+ Object[] args) throws NoSuchMethodException,
+ IllegalAccessException, InvocationTargetException {
if (args == null) {
- args = EMPTY_OBJECT_ARRAY;
- }
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
+ }
int arguments = args.length;
Class[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
- return invokeStaticMethod (objectClass, methodName, args, parameterTypes);
-
+ return invokeStaticMethod(cls, methodName, args, parameterTypes);
}
-
/**
* <p>Invoke a named static method whose parameter type matches the object type.</p>
*
- * <p>The behaviour of this method is less deterministic
- * than {@link
- * #invokeExactStaticMethod(Class objectClass,String methodName,Object [] args,Class[] parameterTypes)}.
- * It loops through all methods with names that match
- * and then executes the first it finds with compatable parameters.</p>
+ * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> class
* would match a <code>boolean</code> primitive.</p>
*
*
- * @param objectClass invoke static method on this class
+ * @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
@@ -566,35 +449,25 @@
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
- public static Object invokeStaticMethod(
- Class objectClass,
- String methodName,
- Object[] args,
- Class[] parameterTypes)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
-
+ public static Object invokeStaticMethod(Class cls, String methodName,
+ Object[] args, Class[] parameterTypes)
+ throws NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException {
if (parameterTypes == null) {
- parameterTypes = EMPTY_CLASS_PARAMETERS;
- }
+ parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
+ }
if (args == null) {
- args = EMPTY_OBJECT_ARRAY;
- }
-
- Method method = getMatchingAccessibleMethod(
- objectClass,
- methodName,
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
+ }
+ Method method = getMatchingAccessibleMethod(cls, methodName,
parameterTypes);
if (method == null) {
- throw new NoSuchMethodException("No such accessible method: " +
- methodName + "() on class: " + objectClass.getName());
+ throw new NoSuchMethodException("No such accessible method: "
+ + methodName + "() on class: " + cls.getName());
}
return method.invoke(null, args);
}
-
/**
* <p>Invoke a static method whose parameter type matches exactly the object
* type.</p>
@@ -603,7 +476,7 @@
* {@link #invokeExactStaticMethod(Class objectClass,String methodName,Object [] args)}.
* </p>
*
- * @param objectClass invoke static method on this class
+ * @param cls invoke static method on this class
* @param methodName get method with this name
* @param arg use this argument
* @return The value returned by the invoked method
@@ -614,21 +487,12 @@
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
- public static Object invokeExactStaticMethod(
- Class objectClass,
- String methodName,
- Object arg)
- throws
- NoSuchMethodException,
- IllegalAccessException,
+ public static Object invokeExactStaticMethod(Class cls, String methodName,
+ Object arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
-
- Object[] args = {arg};
- return invokeExactStaticMethod (objectClass, methodName, args);
-
+ return invokeExactStaticMethod(cls, methodName, new Object[] { arg });
}
-
/**
* <p>Invoke a static method whose parameter types match exactly the object
* types.</p>
@@ -636,7 +500,7 @@
* <p> This uses reflection to invoke the method obtained from a call to
* {@link #getAccessibleMethod(Class, String, Class[])}.</p>
*
- * @param objectClass invoke static method on this class
+ * @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
@@ -647,27 +511,20 @@
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
- public static Object invokeExactStaticMethod(
- Class objectClass,
- String methodName,
- Object[] args)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
+ public static Object invokeExactStaticMethod(Class cls, String methodName,
+ Object[] args) throws NoSuchMethodException,
+ IllegalAccessException, InvocationTargetException {
if (args == null) {
- args = EMPTY_OBJECT_ARRAY;
- }
+ args = ArrayUtils.EMPTY_OBJECT_ARRAY;
+ }
int arguments = args.length;
Class[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
- return invokeExactStaticMethod(objectClass, methodName, args, parameterTypes);
-
+ return invokeExactStaticMethod(cls, methodName, args, parameterTypes);
}
-
/**
* <p>Return an accessible method (that is, one that can be invoked via
* reflection) with given name and a single parameter. If no such method
@@ -675,22 +532,17 @@
* Basically, a convenience wrapper that constructs a <code>Class</code>
* array for you.</p>
*
- * @param clazz get method from this class
+ * @param cls get method from this class
* @param methodName get method with this name
* @param parameterType taking this type of parameter
* @return The accessible method
*/
- public static Method getAccessibleMethod(
- Class clazz,
- String methodName,
+ public static Method getAccessibleMethod(Class cls, String methodName,
Class parameterType) {
-
- Class[] parameterTypes = {parameterType};
- return getAccessibleMethod(clazz, methodName, parameterTypes);
-
+ return getAccessibleMethod(cls, methodName,
+ new Class[] { parameterType });
}
-
/**
* <p>Return an accessible method (that is, one that can be invoked via
* reflection) with given name and parameters. If no such method
@@ -698,35 +550,30 @@
* This is just a convenient wrapper for
* {@link #getAccessibleMethod(Method method)}.</p>
*
- * @param clazz get method from this class
+ * @param cls get method from this class
* @param methodName get method with this name
* @param parameterTypes with these parameters types
* @return The accessible method
*/
- public static Method getAccessibleMethod(
- Class clazz,
- String methodName,
+ public static Method getAccessibleMethod(Class cls, String methodName,
Class[] parameterTypes) {
-
try {
- MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, true);
+ MethodDescriptor md = new MethodDescriptor(cls, methodName,
+ parameterTypes, true);
// Check the cache first
Method method = getCachedMethod(md);
if (method != null) {
return method;
}
-
- method = getAccessibleMethod
- (clazz.getMethod(methodName, parameterTypes));
+ method = getAccessibleMethod(cls.getMethod(methodName,
+ parameterTypes));
cacheMethod(md, method);
return method;
} catch (NoSuchMethodException e) {
return (null);
}
-
}
-
/**
* <p>Return an accessible method (that is, one that can be invoked via
* reflection) that implements the specified Method. If no such method
@@ -736,68 +583,50 @@
* @return The accessible method
*/
public static Method getAccessibleMethod(Method method) {
-
- // Make sure we have a method to check
- if (method == null) {
- return (null);
- }
-
- // If the requested method is not public we cannot call it
- if (!Modifier.isPublic(method.getModifiers())) {
- return (null);
+ if (!MemberUtils.isAccessible(method)) {
+ return null;
}
-
// If the declaring class is public, we are done
- Class clazz = method.getDeclaringClass();
- if (Modifier.isPublic(clazz.getModifiers())) {
- return (method);
+ Class cls = method.getDeclaringClass();
+ if (Modifier.isPublic(cls.getModifiers())) {
+ return method;
}
-
- String methodName = method.getName();
+ String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes();
// Check the implemented interfaces and subinterfaces
- method =
- getAccessibleMethodFromInterfaceNest(clazz,
- methodName,
- parameterTypes);
+ method = getAccessibleMethodFromInterfaceNest(cls, methodName,
+ parameterTypes);
// Check the superclass chain
if (method == null) {
- method = getAccessibleMethodFromSuperclass(clazz,
- methodName,
- parameterTypes);
+ method = getAccessibleMethodFromSuperclass(cls, methodName,
+ parameterTypes);
}
-
- return (method);
-
+ return method;
}
-
- // -------------------------------------------------------- Private Methods
-
/**
* <p>Return an accessible method (that is, one that can be invoked via
* reflection) by scanning through the superclasses. If no such method
* can be found, return <code>null</code>.</p>
*
- * @param clazz Class to be checked
+ * @param cls Class to be checked
* @param methodName Method name of the method we wish to call
* @param parameterTypes The parameter type signatures
*/
- private static Method getAccessibleMethodFromSuperclass
- (Class clazz, String methodName, Class[] parameterTypes) {
-
- Class parentClazz = clazz.getSuperclass();
- while (parentClazz != null) {
- if (Modifier.isPublic(parentClazz.getModifiers())) {
+ private static Method getAccessibleMethodFromSuperclass(Class cls,
+ String methodName, Class[] parameterTypes) {
+ Class parentClass = cls.getSuperclass();
+ while (parentClass != null) {
+ if (Modifier.isPublic(parentClass.getModifiers())) {
try {
- return parentClazz.getMethod(methodName, parameterTypes);
+ return parentClass.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
return null;
}
}
- parentClazz = parentClazz.getSuperclass();
+ parentClass = parentClass.getSuperclass();
}
return null;
}
@@ -812,61 +641,46 @@
* It is because there doesn't seem any reason why other classes should
* call this rather than the higher level methods.</p>
*
- * @param clazz Parent class for the interfaces to be checked
+ * @param cls Parent class for the interfaces to be checked
* @param methodName Method name of the method we wish to call
* @param parameterTypes The parameter type signatures
*/
- private static Method getAccessibleMethodFromInterfaceNest
- (Class clazz, String methodName, Class[] parameterTypes) {
-
+ private static Method getAccessibleMethodFromInterfaceNest(Class cls,
+ String methodName, Class[] parameterTypes) {
Method method = null;
// Search up the superclass chain
- for (; clazz != null; clazz = clazz.getSuperclass()) {
+ for (; cls != null; cls = cls.getSuperclass()) {
// Check the implemented interfaces of the parent class
- Class[] interfaces = clazz.getInterfaces();
+ Class[] interfaces = cls.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
-
// Is this interface public?
if (!Modifier.isPublic(interfaces[i].getModifiers())) {
continue;
}
-
// Does the method exist on this interface?
try {
method = interfaces[i].getDeclaredMethod(methodName,
parameterTypes);
} catch (NoSuchMethodException e) {
- /* Swallow, if no method is found after the loop then this
+ /*
+ * Swallow, if no method is found after the loop then this
* method returns null.
*/
}
if (method != null) {
break;
}
-
// Recursively check our parent interfaces
- method =
- getAccessibleMethodFromInterfaceNest(interfaces[i],
- methodName,
- parameterTypes);
+ method = getAccessibleMethodFromInterfaceNest(interfaces[i],
+ methodName, parameterTypes);
if (method != null) {
break;
}
-
}
-
- }
-
- // If we found a method return it
- if (method != null) {
- return (method);
}
-
- // We did not find anything
- return (null);
-
+ return method;
}
/**
@@ -876,368 +690,75 @@
* In other words, it finds a method with the given name
* that will take the parameters given.<p>
*
- * <p>This method is slightly undeterminstic since it loops
- * through methods names and return the first matching method.</p>
- *
* <p>This method is used by
* {@link
- * #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
+ * #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}.
*
* <p>This method can match primitive parameter by passing in wrapper classes.
* For example, a <code>Boolean</code> will match a primitive <code>boolean</code>
* parameter.
*
- * @param clazz find method in this class
+ * @param cls find method in this class
* @param methodName find method with this name
- * @param parameterTypes find method with compatible parameters
+ * @param parameterTypes find method with most compatible parameters
* @return The accessible method
*/
- public static Method getMatchingAccessibleMethod(
- Class clazz,
- String methodName,
- Class[] parameterTypes) {
- // trace logging
- Log log = LogFactory.getLog(MethodUtils.class);
- if (log.isTraceEnabled()) {
- log.trace("Matching name=" + methodName + " on " + clazz);
+ public static Method getMatchingAccessibleMethod(Class cls,
+ String methodName, Class[] parameterTypes) {
+ MethodDescriptor md = new MethodDescriptor(cls, methodName,
+ parameterTypes, false);
+ // Check the cache first
+ Method method = getCachedMethod(md);
+ if (method != null) {
+ return method;
}
- MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, false);
-
// see if we can find the method directly
// most of the time this works and it's much faster
try {
- // Check the cache first
- Method method = getCachedMethod(md);
- if (method != null) {
- return method;
- }
-
- method = clazz.getMethod(methodName, parameterTypes);
- if (log.isTraceEnabled()) {
- log.trace("Found straight match: " + method);
- log.trace("isPublic:" + Modifier.isPublic(method.getModifiers()));
- }
-
- try {
- //
- // XXX Default access superclass workaround
- //
- // When a public class has a default access superclass
- // with public methods, these methods are accessible.
- // Calling them from compiled code works fine.
- //
- // Unfortunately, using reflection to invoke these methods
- // seems to (wrongly) to prevent access even when the method
- // modifer is public.
- //
- // The following workaround solves the problem but will only
- // work from sufficiently privilages code.
- //
- // Better workarounds would be greatfully accepted.
- //
- method.setAccessible(true);
-
- } catch (SecurityException se) {
- // log but continue just in case the method.invoke works anyway
- if (!loggedAccessibleWarning) {
- boolean vulnerableJVM = false;
- try {
- String specVersion = System.getProperty("java.specification.version");
- if (specVersion.charAt(0) == '1' &&
- (specVersion.charAt(2) == '0' ||
- specVersion.charAt(2) == '1' ||
- specVersion.charAt(2) == '2' ||
- specVersion.charAt(2) == '3')) {
-
- vulnerableJVM = true;
- }
- } catch (SecurityException e) {
- // don't know - so display warning
- vulnerableJVM = true;
- }
- if (vulnerableJVM) {
- log.warn(
- "Current Security Manager restricts use of workarounds for reflection bugs "
- + " in pre-1.4 JVMs.");
- }
- loggedAccessibleWarning = true;
- }
- log.debug(
- "Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.",
- se);
- }
+ method = cls.getMethod(methodName, parameterTypes);
+ MemberUtils.setAccessibleWorkaround(method);
cacheMethod(md, method);
return method;
-
- } catch (NoSuchMethodException e) { /* SWALLOW */ }
-
- // search through all methods
- int paramSize = parameterTypes.length;
+ } catch (NoSuchMethodException e) { /* SWALLOW */
+ }
+ // search through all methods
Method bestMatch = null;
- Method[] methods = clazz.getMethods();
- float bestMatchCost = Float.MAX_VALUE;
- float myCost = Float.MAX_VALUE;
- for (int i = 0, size = methods.length; i < size ; i++) {
+ Method[] methods = cls.getMethods();
+ for (int i = 0, size = methods.length; i < size; i++) {
if (methods[i].getName().equals(methodName)) {
- // log some trace information
- if (log.isTraceEnabled()) {
- log.trace("Found matching name:");
- log.trace(methods[i]);
- }
-
// compare parameters
- Class[] methodsParams = methods[i].getParameterTypes();
- int methodParamSize = methodsParams.length;
- if (methodParamSize == paramSize) {
- boolean match = true;
- for (int n = 0 ; n < methodParamSize; n++) {
- if (log.isTraceEnabled()) {
- log.trace("Param=" + parameterTypes[n].getName());
- log.trace("Method=" + methodsParams[n].getName());
- }
- if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) {
- if (log.isTraceEnabled()) {
- log.trace(methodsParams[n] + " is not assignable from "
- + parameterTypes[n]);
- }
- match = false;
- break;
- }
- }
-
- if (match) {
- // get accessible version of method
- Method method = getAccessibleMethod(methods[i]);
- if (method != null) {
- if (log.isTraceEnabled()) {
- log.trace(method + " accessible version of "
- + methods[i]);
- }
- try {
- //
- // XXX Default access superclass workaround
- // (See above for more details.)
- //
- method.setAccessible(true);
-
- } catch (SecurityException se) {
- // log but continue just in case the method.invoke works anyway
- if (!loggedAccessibleWarning) {
- log.warn(
- "Cannot use JVM pre-1.4 access bug workaround due to restrictive security manager.");
- loggedAccessibleWarning = true;
- }
- log.debug(
- "Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.",
- se);
- }
- myCost = getTotalTransformationCost(parameterTypes,method.getParameterTypes());
- if ( myCost < bestMatchCost ) {
- bestMatch = method;
- bestMatchCost = myCost;
- }
+ if (ClassUtils.isAssignable(parameterTypes, methods[i]
+ .getParameterTypes(), true)) {
+ // get accessible version of method
+ Method accessibleMethod = getAccessibleMethod(methods[i]);
+ if (accessibleMethod != null) {
+ if (bestMatch == null
+ || MemberUtils.compareParameterTypes(
+ accessibleMethod.getParameterTypes(),
+ bestMatch.getParameterTypes(),
+ parameterTypes) < 0) {
+ bestMatch = accessibleMethod;
}
-
- log.trace("Couldn't find accessible method.");
}
}
}
}
- if ( bestMatch != null ){
- cacheMethod(md, bestMatch);
- } else {
- // didn't find a match
- log.trace("No match found.");
- }
-
- return bestMatch;
- }
-
- /**
- * Returns the sum of the object transformation cost for each class in the source
- * argument list.
- * @param srcArgs The source arguments
- * @param destArgs The destination arguments
- * @return The total transformation cost
- */
- private static float getTotalTransformationCost(Class[] srcArgs, Class[] destArgs) {
-
- float totalCost = 0.0f;
- for (int i = 0; i < srcArgs.length; i++) {
- Class srcClass, destClass;
- srcClass = srcArgs[i];
- destClass = destArgs[i];
- totalCost += getObjectTransformationCost(srcClass, destClass);
- }
-
- return totalCost;
- }
-
- /**
- * Gets the number of steps required needed to turn the source class into the
- * destination class. This represents the number of steps in the object hierarchy
- * graph.
- * @param srcClass The source class
- * @param destClass The destination class
- * @return The cost of transforming an object
- */
- private static float getObjectTransformationCost(Class srcClass, Class destClass) {
- float cost = 0.0f;
- while (destClass != null && !destClass.equals(srcClass)) {
- if (destClass.isInterface() && isAssignmentCompatible(destClass,srcClass)) {
- // slight penalty for interface match.
- // we still want an exact match to override an interface match, but
- // an interface match should override anything where we have to get a
- // superclass.
- cost += 0.25f;
- break;
- }
- cost++;
- destClass = destClass.getSuperclass();
- }
-
- /*
- * If the destination class is null, we've travelled all the way up to
- * an Object match. We'll penalize this by adding 1.5 to the cost.
- */
- if (destClass == null) {
- cost += 1.5f;
- }
-
- return cost;
- }
-
-
- /**
- * <p>Determine whether a type can be used as a parameter in a method invocation.
- * This method handles primitive conversions correctly.</p>
- *
- * <p>In order words, it will match a <code>Boolean</code> to a <code>boolean</code>,
- * a <code>Long</code> to a <code>long</code>,
- * a <code>Float</code> to a <code>float</code>,
- * a <code>Integer</code> to a <code>int</code>,
- * and a <code>Double</code> to a <code>double</code>.
- * Now logic widening matches are allowed.
- * For example, a <code>Long</code> will not match a <code>int</code>.
- *
- * @param parameterType the type of parameter accepted by the method
- * @param parameterization the type of parameter being tested
- *
- * @return true if the assignement is compatible.
- */
- public static final boolean isAssignmentCompatible(Class parameterType, Class parameterization) {
- // try plain assignment
- if (parameterType.isAssignableFrom(parameterization)) {
- return true;
- }
-
- if (parameterType.isPrimitive()) {
- // this method does *not* do widening - you must specify exactly
- // is this the right behaviour?
- Class parameterWrapperClazz = getPrimitiveWrapper(parameterType);
- if (parameterWrapperClazz != null) {
- return parameterWrapperClazz.equals(parameterization);
- }
- }
-
- return false;
- }
-
- /**
- * Gets the wrapper object class for the given primitive type class.
- * For example, passing <code>boolean.class</code> returns <code>Boolean.class</code>
- * @param primitiveType the primitive type class for which a match is to be found
- * @return the wrapper type associated with the given primitive
- * or null if no match is found
- */
- public static Class getPrimitiveWrapper(Class primitiveType) {
- // does anyone know a better strategy than comparing names?
- if (boolean.class.equals(primitiveType)) {
- return Boolean.class;
- } else if (float.class.equals(primitiveType)) {
- return Float.class;
- } else if (long.class.equals(primitiveType)) {
- return Long.class;
- } else if (int.class.equals(primitiveType)) {
- return Integer.class;
- } else if (short.class.equals(primitiveType)) {
- return Short.class;
- } else if (byte.class.equals(primitiveType)) {
- return Byte.class;
- } else if (double.class.equals(primitiveType)) {
- return Double.class;
- } else if (char.class.equals(primitiveType)) {
- return Character.class;
- } else {
-
- return null;
+ if (bestMatch != null) {
+ MemberUtils.setAccessibleWorkaround(bestMatch);
+ cacheMethod(md, bestMatch);
}
+ return bestMatch;
}
/**
- * Gets the class for the primitive type corresponding to the primitive wrapper class given.
- * For example, an instance of <code>Boolean.class</code> returns a <code>boolean.class</code>.
- * @param wrapperType the
- * @return the primitive type class corresponding to the given wrapper class,
- * null if no match is found
- */
- public static Class getPrimitiveType(Class wrapperType) {
- // does anyone know a better strategy than comparing names?
- if (Boolean.class.equals(wrapperType)) {
- return boolean.class;
- } else if (Float.class.equals(wrapperType)) {
- return float.class;
- } else if (Long.class.equals(wrapperType)) {
- return long.class;
- } else if (Integer.class.equals(wrapperType)) {
- return int.class;
- } else if (Short.class.equals(wrapperType)) {
- return short.class;
- } else if (Byte.class.equals(wrapperType)) {
- return byte.class;
- } else if (Double.class.equals(wrapperType)) {
- return double.class;
- } else if (Character.class.equals(wrapperType)) {
- return char.class;
- } else {
- Log log = LogFactory.getLog(MethodUtils.class);
- if (log.isDebugEnabled()) {
- log.debug("Not a known primitive wrapper class: " + wrapperType);
- }
- return null;
- }
- }
-
- /**
- * Find a non primitive representation for given primitive class.
- *
- * @param clazz the class to find a representation for, not null
- * @return the original class if it not a primitive. Otherwise the wrapper class. Not null
- */
- public static Class toNonPrimitiveClass(Class clazz) {
- if (clazz.isPrimitive()) {
- Class primitiveClazz = MethodUtils.getPrimitiveWrapper(clazz);
- // the above method returns
- if (primitiveClazz != null) {
- return primitiveClazz;
- } else {
- return clazz;
- }
- } else {
- return clazz;
- }
- }
-
-
- /**
* Return the method from the cache, if present.
*
* @param md The method descriptor
* @return The cached method
*/
private static Method getCachedMethod(MethodDescriptor md) {
- if (CACHE_METHODS) {
- return (Method)cache.get(md);
+ if (cacheMethods) {
+ return (Method) cache.get(md);
}
return null;
}
@@ -1249,7 +770,7 @@
* @param method The method to cache
*/
private static void cacheMethod(MethodDescriptor md, Method method) {
- if (CACHE_METHODS) {
+ if (cacheMethods) {
if (method != null) {
cache.put(md, method);
}
@@ -1274,7 +795,8 @@
* @param paramTypes the array of classes representing the paramater types
* @param exact whether the match has to be exact.
*/
- public MethodDescriptor(Class cls, String methodName, Class[] paramTypes, boolean exact) {
+ public MethodDescriptor(Class cls, String methodName,
+ Class[] paramTypes, boolean exact) {
if (cls == null) {
throw new IllegalArgumentException("Class cannot be null");
}
@@ -1282,16 +804,16 @@
throw new IllegalArgumentException("Method Name cannot be null");
}
if (paramTypes == null) {
- paramTypes = EMPTY_CLASS_PARAMETERS;
+ paramTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
-
this.cls = cls;
this.methodName = methodName;
this.paramTypes = paramTypes;
- this.exact= exact;
-
+ this.exact = exact;
+ // is this adequate? :/
this.hashCode = methodName.length();
}
+
/**
* Checks for equality.
* @param obj object to be tested for equality
@@ -1301,15 +823,13 @@
if (!(obj instanceof MethodDescriptor)) {
return false;
}
- MethodDescriptor md = (MethodDescriptor)obj;
+ MethodDescriptor md = (MethodDescriptor) obj;
- return (
- exact == md.exact &&
- methodName.equals(md.methodName) &&
- cls.equals(md.cls) &&
- java.util.Arrays.equals(paramTypes, md.paramTypes)
- );
+ return exact == md.exact && methodName.equals(md.methodName)
+ && cls.equals(md.cls)
+ && Arrays.equals(paramTypes, md.paramTypes);
}
+
/**
* Returns the string length of method name. I.e. if the
* hashcodes are different, the objects are different. If the