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>