You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by rd...@apache.org on 2002/12/10 20:06:49 UTC
cvs commit: jakarta-commons/lang/src/test/org/apache/commons/lang/reflect MethodUtilsTestCase.java
rdonkin 2002/12/10 11:06:49
Modified: lang/src/java/org/apache/commons/lang/reflect
MethodUtils.java
lang/src/test/org/apache/commons/lang/reflect
MethodUtilsTestCase.java
Log:
Consolidated methods.
Revision Changes Path
1.9 +111 -152 jakarta-commons/lang/src/java/org/apache/commons/lang/reflect/MethodUtils.java
Index: MethodUtils.java
===================================================================
RCS file: /home/cvs/jakarta-commons/lang/src/java/org/apache/commons/lang/reflect/MethodUtils.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- MethodUtils.java 21 Nov 2002 19:38:51 -0000 1.8
+++ MethodUtils.java 10 Dec 2002 19:06:49 -0000 1.9
@@ -66,6 +66,7 @@
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
+
/**
* <code>MethodUtils</code> contains utility methods for working for
* methods by reflection.
@@ -126,6 +127,21 @@
* @throws IllegalArgumentException if the class or method name is null
* @throws ReflectionException if an error occurs during reflection
*/
+ public static Method getMethod(Class cls, String methodName, Class paramType) {
+ Class[] paramTypes = {paramType};
+ return getMethod(cls, methodName, paramTypes);
+ }
+
+ /**
+ * Gets a Method by name. The method must be public.
+ * Superclasses will be considered.
+ *
+ * @param cls the class to reflect, must not be null
+ * @param methodName the field name to obtain
+ * @return the Method object
+ * @throws IllegalArgumentException if the class or method name is null
+ * @throws ReflectionException if an error occurs during reflection
+ */
public static Method getMethod(Class cls, String methodName, Class[] paramTypes) {
return getMethod(cls, methodName, paramTypes, false);
}
@@ -173,7 +189,24 @@
}
throw new NoSuchMethodException("The method '" + methodName + "' could not be found");
} else {
- return cls.getMethod(methodName, paramTypes);
+ // apply workarounds
+ Method method = null;
+ try {
+
+ method = cls.getMethod(methodName, paramTypes);
+
+ } catch(NoSuchMethodException e) {
+ // swallow
+ }
+
+ if (method == null) {
+ // use the same as beanutils for the moment
+ Method[] compatibles = getCompatibleMethods(cls, methodName, paramTypes);
+ if (compatibles.length > 0) {
+ method = compatibles[0];
+ }
+ }
+ return getMethod(method);
}
} catch (ReflectionException ex) {
@@ -186,6 +219,50 @@
ex, "getting method", cls.getName(), null, methodName), ex);
}
}
+
+ /**
+ * <p>Return an accessible method (that is, one that can be invoked via
+ * reflection) that implements the specified Method. If no such method
+ * can be found, return <code>null</code>.</p>
+ *
+ * @param method The method that we wish to call
+ */
+ public static Method getMethod(Method method) {
+
+ Method accessibleMethod = getAccessibleMethod(method);
+ if (accessibleMethod == null) {
+ 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.
+ //
+ if (ReflectionUtils.isPublicScope(method)) {
+ method.setAccessible(true);
+ accessibleMethod = method;
+ }
+
+ } catch (SecurityException se) {
+ // log but continue just in case the method.invoke works anyway
+ log(
+ "Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.",
+ se);
+ }
+ }
+ return (accessibleMethod);
+
+ }
// -------------------------------------------------------------------------
@@ -303,7 +380,7 @@
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
- Method method = getMatchingAccessibleMethod(
+ Method method = getMethod(
object.getClass(),
methodName,
parameterTypes);
@@ -330,62 +407,11 @@
}
}
- /**
- * <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
- * can be found, return <code>null</code>.
- * Basically, a convenience wrapper that constructs a <code>Class</code>
- * array for you.</p>
- *
- * @param clazz get method from this class
- * @param methodName get method with this name
- * @param parameterType taking this type of parameter
- */
- public static Method getAccessibleMethod(
- Class clazz,
- String methodName,
- Class parameterType) {
-
- Class[] parameterTypes = {parameterType};
- return getAccessibleMethod(clazz, methodName, parameterTypes);
-
- }
-
-
- /**
- * <p>Return an accessible method (that is, one that can be invoked via
- * reflection) with given name and parameters. If no such method
- * can be found, return <code>null</code>.
- * This is just a convenient wrapper for
- * {@link #getAccessibleMethod(Method method)}.</p>
- *
- * @param clazz get method from this class
- * @param methodName get method with this name
- * @param parameterTypes with these parameters types
- */
- public static Method getAccessibleMethod(
- Class clazz,
- String methodName,
- Class[] parameterTypes) {
-
- try {
- return getAccessibleMethod
- (clazz.getMethod(methodName, parameterTypes));
- } catch (NoSuchMethodException e) {
- return (null);
- }
- }
+ // -------------------------------------------------------- Private Methods
- /**
- * <p>Return an accessible method (that is, one that can be invoked via
- * reflection) that implements the specified Method. If no such method
- * can be found, return <code>null</code>.</p>
- *
- * @param method The method that we wish to call
- */
- public static Method getAccessibleMethod(Method method) {
+ private static Method getAccessibleMethod(Method method) {
// Make sure we have a method to check
if (method == null) {
@@ -394,14 +420,20 @@
// If the requested method is not public we cannot call it
if (!Modifier.isPublic(method.getModifiers())) {
+ log("Method is not public");
return (null);
}
// If the declaring class is public, we are done
Class clazz = method.getDeclaringClass();
if (Modifier.isPublic(clazz.getModifiers())) {
+ log("Class is public");
return (method);
}
+
+ if (debug) {
+ log("Method is in non-public class " + clazz);
+ }
// Check the implemented interfaces and subinterfaces
String methodName = method.getName();
@@ -410,13 +442,12 @@
getAccessibleMethodFromInterfaceNest(clazz,
method.getName(),
method.getParameterTypes());
+
return (method);
}
- // -------------------------------------------------------- Private Methods
-
/**
* <p>Return an accessible method (that is, one that can be invoked via
* reflection) that implements the specified method, by scanning through
@@ -433,7 +464,9 @@
*/
private static Method getAccessibleMethodFromInterfaceNest
(Class clazz, String methodName, Class parameterTypes[]) {
-
+ if (debug) {
+ log("Finding accessible method " + methodName + " from interface nest");
+ }
Method method = null;
// Search up the superclass chain
@@ -470,38 +503,18 @@
}
// If we found a method return it
- if (method != null)
+ if (method != null) {
+ if (debug) {
+ log("Found method in class " + method.getDeclaringClass());
+ }
return (method);
-
+ }
// We did not find anything
return (null);
- }
-
-
- /**
- * <p>Find an accessible method that matches the given name and has compatible parameters.
- * Compatible parameters mean that every method parameter is assignable from
- * the given parameters.
- * 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)}.
- *
- * <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 methodName find method with this name
- * @param parameterTypes find method with compatible parameters
- */
- private static Method getMatchingAccessibleMethod(
+ }
+
+ private static Method[] getCompatibleMethods(
Class clazz,
String methodName,
Class[] parameterTypes) {
@@ -510,90 +523,36 @@
log("Matching name=" + methodName + " on " + clazz);
}
- // see if we can find the method directly
- // most of the time this works and it's much faster
- try {
- Method method = clazz.getMethod(methodName, parameterTypes);
- if (debug) {
- log("Found straight match: " + method);
- log("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
- log(
- "Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.",
- se);
- }
- return method;
-
- } catch (NoSuchMethodException e) { /* SWALLOW */ }
-
// search through all methods
int paramSize = parameterTypes.length;
Method[] methods = clazz.getMethods();
+ ArrayList compatibles = new ArrayList(methods.length);
for (int i = 0, size = methods.length; i < size ; i++) {
+ if (debug) {
+ log("Checking: " + methods[i]);
+ }
if (methods[i].getName().equals(methodName)) {
// log some trace information
if (debug) {
- log("Found matching name:");
- log(methods[i]);
+ log("Found matching name:" + methods[i]);
}
// compare parameters
Class[] methodsParams = methods[i].getParameterTypes();
if (ReflectionUtils.isCompatible(parameterTypes, methodsParams)) {
// get accessible version of method
- Method method = getAccessibleMethod(methods[i]);
+ Method method = getMethod(methods[i]);
if (method != null) {
- if (debug) {
- log(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
- log(
- "Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.",
- se);
- }
- return method;
+ compatibles.add(method);
+ } else {
+ log("Couldn't find accessible method for: " + methods[i]);
}
-
- log("Couldn't find accessible method.");
}
}
}
- // didn't find a match
- log("No match found.");
- return null;
- }
+ return (Method[]) compatibles.toArray(new Method[compatibles.size()]);
+ }
private static void log(Object o) {
if (debug) {
1.4 +6 -6 jakarta-commons/lang/src/test/org/apache/commons/lang/reflect/MethodUtilsTestCase.java
Index: MethodUtilsTestCase.java
===================================================================
RCS file: /home/cvs/jakarta-commons/lang/src/test/org/apache/commons/lang/reflect/MethodUtilsTestCase.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- MethodUtilsTestCase.java 21 Nov 2002 18:53:32 -0000 1.3
+++ MethodUtilsTestCase.java 10 Dec 2002 19:06:49 -0000 1.4
@@ -129,7 +129,7 @@
// easy bit first - find a public method
// METHOD ONE
- Method method = MethodUtils.getAccessibleMethod
+ Method method = MethodUtils.getMethod
(TestBean.class, "setStringProperty", String.class);
// check that we've found one that matches
@@ -141,7 +141,7 @@
// trickier this one - find a method in a direct interface
// METHOD TWO
- method = MethodUtils.getAccessibleMethod
+ method = MethodUtils.getMethod
(privateBeanFactory.create().getClass(),
"methodBar",
String.class);
@@ -155,7 +155,7 @@
// trickier this one - find a method in a indirect interface
// METHOD THREE
- method = MethodUtils.getAccessibleMethod
+ method = MethodUtils.getMethod
(privateBeanFactory.createSubclass().getClass(),
"methodBaz",
String.class);
@@ -478,7 +478,7 @@
try {
// Acquire the methods we need
- Method currentCounterMethod = MethodUtils.getAccessibleMethod
+ Method currentCounterMethod = MethodUtils.getMethod
(TestBean.class, "currentCounter",
new Class[0]);
assertNotNull("currentCounterMethod exists",
@@ -493,7 +493,7 @@
Modifier.isPublic(currentCounterMethod.getModifiers()));
assertTrue("currentCounterMethod static",
Modifier.isStatic(currentCounterMethod.getModifiers()));
- Method incrementCounterMethod1 = MethodUtils.getAccessibleMethod
+ Method incrementCounterMethod1 = MethodUtils.getMethod
(TestBean.class, "incrementCounter",
new Class[0]);
assertNotNull("incrementCounterMethod1 exists",
@@ -508,7 +508,7 @@
Modifier.isPublic(incrementCounterMethod1.getModifiers()));
assertTrue("incrementCounterMethod1 static",
Modifier.isStatic(incrementCounterMethod1.getModifiers()));
- Method incrementCounterMethod2 = MethodUtils.getAccessibleMethod
+ Method incrementCounterMethod2 = MethodUtils.getMethod
(TestBean.class, "incrementCounter",
new Class[] { Integer.TYPE });
assertNotNull("incrementCounterMethod2 exists",
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>