You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sc...@apache.org on 2002/09/21 15:36:03 UTC
cvs commit: jakarta-commons-sandbox/lang FieldUtils.java MethodUtils.java ConstructorUtils.java ArrayUtils.java ClassUtils.java ReflectionUtils.java
scolebourne 2002/09/21 06:36:02
Modified: lang ConstructorUtils.java ArrayUtils.java
ClassUtils.java ReflectionUtils.java
Added: lang FieldUtils.java MethodUtils.java
Log:
Second cut of the reflection code
Revision Changes Path
1.2 +173 -47 jakarta-commons-sandbox/lang/ConstructorUtils.java
Index: ConstructorUtils.java
===================================================================
RCS file: /home/cvs/jakarta-commons-sandbox/lang/ConstructorUtils.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ConstructorUtils.java 19 Sep 2002 23:02:51 -0000 1.1
+++ ConstructorUtils.java 21 Sep 2002 13:36:02 -0000 1.2
@@ -53,22 +53,22 @@
*/
import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-
-import org.apache.commons.lang.StringUtils;
/**
* <code>ConstructorUtils</code> contains utility methods for working for
* constructors by reflection.
+ * <p>
+ * The ability is provided to break the scoping restrictions coded by the
+ * programmer. This can allow classes to be created that shouldn't be, for
+ * example new instances of an enumerated type. Thus, this facility should
+ * be used with care.
*
* @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
* @version $Id$
*/
public class ConstructorUtils {
- /** An empty class array */
+ /** An empty constructor array */
public static final Constructor[] EMPTY_CONSTRUCTOR_ARRAY = new Constructor[0];
/**
@@ -83,6 +83,71 @@
// -------------------------------------------------------------------------
/**
+ * Gets a public <code>Constructor</code> object by matching the
+ * parameter types as per the Java Language Specification.
+ *
+ * @param cls Class object to find constructor for, must not be null
+ * @param types array of Class objects representing parameter types, may be null
+ * @return Constructor object
+ * @throws ReflectionException if an error occurs during reflection
+ * @throws IllegalArgumentException if the class is null
+ */
+ public static Constructor getConstructor(Class cls, Class[] types) {
+ return getConstructor(cls, types, false);
+ }
+
+ /**
+ * Gets a public <code>Constructor</code> object by matching the
+ * parameter types as per the Java Language Specification.
+ *
+ * @param cls Class object to find constructor for, must not be null
+ * @param types array of Class objects representing parameter types, may be null
+ * @param breakScope whether to break scope restrictions using the
+ * <code>setAccessible</code> method. False will only match public methods.
+ * @return Constructor object
+ * @throws ReflectionException if an error occurs during reflection
+ * @throws IllegalArgumentException if the class is null
+ */
+ public static Constructor getConstructor(Class cls, Class[] types, boolean breakScope) {
+ if (cls == null) {
+ throw new IllegalArgumentException("The class must not be null");
+ }
+ // try exact call first for speed
+ try {
+ getConstructorExact(cls, types, breakScope);
+
+ } catch (ReflectionException ex) {
+ if (types == null || types.length == 0) {
+ throw ex;
+ }
+ if (ex.getCause() instanceof NoSuchMethodException == false) {
+ throw ex;
+ }
+ }
+ // try to find best match
+ try {
+ Constructor[] cons = cls.getDeclaredConstructors();
+ for (int i = 0; i < cons.length; i++) {
+ if (cons[i].getParameterTypes().length == types.length) {
+ // TODO
+ }
+ }
+ return null;
+
+ } catch (ReflectionException ex) {
+ throw ex;
+ } catch (LinkageError ex) {
+ throw new ReflectionException(ReflectionUtils.getThrowableText(
+ ex, "getting constructor", cls.getName(), types, null), ex);
+ } catch (Exception ex) {
+ throw new ReflectionException(ReflectionUtils.getThrowableText(
+ ex, "getting constructor", cls.getName(), types, null), ex);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+
+ /**
* Gets a public <code>Constructor</code> object by exactly matching the
* parameter types.
*
@@ -93,7 +158,7 @@
* @throws IllegalArgumentException if the class is null
*/
public static Constructor getConstructorExact(Class cls, Class[] types) {
- return getConstructorExact(cls, types, true);
+ return getConstructorExact(cls, types, false);
}
/**
@@ -102,30 +167,36 @@
*
* @param cls Class object to find constructor for, must not be null
* @param types array of Class objects representing parameter types, may be null
- * @param publicOnly whether to only consider public constructors. If false the
- * <code>setAccessible</code> method will be used
+ * @param breakScope whether to break scope restrictions using the
+ * <code>setAccessible</code> method. False will only match public methods.
* @return Constructor object
* @throws ReflectionException if an error occurs during reflection
* @throws IllegalArgumentException if the class is null
*/
- public static Constructor getConstructorExact(Class cls, Class[] types, boolean publicOnly) {
+ public static Constructor getConstructorExact(Class cls, Class[] types, boolean breakScope) {
if (cls == null) {
throw new IllegalArgumentException("The class must not be null");
}
try {
- if (publicOnly) {
- return cls.getConstructor(types);
- } else {
+ if (breakScope) {
Constructor con = cls.getDeclaredConstructor(types);
if (Modifier.isPublic(con.getModifiers()) == false) {
con.setAccessible(true);
}
return con;
+
+ } else {
+ return cls.getConstructor(types);
}
- } catch (Throwable th) {
+ } catch (ReflectionException ex) {
+ throw ex;
+ } catch (LinkageError ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
- th, "invoking constructor", cls.getName(), types, null), th);
+ ex, "getting constructor", cls.getName(), types, null), ex);
+ } catch (Exception ex) {
+ throw new ReflectionException(ReflectionUtils.getThrowableText(
+ ex, "getting constructor", cls.getName(), types, null), ex);
}
}
@@ -141,7 +212,7 @@
* @throws IllegalArgumentException if the constructor is null
*/
public static Object newInstance(Constructor con, Object param) {
- return newInstance(con, new Object[] {param}, true);
+ return newInstance(con, new Object[] {param}, false);
}
/**
@@ -154,7 +225,7 @@
* @throws IllegalArgumentException if the constructor is null
*/
public static Object newInstance(Constructor con, Object[] params) {
- return newInstance(con, params, true);
+ return newInstance(con, params, false);
}
/**
@@ -162,25 +233,30 @@
*
* @param con Class object to find constructor for, must not be null
* @param params array of objects to pass as parameters, may be null
- * @param publicOnly whether to only consider public constructors. If false the
- * <code>setAccessible</code> method will be used
+ * @param breakScope whether to break scope restrictions using the
+ * <code>setAccessible</code> method. False will only match public methods.
* @return the newly created object
* @throws ReflectionException if an error occurs during reflection
* @throws IllegalArgumentException if the constructor is null
*/
- public static Object newInstance(Constructor con, Object[] params, boolean publicOnly) {
+ public static Object newInstance(Constructor con, Object[] params, boolean breakScope) {
if (con == null) {
throw new IllegalArgumentException("The constructor must not be null");
}
try {
- if (publicOnly == false && Modifier.isPublic(con.getModifiers()) == false) {
+ if (breakScope && Modifier.isPublic(con.getModifiers()) == false) {
con.setAccessible(true);
}
return con.newInstance(params);
- } catch (Throwable th) {
+ } catch (ReflectionException ex) {
+ throw ex;
+ } catch (LinkageError ex) {
+ throw new ReflectionException(ReflectionUtils.getThrowableText(
+ ex, "invoking constructor", con.getDeclaringClass().getName(), con.getParameterTypes(), null), ex);
+ } catch (Exception ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
- th, "invoking constructor", con.getDeclaringClass().getName(), con.getParameterTypes(), null), th);
+ ex, "invoking constructor", con.getDeclaringClass().getName(), con.getParameterTypes(), null), ex);
}
}
@@ -195,7 +271,7 @@
* @throws IllegalArgumentException if the class name is empty
*/
public static Object newInstance(String className) {
- return newInstance(className, true);
+ return newInstance(className, false);
}
/**
@@ -204,15 +280,15 @@
* is used to make it accessible.
*
* @param className String class name to instantiate, must not be empty
- * @param publicOnly whether to only consider public constructors. If false the
- * <code>setAccessible</code> method will be used
+ * @param breakScope whether to break scope restrictions using the
+ * <code>setAccessible</code> method. False will only match public methods.
* @return the newly created object
* @throws ReflectionException if an error occurs during reflection
* @throws IllegalArgumentException if the class name is empty
*/
- public static Object newInstance(String className, boolean publicOnly) {
+ public static Object newInstance(String className, boolean breakScope) {
Class cls = ReflectionUtils.getClass(className);
- return ConstructorUtils.newInstance(cls, publicOnly);
+ return newInstance(cls, breakScope);
}
// -------------------------------------------------------------------------
@@ -226,7 +302,7 @@
* @throws IllegalArgumentException if the class is null
*/
public static Object newInstance(Class cls) {
- return newInstance(cls, true);
+ return newInstance(cls, false);
}
/**
@@ -235,27 +311,32 @@
* is used to make it accessible.
*
* @param cls Class object to instantiate, must not be null
- * @param publicOnly whether to only consider public constructors. If false the
- * <code>setAccessible</code> method will be used
+ * @param breakScope whether to break scope restrictions using the
+ * <code>setAccessible</code> method. False will only match public methods.
* @return the newly created object
* @throws ReflectionException if an error occurs during reflection
* @throws IllegalArgumentException if the class is null
*/
- public static Object newInstance(Class cls, boolean publicOnly) {
- if (publicOnly) {
+ public static Object newInstance(Class cls, boolean breakScope) {
+ if (breakScope) {
+ return newInstanceExact(cls, null, null, true);
+
+ } else {
if (cls == null) {
throw new IllegalArgumentException("The constructor must not be null");
}
try {
return cls.newInstance();
- } catch (Throwable th) {
+ } catch (ReflectionException ex) {
+ throw ex;
+ } catch (LinkageError ex) {
+ throw new ReflectionException(ReflectionUtils.getThrowableText(
+ ex, "instantiating class", cls.getName(), null, null), ex);
+ } catch (Exception ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
- th, "instantiating class", cls.getName(), null, null), th);
+ ex, "instantiating class", cls.getName(), null, null), ex);
}
- } else {
- Constructor con = ConstructorUtils.getConstructorExact(cls, null, publicOnly);
- return ConstructorUtils.newInstance(con, null, publicOnly);
}
}
@@ -263,6 +344,48 @@
/**
* Creates a new instance of the specified <code>Class</code>.
+ * The constructor is found by matching the
+ * parameter types as per the Java Language Specification.
+ *
+ * @param cls Class object to instantiate, must not be null
+ * @param types array of Class objects representing parameter types, may be null
+ * @param params array of objects to pass as parameters, may be null
+ * @return the newly created object
+ * @throws ReflectionException if an error occurs during reflection
+ * @throws IllegalArgumentException if the class is null
+ */
+ public static Object newInstance(Class cls, Class[] types, Object[] params) {
+ return newInstance(cls, types, params, false);
+ }
+
+ /**
+ * Creates a new instance of the specified <code>Class</code>.
+ * The constructor is found by matching the
+ * parameter types as per the Java Language Specification.
+ *
+ * @param cls Class object to instantiate, must not be null
+ * @param types array of Class objects representing parameter types, may be null
+ * @param params array of objects to pass as parameters, may be null
+ * @param breakScope whether to break scope restrictions using the
+ * <code>setAccessible</code> method. False will only match public methods.
+ * @return the newly created object
+ * @throws ReflectionException if an error occurs during reflection
+ * @throws IllegalArgumentException if the types and params lengths differ
+ * @throws IllegalArgumentException if the class is null
+ */
+ public static Object newInstance(Class cls, Class[] types, Object[] params, boolean breakScope) {
+ if (ArrayUtils.isSameLength(types, params) == false) {
+ throw new IllegalArgumentException("The types and params lengths must be the same");
+ }
+ Constructor con = getConstructor(cls, types, breakScope);
+ return newInstance(con, params, breakScope);
+ }
+
+ // -------------------------------------------------------------------------
+
+ /**
+ * Creates a new instance of the specified <code>Class</code>.
+ * The constructor is found by matching the parameter types exactly.
*
* @param cls Class object to instantiate, must not be null
* @param types array of Class objects representing parameter types, may be null
@@ -272,26 +395,29 @@
* @throws IllegalArgumentException if the class is null
*/
public static Object newInstanceExact(Class cls, Class[] types, Object[] params) {
- return newInstanceExact(cls, types, params, true);
+ return newInstanceExact(cls, types, params, false);
}
/**
* Creates a new instance of the specified <code>Class</code>.
- * If the constructor is not public, <code>setAccessible(true)</code>
- * is used to make it accessible.
+ * The constructor is found by matching the parameter types exactly.
*
* @param cls Class object to instantiate, must not be null
* @param types array of Class objects representing parameter types, may be null
* @param params array of objects to pass as parameters, may be null
- * @param publicOnly whether to only consider public constructors. If false the
- * <code>setAccessible</code> method will be used
+ * @param breakScope whether to break scope restrictions using the
+ * <code>setAccessible</code> method. False will only match public methods.
* @return the newly created object
* @throws ReflectionException if an error occurs during reflection
+ * @throws IllegalArgumentException if the types and params lengths differ
* @throws IllegalArgumentException if the class is null
*/
- public static Object newInstanceExact(Class cls, Class[] types, Object[] params, boolean publicOnly) {
- Constructor con = ConstructorUtils.getConstructorExact(cls, types, publicOnly);
- return ConstructorUtils.newInstance(con, params, publicOnly);
+ public static Object newInstanceExact(Class cls, Class[] types, Object[] params, boolean breakScope) {
+ if (ArrayUtils.isSameLength(types, params) == false) {
+ throw new IllegalArgumentException("The types and params lengths must be the same");
+ }
+ Constructor con = getConstructorExact(cls, types, breakScope);
+ return newInstance(con, params, breakScope);
}
// -------------------------------------------------------------------------
1.2 +53 -17 jakarta-commons-sandbox/lang/ArrayUtils.java
Index: ArrayUtils.java
===================================================================
RCS file: /home/cvs/jakarta-commons-sandbox/lang/ArrayUtils.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ArrayUtils.java 19 Sep 2002 23:02:51 -0000 1.1
+++ ArrayUtils.java 21 Sep 2002 13:36:02 -0000 1.2
@@ -102,7 +102,7 @@
* multi-dimensional primitive arrays.
* The format is that of Java source code, for example {a,b}.
*
- * @param array the array to get a toString for
+ * @param array the array to get a toString for, must not be null
* @return a String representation of the array
* @throws IllegalArgumentException if the array is null
*/
@@ -111,12 +111,30 @@
}
/**
+ * Output the array as a String handling nulls.
+ * <p>
+ * Multi-dimensional arrays are handled correctly, including
+ * multi-dimensional primitive arrays.
+ * The format is that of Java source code, for example {a,b}.
+ *
+ * @param array the array to get a toString for, may be null
+ * @param stringIfNull the String to return if the array is null
+ * @return a String representation of the array
+ */
+ public static String toString(Object[] array, String stringIfNull) {
+ if (array == null) {
+ return stringIfNull;
+ }
+ return new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString();
+ }
+
+ /**
* Output the array as a String.
* <p>
* Multi-dimensional arrays are handled by the Object[] method.
* The format is that of Java source code, for example {1,2}.
*
- * @param array the array to get a toString for
+ * @param array the array to get a toString for, must not be null
* @return a String representation of the array
* @throws IllegalArgumentException if the array is null
*/
@@ -130,7 +148,7 @@
* Multi-dimensional arrays are handled by the Object[] method.
* The format is that of Java source code, for example {1,2}.
*
- * @param array the array to get a toString for
+ * @param array the array to get a toString for, must not be null
* @return a String representation of the array
* @throws IllegalArgumentException if the array is null
*/
@@ -144,7 +162,7 @@
* Multi-dimensional arrays are handled by the Object[] method.
* The format is that of Java source code, for example {1,2}.
*
- * @param array the array to get a toString for
+ * @param array the array to get a toString for, must not be null
* @return a String representation of the array
* @throws IllegalArgumentException if the array is null
*/
@@ -158,7 +176,7 @@
* Multi-dimensional arrays are handled by the Object[] method.
* The format is that of Java source code, for example {1,2}.
*
- * @param array the array to get a toString for
+ * @param array the array to get a toString for, must not be null
* @return a String representation of the array
* @throws IllegalArgumentException if the array is null
*/
@@ -172,7 +190,7 @@
* Multi-dimensional arrays are handled by the Object[] method.
* The format is that of Java source code, for example {1.0,2.0}.
*
- * @param array the array to get a toString for
+ * @param array the array to get a toString for, must not be null
* @return a String representation of the array
* @throws IllegalArgumentException if the array is null
*/
@@ -186,7 +204,7 @@
* Multi-dimensional arrays are handled by the Object[] method.
* The format is that of Java source code, for example {1.0,2.0}.
*
- * @param array the array to get a toString for
+ * @param array the array to get a toString for, must not be null
* @return a String representation of the array
* @throws IllegalArgumentException if the array is null
*/
@@ -200,7 +218,7 @@
* Multi-dimensional arrays are handled by the Object[] method.
* The format is that of Java source code, for example {true,false}.
*
- * @param array the array to get a toString for
+ * @param array the array to get a toString for, must not be null
* @return a String representation of the array
* @throws IllegalArgumentException if the array is null
*/
@@ -215,7 +233,7 @@
* <p>
* The objecs in the array are not cloned.
*
- * @param array the array to shallow clone
+ * @param array the array to shallow clone, must not be null
* @return the cloned array
* @throws IllegalArgumentException if the array is null
*/
@@ -229,7 +247,7 @@
/**
* Clone an array.
*
- * @param array the array to clone
+ * @param array the array to clone, must not be null
* @return the cloned array
* @throws IllegalArgumentException if the array is null
*/
@@ -243,7 +261,7 @@
/**
* Clone an array.
*
- * @param array the array to clone
+ * @param array the array to clone, must not be null
* @return the cloned array
* @throws IllegalArgumentException if the array is null
*/
@@ -257,7 +275,7 @@
/**
* Clone an array.
*
- * @param array the array to clone
+ * @param array the array to clone, must not be null
* @return the cloned array
* @throws IllegalArgumentException if the array is null
*/
@@ -271,7 +289,7 @@
/**
* Clone an array.
*
- * @param array the array to clone
+ * @param array the array to clone, must not be null
* @return the cloned array
* @throws IllegalArgumentException if the array is null
*/
@@ -285,7 +303,7 @@
/**
* Clone an array.
*
- * @param array the array to clone
+ * @param array the array to clone, must not be null
* @return the cloned array
* @throws IllegalArgumentException if the array is null
*/
@@ -299,7 +317,7 @@
/**
* Clone an array.
*
- * @param array the array to clone
+ * @param array the array to clone, must not be null
* @return the cloned array
* @throws IllegalArgumentException if the array is null
*/
@@ -313,7 +331,7 @@
/**
* Clone an array.
*
- * @param array the array to clone
+ * @param array the array to clone, must not be null
* @return the cloned array
* @throws IllegalArgumentException if the array is null
*/
@@ -322,6 +340,24 @@
throw new IllegalArgumentException("The array must not be null");
}
return (boolean[]) array.clone();
+ }
+
+ //--------------------------------------------------------------------------
+
+ /**
+ * Checks whether two arrays are the same length, treating null arrays as length 0.
+ *
+ * @param array1 the first array, may be null
+ * @param array2 the second array, may be null
+ * @param true if length of arrays matches, treating null as an empty array
+ */
+ public static boolean isSameLength(Object[] array1, Object[] array2) {
+ if ((array1 == null && array2 != null && array2.length > 0) ||
+ (array2 == null && array1 != null && array1.length > 0) ||
+ (array1 != null && array2 != null && array1.length != array2.length)) {
+ return false;
+ }
+ return true;
}
}
1.2 +336 -122 jakarta-commons-sandbox/lang/ClassUtils.java
Index: ClassUtils.java
===================================================================
RCS file: /home/cvs/jakarta-commons-sandbox/lang/ClassUtils.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ClassUtils.java 6 Sep 2002 22:42:38 -0000 1.1
+++ ClassUtils.java 21 Sep 2002 13:36:02 -0000 1.2
@@ -52,168 +52,382 @@
* <http://www.apache.org/>.
*/
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
/**
- * A set of static utilities for use with ClassUtils.
+ * <code>ClassUtils</code> contains utility methods for working for
+ * classes without using reflection.
*
- * @author bayard@generationjava.com
+ * @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
* @version $Id$
*/
-final public class ClassUtils {
+public class ClassUtils {
/**
- * Create an object from the classname. Must have an empty constructor.
- *
- * @param classname String name of the class
- *
- * @return Object instance of the class or null
+ * ClassUtils instances should NOT be constructed in standard programming.
+ * Instead, the class should be used as <code>ClassUtils.getShortClassName(cls)</code>.
+ * This constructor is public to permit tools that require a JavaBean instance
+ * to operate.
*/
- static public Object createObject(String classname) {
- Class tmpClass = null;
-
- tmpClass = getClass(classname);
-
- return createObject(tmpClass);
+ public ClassUtils() {
}
+ // -------------------------------------------------------------------------
+
/**
- * Create an object from a class.
- *
- * @param clss Class object to instantiate
- *
- * @return Object instance of the class or null
+ * Gets the class name minus the package name from a Class.
+ *
+ * @param cls the class to get the short name for, must not be null
+ * @return the class name without the package name
+ * @throws IllegalArgumentException if the class is null
*/
- static public Object createObject(Class clss) {
-
- try {
- return clss.newInstance();
- } catch (IllegalAccessException iae) {
- System.err.println("Cant instantiate " + clss.getName() + " because " +
- iae.getMessage());
- } catch (InstantiationException ie) {
- System.err.println("Cant instantiate " + clss.getName() + " because " +
- ie.getMessage());
+ public static String getShortClassName(Class cls) {
+ if (cls == null) {
+ throw new IllegalArgumentException("The class must not be null");
}
-
- return null;
+ return getShortClassName(cls.getName());
}
-
+
/**
- * Is this Class in the CLASSPATH
- *
- * @param classname String of the class
- *
- * @return boolean exists or not.
+ * Gets the class name minus the package name for an Object.
+ *
+ * @param object the class to get the short name for, must not be null
+ * @return the class name of the object without the package name
+ * @throws IllegalArgumentException if the object is null
*/
- static public boolean classExists(String classname) {
- Class tmpClass = null;
-
- /* try and load class */
- try {
- tmpClass = Class.forName(classname);
- } catch (ClassNotFoundException cnfe) {
- return false;
- } catch (IllegalArgumentException iae) {
- return false;
+ public static String getShortClassName(Object object) {
+ if (object == null) {
+ throw new IllegalArgumentException("The object must not be null");
}
-
- return true;
+ return getShortClassName(object.getClass().getName());
}
-
+
/**
- * Get the Class object for a classname.
- *
- * @param classname String of the class
- *
- * @return Class instance for the class.
+ * Gets the class name minus the package name from a String.
+ * <p>
+ * The string passed in is assumed to be a class name - it is not
+ * checked.
+ *
+ * @param className the className to get the short name for, must not be empty
+ * @return the class name of the class without the package name
+ * @throws IllegalArgumentException if the className is empty
*/
- static public Class getClass(String classname) {
- Class tmpClass = null;
-
- /* try an load class */
- try {
- tmpClass = Class.forName(classname);
- } catch (ClassNotFoundException cnfe) {
- System.out.println("Can't resolve classname " + classname);
- } catch (IllegalArgumentException iae) {
- System.err.println("Cant resolve " + tmpClass.getName() + " because " + iae.getMessage());
+ public static String getShortClassName(String className) {
+ if (StringUtils.isEmpty(className)) {
+ throw new IllegalArgumentException("The className must not be empty");
+ }
+ int i = className.lastIndexOf('.');
+ if (i == -1) {
+ return className;
}
-
- return tmpClass;
+ return className.substring(i + 1);
}
-
+
+ // -------------------------------------------------------------------------
+
/**
- * Is this Class object an instance of the class with this name.
- *
- * @param clss Class instance
- * @param inst String name of potential supertype
+ * Gets the package name of a Class.
+ *
+ * @param cls the class to get the package name for, must not be null
+ * @return the package name
+ * @throws IllegalArgumentException if the class is null
+ */
+ public static String getPackageName(Class cls) {
+ if (cls == null) {
+ throw new IllegalArgumentException("The class must not be null");
+ }
+ return getPackageName(cls.getName());
+ }
+
+ /**
+ * Gets the package name of an Object.
+ *
+ * @param object the class to get the package name for, must not be null
+ * @return the package name
+ * @throws IllegalArgumentException if the object is null
+ */
+ public static String getPackageName(Object object) {
+ if (object == null) {
+ throw new IllegalArgumentException("The object must not be null");
+ }
+ return getPackageName(object.getClass().getName());
+ }
+
+ /**
+ * Gets the package name from a String.
+ * <p>
+ * The string passed in is assumed to be a class name - it is not
+ * checked.
+ *
+ * @param className the className to get the package name for, must not be empty
+ * @return the package name
+ * @throws IllegalArgumentException if the className is empty
+ */
+ public static String getPackageName(String className) {
+ if (StringUtils.isEmpty(className)) {
+ throw new IllegalArgumentException("The className must not be empty");
+ }
+ int i = className.lastIndexOf('.');
+ if (i == -1) {
+ return "";
+ }
+ return className.substring(0, i);
+ }
+
+ // -------------------------------------------------------------------------
+
+ /**
+ * Gets a list of superclasses for the given class.
+ *
+ * @param cls the class to look up, must not be null
+ * @return the list of superclasses in order going up from this one
+ * @throws IllegalArgumentException if the class is null
+ */
+ public static List getAllSuperclasses(Class cls) {
+ if (cls == null) {
+ throw new IllegalArgumentException("The class must not be null");
+ }
+ List classes = new ArrayList();
+ Class superclass = cls.getSuperclass();
+ while (superclass != null) {
+ classes.add(superclass);
+ superclass = superclass.getSuperclass();
+ }
+ return classes;
+ }
+
+ /**
+ * Gets a list of all interfaces implemented by the given class.
+ * <p>
+ * The order is determined by looking through each interface in turn as
+ * declared in the source file and following its hieracrchy up. Later
+ * duplicates are ignored, so the order is maintained.
+ *
+ * @param cls the class to look up, must not be null
+ * @return the list of interfaces in order
+ * @throws IllegalArgumentException if the class is null
+ */
+ public static List getAllInterfaces(Class cls) {
+ if (cls == null) {
+ throw new IllegalArgumentException("The class must not be null");
+ }
+ List list = new ArrayList();
+ Class[] interfaces = cls.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ if (list.contains(interfaces[i]) == false) {
+ list.add(interfaces[i]);
+ }
+ List superInterfaces = getAllInterfaces(interfaces[i]);
+ for (Iterator it = superInterfaces.iterator(); it.hasNext();) {
+ Class intface = (Class) it.next();
+ if (list.contains(intface) == false) {
+ list.add(intface);
+ }
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Gets a list of subclasses of the specified class.
+ * <p>
+ * This method searches the classpath to find all the subclasses
+ * of a particular class available. No classes are loaded, the
+ * returned list contains class names, not classes.
*
- * @return boolean was it an instanceof
+ * @param cls the class to find subclasses for
+ * @return the list of subclasses
*/
- static public boolean classInstanceOf(Class clss, String inst) {
- if(classImplements(clss,inst)) {
- return true;
- } else
- if(classExtends(clss,inst)) {
- return true;
- } else {
- return false;
+ public static List getAllSubclassNames(Class cls) {
+ if (cls == null) {
+ throw new IllegalArgumentException("The class must not be null");
}
+ // TODO Use JavaWorld tip for searching the classpath
+ return null;
}
/**
- * Does this Class implement an interface with this name.
- *
- * @param clss Class instance
- * @param exts String name of potential interface
+ * Gets a list of implementations of the specified interface.
+ * <p>
+ * This method searches the classpath to find all the implementations
+ * of a particular interface available. No classes are loaded, the
+ * returned list contains class names, not classes.
*
- * @return boolean was it an implementor
+ * @param cls the class to find sub classes for
+ * @return the list of sub classes
*/
- static public boolean classImplements(Class clss, String exts) {
-
- Class sprcls = clss;
- Class excls = getClass(exts);
-
- while(sprcls != null) {
- Class[] interfaces = sprcls.getInterfaces();
+ public static List getAllImplementationClassNames(Class cls) {
+ if (cls == null) {
+ throw new IllegalArgumentException("The class must not be null");
+ }
+ // TODO Use JavaWorld tip for searching the classpath
+ return null;
+ }
- for(int i=0;i<interfaces.length;i++) {
- if(interfaces[i].equals(excls)) {
- return true;
+ /**
+ * Given a list of classes, this method finds all those which are
+ * subclasses or implementations of a specified superclass.
+ *
+ * @param classes the classes to check
+ * @param superclass the superclass to check for
+ * @return the list of subclasses or implementations
+ * @throws IllegalArgumentException if the classes or superClass is null
+ */
+ public static List getAssignableFrom(List classes, Class superclass) {
+ if (classes == null) {
+ throw new IllegalArgumentException("The classes must not be null");
+ }
+ if (superclass == null) {
+ throw new IllegalArgumentException("The superclass must not be null");
+ }
+ List subs = new ArrayList();
+ Iterator it = classes.iterator();
+ while (it.hasNext()) {
+ Class cls = (Class) it.next();
+ if (cls == null) {
+ throw new IllegalArgumentException("The class list must not contain nulls");
+ }
+ if (isAssignable(cls, superclass)) {
+ subs.add(cls);
}
}
-
- sprcls = sprcls.getSuperclass();
- }
-
- return false;
+ return subs;
}
/**
- * Does this Class extend a superclass with this name.
- *
- * @param clss Class instance
- * @param exts String name of potential superclass
- *
- * @return boolean was it a superclass
+ * Converts a primitive class to its matching object class.
+ * Non-primitive classes are unaffected.
+ * <p>
+ * In other words, a <code>boolean</code> Class will be converted to
+ * a <code>Boolean</code> Class and so on.
+ *
+ * @param cls the class to convert
+ * @return converted class
+ * @throws IllegalArgumentException if the class is null
*/
- static public boolean classExtends(Class clss, String exts) {
- if(clss == null) {
- return false;
+ public static Class convertPrimitiveClass(Class cls) {
+ if (cls == null) {
+ throw new IllegalArgumentException("The class must not be null");
+ }
+ if (cls.isPrimitive()) {
+ if (Integer.TYPE.equals(cls)) {
+ return Integer.class;
+ } else if (Long.TYPE.equals(cls)) {
+ return Long.class;
+ } else if (Boolean.TYPE.equals(cls)) {
+ return Boolean.class;
+ } else if (Double.TYPE.equals(cls)) {
+ return Double.class;
+ } else if (Float.TYPE.equals(cls)) {
+ return Float.class;
+ } else if (Character.TYPE.equals(cls)) {
+ return Character.class;
+ } else if (Short.TYPE.equals(cls)) {
+ return Short.class;
+ } else if (Byte.TYPE.equals(cls)) {
+ return Byte.class;
+ }
+ }
+ return cls;
+ }
+
+ /**
+ * Checks if one Class can be assigned to a variable of another Class.
+ * <p>
+ * Unlike the Class.isAssignableFrom method, this method takes into
+ * account widenings of primitive classes and nulls.
+ * <p>
+ * Primitive widenings allow an int to be assigned to a long, float or
+ * double. This method returns the correct result for these cases.
+ * <p>
+ * Null may be assigned to any reference type. This method will return
+ * true if null is passed in and the toClass is non-primitive.
+ * <p>
+ * Specifically, this method tests whether the type represented by the
+ * specified <code>Class</code> parameter can be converted to the type
+ * represented by this <code>Class</code> object via an identity conversion
+ * widening primitive or widening reference conversion. See
+ * <em>The Java Language Specification</em>, sections 5.1.1, 5.1.2 and
+ * 5.1.4 for details.
+ *
+ * @param cls the Class to check, may be null
+ * @param toClass the Class to try to assign into, must not be null
+ * @return true if assignment possible
+ * @throws IllegalArgumentException if the toClass is null
+ */
+ public static boolean isAssignable(Class cls, Class toClass) {
+ if (toClass == null) {
+ throw new IllegalArgumentException("The class must not be null");
}
- if(clss.getName().equals(exts)) {
+ // have to check for null, as isAssignableFrom doesn't
+ if (cls == null) {
+ return !(toClass.isPrimitive());
+ }
+ if (cls.equals(toClass)) {
return true;
}
- Class sprcls = clss.getSuperclass();
- Class excls = getClass(exts);
-
-// while(! sprcls.equals(sprcls.getSuperclass()) ) {
- while( sprcls != null ) {
- if(sprcls.equals(excls)) {
- return true;
+ if (cls.isPrimitive()) {
+ if (toClass.isPrimitive() == false) {
+ return false;
+ }
+ if (Integer.TYPE.equals(cls)) {
+ return Long.TYPE.equals(toClass)
+ || Float.TYPE.equals(toClass)
+ || Double.TYPE.equals(toClass);
+ }
+ if (Long.TYPE.equals(cls)) {
+ return Float.TYPE.equals(toClass)
+ || Double.TYPE.equals(toClass);
+ }
+ if (Boolean.TYPE.equals(cls)) {
+ return false;
}
- sprcls = sprcls.getSuperclass();
+ if (Double.TYPE.equals(cls)) {
+ return false;
+ }
+ if (Float.TYPE.equals(cls)) {
+ return Double.TYPE.equals(toClass);
+ }
+ if (Character.TYPE.equals(cls)) {
+ return Integer.TYPE.equals(toClass)
+ || Long.TYPE.equals(toClass)
+ || Float.TYPE.equals(toClass)
+ || Double.TYPE.equals(toClass);
+ }
+ if (Short.TYPE.equals(cls)) {
+ return Integer.TYPE.equals(toClass)
+ || Long.TYPE.equals(toClass)
+ || Float.TYPE.equals(toClass)
+ || Double.TYPE.equals(toClass);
+ }
+ if (Byte.TYPE.equals(cls)) {
+ return Short.TYPE.equals(toClass)
+ || Integer.TYPE.equals(toClass)
+ || Long.TYPE.equals(toClass)
+ || Float.TYPE.equals(toClass)
+ || Double.TYPE.equals(toClass);
+ }
+ // should never get here
+ return false;
}
- return false;
+ return toClass.isAssignableFrom(cls);
}
-
+
+ /**
+ * Is the specified class an inner class or static nested class.
+ *
+ * @param cls the class to check
+ * @return true if the class is an inner or static nested class
+ * @throws IllegalArgumentException if the class is null
+ */
+ public static boolean isInnerClass(Class cls) {
+ if (cls == null) {
+ throw new IllegalArgumentException("The class must not be null");
+ }
+ return (cls.getDeclaringClass() != null);
+ }
+
}
1.2 +110 -895 jakarta-commons-sandbox/lang/ReflectionUtils.java
Index: ReflectionUtils.java
===================================================================
RCS file: /home/cvs/jakarta-commons-sandbox/lang/ReflectionUtils.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ReflectionUtils.java 19 Sep 2002 23:02:51 -0000 1.1
+++ ReflectionUtils.java 21 Sep 2002 13:36:02 -0000 1.2
@@ -52,136 +52,116 @@
* <http://www.apache.org/>.
*/
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
import org.apache.commons.lang.StringUtils;
/**
- * <code>MethodUtils</code> contains utility methods for working for
- * methods by reflection.
+ * <code>ReflectionUtils</code> contains utility methods for working for
+ * reflection.
*
- * @author Based on code from BeanUtils
* @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
* @version $Id$
*/
public class ReflectionUtils {
- //
- // WORK IN PROGRESS - DOESN't COMPILE
- //
+ /**
+ * ReflectionUtils instances should NOT be constructed in standard programming.
+ * Instead, the class should be used as <code>ReflectionUtils.getShortClassName(obj)</code>.
+ * This constructor is public to permit tools that require a JavaBean instance
+ * to operate.
+ */
+ public ReflectionUtils() {
+ }
- /** An empty class array */
- public static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
- /** An empty class array */
- public static final Field[] EMPTY_FIELD_ARRAY = new Field[0];
- /** An empty class array */
- public static final Constructor[] EMPTY_CONSTRUCTOR_ARRAY = new Constructor[0];
-
// -------------------------------------------------------------------------
/**
- * Gets the class name minus the package name from a Class.
+ * Tests whether the specified field or method is
+ * <code>static</code>.
*
- * @param cls the class to get the short name for, must not be null
- * @return the class name without the package name
- * @throws IllegalArgumentException if the class is null
+ * @param member the member to test, must not be null
+ * @return true if the member is static
*/
- public static String getShortClassName(Class cls) {
- if (cls == null) {
- throw new IllegalArgumentException("The class must not be null");
- }
- return getShortClassName(cls.getName());
+ public static boolean isStatic(Member member) {
+ if (member == null) {
+ throw new IllegalArgumentException("The member must not be null");
+ }
+ return Modifier.isStatic(member.getModifiers());
}
-
+
/**
- * Gets the class name minus the package name for an Object.
+ * Tests whether the specified field or method is
+ * <code>static</code>.
*
- * @param object the class to get the short name for, must not be null
- * @return the class name of the object without the package name
- * @throws IllegalArgumentException if the object is null
+ * @param member the member to test, must not be null
+ * @return true if the member is final
*/
- public static String getShortClassName(Object object) {
- if (object == null) {
- throw new IllegalArgumentException("The object must not be null");
- }
- return getShortClassName(object.getClass().getName());
+ public static boolean isFinal(Member member) {
+ if (member == null) {
+ throw new IllegalArgumentException("The member must not be null");
+ }
+ return Modifier.isFinal(member.getModifiers());
}
-
+
/**
- * Gets the class name minus the package name from a String.
- * <p>
- * The string passed in is assumed to be a class name - it is not
- * checked.
+ * Tests whether the specified field, method or constructor is
+ * <code>public</code>.
*
- * @param className the className to get the short name for, must not be empty
- * @return the class name of the class without the package name
- * @throws IllegalArgumentException if the className is empty
+ * @param member the member to test, must not be null
+ * @return true if the member is public scoped
*/
- public static String getShortClassName(String className) {
- if (StringUtils.isEmpty(className)) {
- throw new IllegalArgumentException("The className must not be empty");
- }
- int i = className.lastIndexOf('.');
- if (i == -1) {
- return className;
- }
- return className.substring(i + 1);
+ public static boolean isPublicScope(Member member) {
+ if (member == null) {
+ throw new IllegalArgumentException("The member must not be null");
+ }
+ return Modifier.isStatic(member.getModifiers());
}
-
- // -------------------------------------------------------------------------
-
+
/**
- * Gets the package name of a Class.
+ * Tests whether the specified field, method or constructor is
+ * <code>protected</code>.
*
- * @param cls the class to get the package name for, must not be null
- * @return the package name
- * @throws IllegalArgumentException if the class is null
+ * @param member the member to test, must not be null
+ * @return true if the member is protected scoped
*/
- public static String getPackageName(Class cls) {
- if (cls == null) {
- throw new IllegalArgumentException("The class must not be null");
- }
- return getPackageName(cls.getName());
+ public static boolean isProtectedScope(Member member) {
+ if (member == null) {
+ throw new IllegalArgumentException("The member must not be null");
+ }
+ return Modifier.isProtected(member.getModifiers());
}
-
+
/**
- * Gets the package name of an Object.
+ * Tests whether the specified field, method or constructor is
+ * package (default) scoped.
*
- * @param object the class to get the package name for, must not be null
- * @return the package name
- * @throws IllegalArgumentException if the object is null
+ * @param member the member to test, must not be null
+ * @return true if the member is package scoped
*/
- public static String getPackageName(Object object) {
- if (object == null) {
- throw new IllegalArgumentException("The object must not be null");
- }
- return getPackageName(object.getClass().getName());
+ public static boolean isPackageScope(Member member) {
+ return !(isPublicScope(member) || isProtectedScope(member) || isPrivateScope(member));
}
-
+
/**
- * Gets the package name from a String.
- * <p>
- * The string passed in is assumed to be a class name - it is not
- * checked.
+ * Tests whether the specified field, method or constructor is
+ * <code>private</code>.
*
- * @param className the className to get the package name for, must not be empty
- * @return the package name
- * @throws IllegalArgumentException if the className is empty
+ * @param member the member to test, must not be null
+ * @return true if the member is private scoped
*/
- public static String getPackageName(String className) {
- if (StringUtils.isEmpty(className)) {
- throw new IllegalArgumentException("The className must not be empty");
- }
- int i = className.lastIndexOf('.');
- if (i == -1) {
- return "";
- }
- return className.substring(0, i);
+ public static boolean isPrivateScope(Member member) {
+ if (member == null) {
+ throw new IllegalArgumentException("The member must not be null");
+ }
+ return Modifier.isPrivate(member.getModifiers());
}
-
+
// -------------------------------------------------------------------------
/**
@@ -196,822 +176,41 @@
if (StringUtils.isEmpty(className)) {
throw new IllegalArgumentException("The class name must not be null");
}
-
try {
return Class.forName(className);
- } catch (ExceptionInInitializerError ex) {
- throw new ReflectionException("ExceptionInInitializerError while creating Class '" + className + "'", ex);
- } catch (NoClassDefFoundError ex) {
- throw new ReflectionException("NoClassDefFoundError while creating Class '" + className + "'", ex);
} catch (LinkageError ex) {
- throw new ReflectionException("LinkageError while creating Class '" + className + "'", ex);
- } catch (ClassNotFoundException ex) {
- throw new ReflectionException("ClassNotFoundException while creating Class '" + className + "'", ex);
+ throw new ReflectionException(getThrowableText(ex, "getting class", className, null, null), ex);
+ } catch (Exception ex) {
+ throw new ReflectionException(getThrowableText(ex, "getting class", className, null, null), ex);
}
}
// -------------------------------------------------------------------------
/**
- * <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}.
- * It loops through all methods with names that match
- * and then executes the first it finds with compatable parameters.</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>
- *
- * <p> This is a convenient wrapper for
- * {@link #invokeMethod(Object object,String methodName,Object [] args)}.
- * </p>
- *
- * @param objectToInvoke invoke method on this object, must not be null
- * @param methodName get method with this name, must not be null
- * @param arg use this argument, must not be null
- *
- * @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 IllegalArgumentException if any parameter is null
- */
- public static Object invokeMethod(
- Object objectToInvoke,
- String methodName,
- Object arg)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
-
- if (objectToInvoke == null) {
- throw new IllegalArgumentException("The object to invoke must not be null");
- }
- if (methodName == null) {
- throw new IllegalArgumentException("The method name must not be null");
- }
- if (arg == null) {
- throw new IllegalArgumentException("The argument must not be null");
- }
- Object[] args = {arg};
- return invokeMethod(objectToInvoke, methodName, args);
- }
-
- /**
- * <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 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>
- *
- * <p> This is a convenient wrapper for
- * {@link #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
- * </p>
- *
- * @param objectToInvoke invoke method on this object, must not be null
- * @param methodName get method with this name, must not be null
- * @param args use these arguments - treat null as empty array
- *
- * @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 IllegalArgumentException if the objectToInvoke, methodName or any argument is null
- */
- public static Object invokeMethod(
- Object objectToInvoke,
- String methodName,
- Object[] args)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
-
- if (objectToInvoke == null) {
- throw new IllegalArgumentException("The object to invoke must not be null");
- }
- if (methodName == null) {
- throw new IllegalArgumentException("The method name must not be null");
- }
- if (args == null) {
- return invokeMethod(objectToInvoke, methodName, null, null);
- } else {
- int arguments = args.length;
- Class parameterTypes [] = new Class[arguments];
- for (int i = 0; i < arguments; i++) {
- if (args[i] == null) {
- throw new IllegalArgumentException("The arguments must not be null. Index " + i + " was null.");
- }
- parameterTypes[i] = args[i].getClass();
- }
- return invokeMethod(objectToInvoke, 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 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 object invoke method on this object
- * @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
- *
- * @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
- */
- public static Object invokeMethod(
- Object object,
- String methodName,
- Object[] args,
- Class[] parameterTypes)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
-
- if (parameterTypes == null) {
- parameterTypes = emptyClassArray;
- }
- if (args == null) {
- args = emptyObjectArray;
- }
-
- Method method = getMatchingAccessibleMethod(
- object.getClass(),
- methodName,
- parameterTypes);
- if (method == null)
- 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>
- *
- * <p> This is a convenient wrapper for
- * {@link #invokeExactMethod(Object object,String methodName,Object [] args)}.
- * </p>
- *
- * @param object invoke method on this object
- * @param methodName get method with this name
- * @param arg use this argument
- *
- * @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
- */
- public static Object invokeExactMethod(
- Object object,
- String methodName,
- Object arg)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
-
- Object[] args = {arg};
- return invokeExactMethod(object, methodName, args);
-
- }
-
-
- /**
- * <p>Invoke a method whose parameter types match exactly the object
- * types.</p>
- *
- * <p> This uses reflection to invoke the method obtained from a call to
- * {@link #getAccessibleMethod}.</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
- *
- * @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
- */
- public static Object invokeExactMethod(
- Object object,
- String methodName,
- Object[] args)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
- if (args == null) {
- args = emptyObjectArray;
- }
- 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>
- *
- * <p>This uses reflection to invoke the method obtained from a call to
- * {@link #getAccessibleMethod}.</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
- * @param parameterTypes match these parameters - treat null as empty array
- *
- * @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
- */
- public static Object invokeExactMethod(
- Object object,
- String methodName,
- Object[] args,
- Class[] parameterTypes)
- throws
- NoSuchMethodException,
- IllegalAccessException,
- InvocationTargetException {
-
- if (args == null) {
- args = emptyObjectArray;
- }
-
- if (parameterTypes == null) {
- parameterTypes = emptyClassArray;
- }
-
- Method method = getAccessibleMethod(
- object.getClass(),
- methodName,
- parameterTypes);
- if (method == null)
- throw new NoSuchMethodException("No such accessible method: " +
- methodName + "() on object: " + object.getClass().getName());
- return method.invoke(object, args);
-
- }
-
-
- /**
- * <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);
- }
-
- }
-
-
- /**
- * <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) {
-
- // 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 the declaring class is public, we are done
- Class clazz = method.getDeclaringClass();
- if (Modifier.isPublic(clazz.getModifiers())) {
- return (method);
- }
-
- // Check the implemented interfaces and subinterfaces
- String methodName = method.getName();
- Class[] parameterTypes = method.getParameterTypes();
- method =
- 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
- * all implemented interfaces and subinterfaces. If no such method
- * can be found, return <code>null</code>.</p>
- *
- * <p> There isn't any good reason why this method must be private.
- * 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 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[]) {
-
- Method method = null;
-
- // Search up the superclass chain
- for (; clazz != null; clazz = clazz.getSuperclass()) {
-
- // Check the implemented interfaces of the parent class
- Class interfaces[] = clazz.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) {
- ;
- }
- if (method != null)
- break;
-
- // Recursively check our parent interfaces
- 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);
-
- }
-
- /**
- * <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>
+ * Produces nicely formatted informational error messages for reflection errors.
*
- * <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(
- Class clazz,
- String methodName,
- Class[] parameterTypes) {
- // trace logging
- if (log.isTraceEnabled()) {
- log.trace("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);
- return method;
-
- } catch (NoSuchMethodException e) { /* SWALLOW */ }
-
- // search through all methods
- int paramSize = parameterTypes.length;
- Method[] methods = clazz.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]);
- }
- return method;
- }
-
- log.trace("Couldn't find accessible method.");
- }
- }
- }
- }
-
- // didn't find a match
- log.trace("No match found.");
- return null;
- }
-
- /**
- * <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.
- */
- private static final boolean isAssignmentCompatible(Class parameterType, Class parameterization) {
- // try plain assignment
- if (parameterType.isAssignableFrom(parameterization)) {
- return true;
- }
-
- if (parameterType.isPrimitive()) {
- // does anyone know a better strategy than comparing names?
- // also, this method does *not* do widening - you must specify exactly
- // is this the right behaviour?
- if (boolean.class.equals(parameterType)) {
- return Boolean.class.equals(parameterization);
- }
- if (float.class.equals(parameterType)) {
- return Float.class.equals(parameterization);
- }
- if (long.class.equals(parameterType)) {
- return Long.class.equals(parameterization);
- }
- if (int.class.equals(parameterType)) {
- return Integer.class.equals(parameterization);
- }
- if (double.class.equals(parameterType)) {
- return Double.class.equals(parameterization);
- }
- }
-
- return false;
- }
-
- /**
- * Gets the Field for the specified parameters.
- *
- * @return java.lang.reflect.Field
- * @param cls java.lang.Class
- * @param fieldName java.lang.String
+ * @param th the throwable
+ * @param desc the short description of the action, such as 'getting field'
+ * @param className the class name being used
+ * @param types the parameter types
+ * @param memberName the name of the field or method
+ * @return a suitable error message
*/
- public static Field getField(Class cls, String fieldName) throws ReflectionException {
-
- try {
- return cls.getDeclaredField(fieldName);
-
- } catch (NullPointerException ex) {
- throw new ReflectionException(ex, "The class cannot be null");
- } catch (NoSuchFieldException ex) {
- throw new ReflectionException(ex, "The field '" + fieldName + "' does not exist on " + cls.getName());
- }
- }
- /**
- * Gets the value of the field on the object
- * @return java.lang.Object
- * @param cls java.lang.Class
- * @param fieldName java.lang.String
- * @param calledObj java.lang.Object
- */
- public static Object getFieldValue(Class cls, String fieldName, Object calledObject) throws ReflectionException {
-
- try {
- return cls.getDeclaredField(fieldName).get(calledObject);
-
- } catch (IllegalAccessException ex) {
- throw new ReflectionException(ex, "The field cannot be accessed");
- } catch (NullPointerException ex) {
- throw new ReflectionException(ex, "The class cannot be null");
- } catch (NoSuchFieldException ex) {
- throw new ReflectionException(ex, "The field '" + fieldName + "' does not exist on " + cls.getName());
- }
- }
- /**
- * Gets the Method for the specified parameters. The method to be searched
- * for has no parameters.
- * @return java.lang.reflect.Method
- * @param cls java.lang.Class
- * @param methodName java.lang.String
- */
- public static Method getMethod(Class cls, String methodName) throws ReflectionException {
-
- return Reflection.getMethod(cls, methodName, (Class[]) null);
- }
- /**
- * Gets the Method for the specified parameters.
- * @return java.lang.reflect.Method
- * @param cls java.lang.Class
- * @param methodName java.lang.String
- * @param types java.lang.Class[]
- */
- public static Method getMethod(Class cls, String methodName, Class[] types) throws ReflectionException {
-
- if ((methodName == null) || (methodName.length() == 0)) {
- throw new ReflectionException(new IllegalArgumentException(), "Method name cannot be null");
- }
-
- try {
- return cls.getMethod(methodName, types);
-
- } catch (NullPointerException ex) {
- throw new ReflectionException(ex, "The Class cannot be null");
- } catch (NoSuchMethodException ex) {
- throw new ReflectionException(ex, "The Method '" + methodName + "' does not exist");
- } catch (SecurityException ex) {
- throw new ReflectionException(ex);
- }
- }
- /**
- * Gets the Method for the specified parameters. The method to be searched
- * for has no parameters.
- * @return java.lang.reflect.Method
- * @param className java.lang.String
- * @param methodName java.lang.String
- */
- public static Method getMethod(String className, String methodName) throws ReflectionException {
-
- return Reflection.getMethod(getClass(className), methodName);
- }
- /**
- * Gets the Method for the specified parameters.
- * @return java.lang.reflect.Method
- * @param className java.lang.String
- * @param methodName java.lang.String
- * @param types java.lang.Class[]
- */
- public static Method getMethod(String className, String methodName, Class[] types) throws ReflectionException {
-
- return Reflection.getMethod(getClass(className), methodName, types);
- }
-
- /**
- * Invoke a method with no parameters.
- */
- public static Object invokeMethod(Method mth, Object obj) throws IllegalArgumentException, ReflectionException {
-
- return Reflection.invokeMethod(mth, obj, (Object[]) null);
- }
- /**
- * Invoke a method.
- */
- public static Object invokeMethod(Method mth, Object obj, Object[] args)
- throws IllegalArgumentException, ReflectionException {
-
- try {
- return mth.invoke(obj, args); // Handles statics OK as well.
-
- } catch (NullPointerException ex) {
- throw new ReflectionException(ex, "The Method cannot be null");
- } catch (InvocationTargetException ex) {
- throw new ReflectionException(ex, "The Method '" + mth + "' threw an exception");
- } catch (IllegalAccessException ex) {
- throw new ReflectionException(ex, "The Method '" + mth + "' is not public");
- }
- }
- /**
- * Invoke a method with no parameters.
- */
- public static Object invokeMethod(String methodName, Object obj)
- throws IllegalArgumentException, ReflectionException {
-
- Method mth = Reflection.getMethod(obj.getClass(), methodName);
-
- return Reflection.invokeMethod(mth, obj);
- }
- /**
- * Invoke a method.
- */
- public static Object invokeMethod(String methodName, Object obj, Class[] types, Object[] args)
- throws IllegalArgumentException, ReflectionException {
-
- Method mth = Reflection.getMethod(obj.getClass(), methodName, types);
-
- return Reflection.invokeMethod(mth, obj, args);
- }
- /**
- * Tests whether the specified field is a static or not
- * @return boolean
- * @param mth java.lang.reflect.Field
- */
- public static boolean isStatic(Field fld) {
-
- return Modifier.isStatic(fld.getModifiers());
- }
- /**
- * Tests whether the specified method is a static or not
- * @return boolean
- * @param mth java.lang.reflect.Method
- */
- public static boolean isStatic(Method mth) {
-
- return Modifier.isStatic(mth.getModifiers());
- }
- /**
- * Gets a list of all interfaces implemented by the given class.
- * @return the list of interfaces
- * @param cls the class to look up
- */
- public static List getAllInterfaces(Class cls) {
- if (cls == null) {
- return new ArrayList();
- }
- Set classes = new HashSet();
- Class[] interfaces = cls.getInterfaces();
- for (int i = 0; i < interfaces.length; i++) {
- classes.add(interfaces[i]);
- classes.addAll(getAllInterfaces(interfaces[i]));
- }
- classes.addAll(getAllInterfaces(cls.getSuperclass()));
- return new ArrayList(classes);
- }
-
- /**
- * Gets a list of super classes for the given class.
- * @return the list of classes
- * @param cls the class to look up
- */
- public static List getAllSuperClasses(Class cls) {
- List classes = new ArrayList();
- if (cls != null) {
- Class superClass = cls.getSuperclass();
- if (superClass != null) {
- classes.add(superClass);
- classes.addAll(getAllSuperClasses(superClass));
- }
- }
- return classes;
- }
-
- /**
- * Given a list of classes, this method finds all those which are
- * subclasses or implementations of a specified super class
- * @return the list of subclasses or implementors
- * @param classes the classes to check
- * @param superClass the super class to check for
- */
- public static List getAllSubclasses(List classes, Class superClass) {
- List clsss = new ArrayList();
- Iterator it = classes.iterator();
- while (it.hasNext()) {
- Class cls = (Class) it.next();
- if (superClass.isAssignableFrom(cls)) {
- clsss.add(cls);
- }
- }
- return clsss;
- }
-
- /**
- * Get the array of types for error messages
- */
- static String getClassArrayString(Class[] array) {
- return array == null ? "{}" : ArrayUtils.toString(array);
- }
-
- /**
- * Produce nice error messages
- */
- static String getThrowableText(Throwable th, String desc, String className, Class[] types, String methodName) {
+ public static String getThrowableText(Throwable th, String desc, String className, Class[] types, String memberName) {
String message = null;
try {
throw th;
- } catch (ExceptionInInitializerError ex) {
- message = "the class initialization threw an exception";
- } catch (InvocationTargetException ex) {
- message = "the method threw an exception";
} catch (NoSuchMethodException ex) {
message = "the method does not exist";
+ } catch (NoSuchFieldException ex) {
+ message = "the field does not exist";
+ } catch (ClassNotFoundException ex) {
+ message = "the class could not be found in the classpath";
+ } catch (InvocationTargetException ex) {
+ message = "the method threw an exception";
} catch (InstantiationException ex) {
message = "the class is abstract/interface/array/primitive";
} catch (IllegalAccessException ex) {
@@ -1019,12 +218,28 @@
} catch (IllegalArgumentException ex) {
message = "the parameters did not match those expected";
} catch (SecurityException ex) {
- message = "the security manager is blocking reflection";
+ message = "the security manager prevents reflection";
+ } catch (ExceptionInInitializerError ex) {
+ message = "the class initialization for static variables threw an exception";
+ } catch (ClassCircularityError ex) {
+ message = "a circularity has been detected while initializing a class";
+ } catch (ClassFormatError ex) {
+ message = "the class file is malformed or otherwise cannot be interpreted as a class";
+ } catch (IncompatibleClassChangeError ex) {
+ message = "the method references another class that has changed incompatibly since compile time";
+ } catch (UnsatisfiedLinkError ex) {
+ message = "no implementation found for a native method";
+ } catch (VerifyError ex) {
+ message = "the class file contains an internal inconsistency or security problem";
+ } catch (NoClassDefFoundError ex) {
+ message = "the class references another class that was present at compile time but is no longer available";
+ } catch (LinkageError ex) {
+ message = "the class references another class that has changed incompatibly since compile time";
} catch (Throwable ex) {
message = null;
}
StringBuffer buf = new StringBuffer();
- buf.append(ReflectionUtils.getShortClassName(th));
+ buf.append(ClassUtils.getShortClassName(th));
buf.append(" while ");
buf.append(desc);
buf.append(" on Class '");
@@ -1032,11 +247,11 @@
buf.append("'");
if (types != null) {
buf.append(" for types ");
- buf.append(ReflectionUtils.getClassArrayString(types));
+ buf.append(ArrayUtils.toString(types));
}
- if (methodName != null) {
+ if (memberName != null) {
buf.append(" for method '");
- buf.append(methodName);
+ buf.append(memberName);
buf.append("'");
}
if (message != null) {
1.1 jakarta-commons-sandbox/lang/FieldUtils.java
Index: FieldUtils.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* <code>FieldUtils</code> contains utility methods for working with
* fields by reflection.
* <p>
* The ability is provided to break the scoping restrictions coded by the
* programmer. This can allow fields to be changed that shouldn't be. This
* facility should be used with care.
*
* @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
* @version $Id: FieldUtils.java,v 1.1 2002/09/21 13:36:02 scolebourne Exp $
*/
public class FieldUtils {
/** An empty field array */
public static final Field[] EMPTY_FIELD_ARRAY = new Field[0];
/**
* FieldUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as <code>FieldUtils.getField(cls, name)</code>.
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public FieldUtils() {
}
// -------------------------------------------------------------------------
/**
* Gets a Field by name. The field must be public.
* Superclasses will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Field getField(Class cls, String fieldName) {
return getField(cls, fieldName, false);
}
/**
* Gets a Field by name.
* Superclasses will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @param breakScope whether to break scope restrictions using the
* <code>setAccessible</code> method. False will only match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Field getField(Class cls, String fieldName, boolean breakScope) {
if (cls == null) {
throw new IllegalArgumentException("The class must not be null");
}
if (fieldName == null) {
throw new IllegalArgumentException("The field name must not be null");
}
try {
if (breakScope) {
Class acls = cls;
while (acls != null) {
Field[] fields = acls.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(fieldName)) {
if (Modifier.isPublic(fields[i].getModifiers())) {
fields[i].setAccessible(true);
}
return fields[i];
}
}
acls = acls.getSuperclass();
}
throw new NoSuchFieldException("The field '" + fieldName + "' could not be found");
} else {
return cls.getField(fieldName);
}
} catch (ReflectionException ex) {
throw ex;
} catch (LinkageError ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
ex, "getting field", cls.getName(), null, fieldName), ex);
} catch (Exception ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
ex, "getting field", cls.getName(), null, fieldName), ex);
}
}
// -------------------------------------------------------------------------
/**
* Gets a Field by name. The field must be public.
* Only the specified class will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Field getFieldExact(Class cls, String fieldName) {
return getFieldExact(cls, fieldName, false);
}
/**
* Gets a Field by name.
* Only the specified class will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @param breakScope whether to break scope restrictions using the
* <code>setAccessible</code> method. False will only match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Field getFieldExact(Class cls, String fieldName, boolean breakScope) {
if (cls == null) {
throw new IllegalArgumentException("The class must not be null");
}
if (fieldName == null) {
throw new IllegalArgumentException("The field name must not be null");
}
try {
if (breakScope) {
Field field = cls.getDeclaredField(fieldName);
if (Modifier.isPublic(field.getModifiers())) {
field.setAccessible(true);
}
return field;
} else {
Field field = cls.getField(fieldName);
if (field.getDeclaringClass() != cls) {
throw new NoSuchFieldException("The field '" + fieldName + "' was not found in the specified class, although it was found in a superclass");
}
return field;
}
} catch (ReflectionException ex) {
throw ex;
} catch (LinkageError ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
ex, "getting field", cls.getName(), null, fieldName), ex);
} catch (Exception ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
ex, "getting field", cls.getName(), null, fieldName), ex);
}
}
// -------------------------------------------------------------------------
/**
* Gets a static Field value from a Field object.
*
* @param field the field to use
* @return the field value
* @throws IllegalArgumentException if the field is null or not static
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getStaticFieldValue(Field field) {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
if (Modifier.isStatic(field.getModifiers()) == false) {
throw new IllegalArgumentException("The field '" + field.getName() + "' is not static");
}
return getFieldValue(field, (Object) null, false);
}
/**
* Gets a static Field value from a Field object.
*
* @param field the field to use
* @param breakScope whether to break scope restrictions using the
* <code>setAccessible</code> method. False will only match public methods.
* @return the field value
* @throws IllegalArgumentException if the field is null or not static
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getStaticFieldValue(Field field, boolean breakScope) {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
if (Modifier.isStatic(field.getModifiers()) == false) {
throw new IllegalArgumentException("The field '" + field.getName() + "' is not static");
}
return getFieldValue(field, (Object) null, breakScope);
}
/**
* Gets a Field value from a Field object.
*
* @param field the field to use
* @param object the object to call on, may be null for static fields
* @return the field value
* @throws IllegalArgumentException if the field is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getFieldValue(Field field, Object object) {
return getFieldValue(field, object, false);
}
/**
* Gets a Field value from a Field object.
*
* @param field the field to use
* @param object the object to call on, may be null for static fields
* @param breakScope whether to break scope restrictions using the
* <code>setAccessible</code> method. False will only match public methods.
* @return the field value
* @throws IllegalArgumentException if the field is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getFieldValue(Field field, Object object, boolean breakScope) {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
try {
if (breakScope && Modifier.isPublic(field.getModifiers()) == false) {
field.setAccessible(true);
}
return field.get(object);
} catch (ReflectionException ex) {
throw ex;
} catch (LinkageError ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
ex, "getting field value", field.getDeclaringClass().getName(), null, field.getName()), ex);
} catch (Exception ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
ex, "getting field value", field.getDeclaringClass().getName(), null, field.getName()), ex);
}
}
// -------------------------------------------------------------------------
/**
* Gets a static Field value by name. The field must be public.
* Superclasses will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @return the value of the field
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getStaticFieldValue(Class cls, String fieldName) {
return getStaticFieldValue(cls, fieldName, false);
}
/**
* Gets a static Field value by name.
* Only the specified class will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @param breakScope whether to break scope restrictions using the
* <code>setAccessible</code> method. False will only match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getStaticFieldValue(Class cls, String fieldName, boolean breakScope) {
try {
Field field = getField(cls, fieldName, breakScope);
if (Modifier.isStatic(field.getModifiers()) == false) {
throw new NoSuchMethodException("The field '" + fieldName + "' is not static");
}
return getStaticFieldValue(field, breakScope);
} catch (ReflectionException ex) {
throw ex;
} catch (LinkageError ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
ex, "getting field value", cls.getName(), null, fieldName), ex);
} catch (Exception ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
ex, "getting field value", cls.getName(), null, fieldName), ex);
}
}
// -------------------------------------------------------------------------
/**
* Gets a static Field value by name. The field must be public.
* Only the specified class will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @return the value of the field
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getStaticFieldValueExact(Class cls, String fieldName) {
return getStaticFieldValueExact(cls, fieldName, false);
}
/**
* Gets a static Field value by name.
* Only the specified class will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @param breakScope whether to break scope restrictions using the
* <code>setAccessible</code> method. False will only match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getStaticFieldValueExact(Class cls, String fieldName, boolean breakScope) {
try {
Field field = getFieldExact(cls, fieldName, breakScope);
if (Modifier.isStatic(field.getModifiers()) == false) {
throw new NoSuchMethodException("The field '" + fieldName + "' is not static");
}
return getStaticFieldValue(field, breakScope);
} catch (ReflectionException ex) {
throw ex;
} catch (LinkageError ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
ex, "getting field value", cls.getName(), null, fieldName), ex);
} catch (Exception ex) {
throw new ReflectionException(ReflectionUtils.getThrowableText(
ex, "getting field value", cls.getName(), null, fieldName), ex);
}
}
// -------------------------------------------------------------------------
/**
* Gets a Field value by name. The field must be public.
* Superclasses will be considered.
*
* @param object the object to reflect, must not be null
* @param fieldName the field name to obtain
* @return the value of the field
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getFieldValue(Object object, String fieldName) {
return getFieldValue(object, fieldName, false);
}
/**
* Gets a Field value by name.
* Only the specified class will be considered.
*
* @param object the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param breakScope whether to break scope restrictions using the
* <code>setAccessible</code> method. False will only match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getFieldValue(Object object, String fieldName, boolean breakScope) {
Field field = getField(object.getClass(), fieldName, breakScope);
return getFieldValue(field, object, breakScope);
}
// -------------------------------------------------------------------------
/**
* Gets a Field value by name. The field must be public.
* Only the class of the specified object will be considered.
*
* @param object the object to reflect, must not be null
* @param fieldName the field name to obtain
* @return the value of the field
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getFieldValueExact(Object object, String fieldName) {
return getFieldValueExact(object, fieldName, false);
}
/**
* Gets a Field value by name.
* Only the class of the specified object will be considered.
*
* @param object the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param breakScope whether to break scope restrictions using the
* <code>setAccessible</code> method. False will only match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws ReflectionException if an error occurs during reflection
*/
public static Object getFieldValueExact(Object object, String fieldName, boolean breakScope) {
Field field = getFieldExact(object.getClass(), fieldName, breakScope);
return getFieldValue(field, object, breakScope);
}
}
1.1 jakarta-commons-sandbox/lang/MethodUtils.java
Index: MethodUtils.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
/**
* <code>MethodUtils</code> contains utility methods for working for
* methods by reflection.
* <p>
* The ability is provided to break the scoping restrictions coded by the
* programmer. This can break an implementation if used incorrectly. This
* facility should be used with care.
*
* @author Based on code from BeanUtils
* @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
* @version $Id: MethodUtils.java,v 1.1 2002/09/21 13:36:02 scolebourne Exp $
*/
public class MethodUtils {
//
// WORK IN PROGRESS - DOESN't COMPILE
//
/** An empty method array */
public static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
/**
* MethodUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as <code>MethodUtils.getMethod(cls, name)</code>.
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public MethodUtils() {
}
// -------------------------------------------------------------------------
/**
* <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}.
* It loops through all methods with names that match
* and then executes the first it finds with compatable parameters.</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>
*
* <p> This is a convenient wrapper for
* {@link #invokeMethod(Object object,String methodName,Object [] args)}.
* </p>
*
* @param objectToInvoke invoke method on this object, must not be null
* @param methodName get method with this name, must not be null
* @param arg use this argument, must not be null
*
* @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 IllegalArgumentException if any parameter is null
*/
public static Object invokeMethod(
Object objectToInvoke,
String methodName,
Object arg)
throws
NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
if (objectToInvoke == null) {
throw new IllegalArgumentException("The object to invoke must not be null");
}
if (methodName == null) {
throw new IllegalArgumentException("The method name must not be null");
}
if (arg == null) {
throw new IllegalArgumentException("The argument must not be null");
}
Object[] args = {arg};
return invokeMethod(objectToInvoke, methodName, args);
}
/**
* <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 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>
*
* <p> This is a convenient wrapper for
* {@link #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
* </p>
*
* @param objectToInvoke invoke method on this object, must not be null
* @param methodName get method with this name, must not be null
* @param args use these arguments - treat null as empty array
*
* @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 IllegalArgumentException if the objectToInvoke, methodName or any argument is null
*/
public static Object invokeMethod(
Object objectToInvoke,
String methodName,
Object[] args)
throws
NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
if (objectToInvoke == null) {
throw new IllegalArgumentException("The object to invoke must not be null");
}
if (methodName == null) {
throw new IllegalArgumentException("The method name must not be null");
}
if (args == null) {
return invokeMethod(objectToInvoke, methodName, null, null);
} else {
int arguments = args.length;
Class parameterTypes [] = new Class[arguments];
for (int i = 0; i < arguments; i++) {
if (args[i] == null) {
throw new IllegalArgumentException("The arguments must not be null. Index " + i + " was null.");
}
parameterTypes[i] = args[i].getClass();
}
return invokeMethod(objectToInvoke, 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 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 object invoke method on this object
* @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
*
* @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
*/
public static Object invokeMethod(
Object object,
String methodName,
Object[] args,
Class[] parameterTypes)
throws
NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
if (parameterTypes == null) {
parameterTypes = emptyClassArray;
}
if (args == null) {
args = emptyObjectArray;
}
Method method = getMatchingAccessibleMethod(
object.getClass(),
methodName,
parameterTypes);
if (method == null)
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>
*
* <p> This is a convenient wrapper for
* {@link #invokeExactMethod(Object object,String methodName,Object [] args)}.
* </p>
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param arg use this argument
*
* @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
*/
public static Object invokeExactMethod(
Object object,
String methodName,
Object arg)
throws
NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
Object[] args = {arg};
return invokeExactMethod(object, methodName, args);
}
/**
* <p>Invoke a method whose parameter types match exactly the object
* types.</p>
*
* <p> This uses reflection to invoke the method obtained from a call to
* {@link #getAccessibleMethod}.</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
*
* @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
*/
public static Object invokeExactMethod(
Object object,
String methodName,
Object[] args)
throws
NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
if (args == null) {
args = emptyObjectArray;
}
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>
*
* <p>This uses reflection to invoke the method obtained from a call to
* {@link #getAccessibleMethod}.</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
* @param parameterTypes match these parameters - treat null as empty array
*
* @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
*/
public static Object invokeExactMethod(
Object object,
String methodName,
Object[] args,
Class[] parameterTypes)
throws
NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
if (args == null) {
args = emptyObjectArray;
}
if (parameterTypes == null) {
parameterTypes = emptyClassArray;
}
Method method = getAccessibleMethod(
object.getClass(),
methodName,
parameterTypes);
if (method == null)
throw new NoSuchMethodException("No such accessible method: " +
methodName + "() on object: " + object.getClass().getName());
return method.invoke(object, args);
}
/**
* <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);
}
}
/**
* <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) {
// 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 the declaring class is public, we are done
Class clazz = method.getDeclaringClass();
if (Modifier.isPublic(clazz.getModifiers())) {
return (method);
}
// Check the implemented interfaces and subinterfaces
String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes();
method =
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
* all implemented interfaces and subinterfaces. If no such method
* can be found, return <code>null</code>.</p>
*
* <p> There isn't any good reason why this method must be private.
* 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 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[]) {
Method method = null;
// Search up the superclass chain
for (; clazz != null; clazz = clazz.getSuperclass()) {
// Check the implemented interfaces of the parent class
Class interfaces[] = clazz.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) {
;
}
if (method != null)
break;
// Recursively check our parent interfaces
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);
}
/**
* <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(
Class clazz,
String methodName,
Class[] parameterTypes) {
// trace logging
if (log.isTraceEnabled()) {
log.trace("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);
return method;
} catch (NoSuchMethodException e) { /* SWALLOW */ }
// search through all methods
int paramSize = parameterTypes.length;
Method[] methods = clazz.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]);
}
return method;
}
log.trace("Couldn't find accessible method.");
}
}
}
}
// didn't find a match
log.trace("No match found.");
return null;
}
/**
* <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.
*/
private static final boolean isAssignmentCompatible(Class parameterType, Class parameterization) {
// try plain assignment
if (parameterType.isAssignableFrom(parameterization)) {
return true;
}
if (parameterType.isPrimitive()) {
// does anyone know a better strategy than comparing names?
// also, this method does *not* do widening - you must specify exactly
// is this the right behaviour?
if (boolean.class.equals(parameterType)) {
return Boolean.class.equals(parameterization);
}
if (float.class.equals(parameterType)) {
return Float.class.equals(parameterization);
}
if (long.class.equals(parameterType)) {
return Long.class.equals(parameterization);
}
if (int.class.equals(parameterType)) {
return Integer.class.equals(parameterization);
}
if (double.class.equals(parameterType)) {
return Double.class.equals(parameterization);
}
}
return false;
}
// -------------------------------------------------------------------------
/**
* Gets the Method for the specified parameters. The method to be searched
* for has no parameters.
* @return java.lang.reflect.Method
* @param cls java.lang.Class
* @param methodName java.lang.String
*/
public static Method getMethod(Class cls, String methodName) throws ReflectionException {
return Reflection.getMethod(cls, methodName, (Class[]) null);
}
/**
* Gets the Method for the specified parameters.
* @return java.lang.reflect.Method
* @param cls java.lang.Class
* @param methodName java.lang.String
* @param types java.lang.Class[]
*/
public static Method getMethod(Class cls, String methodName, Class[] types) throws ReflectionException {
if ((methodName == null) || (methodName.length() == 0)) {
throw new ReflectionException(new IllegalArgumentException(), "Method name cannot be null");
}
try {
return cls.getMethod(methodName, types);
} catch (NullPointerException ex) {
throw new ReflectionException(ex, "The Class cannot be null");
} catch (NoSuchMethodException ex) {
throw new ReflectionException(ex, "The Method '" + methodName + "' does not exist");
} catch (SecurityException ex) {
throw new ReflectionException(ex);
}
}
/**
* Gets the Method for the specified parameters. The method to be searched
* for has no parameters.
* @return java.lang.reflect.Method
* @param className java.lang.String
* @param methodName java.lang.String
*/
public static Method getMethod(String className, String methodName) throws ReflectionException {
return Reflection.getMethod(getClass(className), methodName);
}
/**
* Gets the Method for the specified parameters.
* @return java.lang.reflect.Method
* @param className java.lang.String
* @param methodName java.lang.String
* @param types java.lang.Class[]
*/
public static Method getMethod(String className, String methodName, Class[] types) throws ReflectionException {
return Reflection.getMethod(getClass(className), methodName, types);
}
/**
* Invoke a method with no parameters.
*/
public static Object invokeMethod(Method mth, Object obj) throws IllegalArgumentException, ReflectionException {
return Reflection.invokeMethod(mth, obj, (Object[]) null);
}
/**
* Invoke a method.
*/
public static Object invokeMethod(Method mth, Object obj, Object[] args)
throws IllegalArgumentException, ReflectionException {
try {
return mth.invoke(obj, args); // Handles statics OK as well.
} catch (NullPointerException ex) {
throw new ReflectionException(ex, "The Method cannot be null");
} catch (InvocationTargetException ex) {
throw new ReflectionException(ex, "The Method '" + mth + "' threw an exception");
} catch (IllegalAccessException ex) {
throw new ReflectionException(ex, "The Method '" + mth + "' is not public");
}
}
/**
* Invoke a method with no parameters.
*/
public static Object invokeMethod(String methodName, Object obj)
throws IllegalArgumentException, ReflectionException {
Method mth = Reflection.getMethod(obj.getClass(), methodName);
return Reflection.invokeMethod(mth, obj);
}
/**
* Invoke a method.
*/
public static Object invokeMethod(String methodName, Object obj, Class[] types, Object[] args)
throws IllegalArgumentException, ReflectionException {
Method mth = Reflection.getMethod(obj.getClass(), methodName, types);
return Reflection.invokeMethod(mth, obj, args);
}
// -------------------------------------------------------- Private Methods
/**
* <p>Return an accessible method (that is, one that can be invoked via
* reflection) that implements the specified method, by scanning through
* all implemented interfaces and subinterfaces. If no such method
* can be found, return <code>null</code>.</p>
*
* <p> There isn't any good reason why this method must be private.
* 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 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[]) {
Method method = null;
// Search up the superclass chain
for (; clazz != null; clazz = clazz.getSuperclass()) {
// Check the implemented interfaces of the parent class
Class interfaces[] = clazz.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) {
;
}
if (method != null)
break;
// Recursively check our parent interfaces
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);
}
/**
* <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(
Class clazz,
String methodName,
Class[] parameterTypes) {
// trace logging
if (log.isTraceEnabled()) {
log.trace("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);
return method;
} catch (NoSuchMethodException e) { /* SWALLOW */ }
// search through all methods
int paramSize = parameterTypes.length;
Method[] methods = clazz.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]);
}
return method;
}
log.trace("Couldn't find accessible method.");
}
}
}
}
// didn't find a match
log.trace("No match found.");
return null;
}
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>