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/20 01:02:51 UTC

cvs commit: jakarta-commons-sandbox/lang ConstructorUtils.java ArrayUtils.java ReflectionException.java ReflectionUtils.java

scolebourne    2002/09/19 16:02:51

  Added:       lang     ConstructorUtils.java ArrayUtils.java
                        ReflectionException.java ReflectionUtils.java
  Log:
  Initial versions of reflection code
  
  Revision  Changes    Path
  1.1                  jakarta-commons-sandbox/lang/ConstructorUtils.java
  
  Index: ConstructorUtils.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.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.
   *
   * @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
   * @version $Id: ConstructorUtils.java,v 1.1 2002/09/19 23:02:51 scolebourne Exp $
   */
  public class ConstructorUtils {
  
      /** An empty class array */
      public static final Constructor[] EMPTY_CONSTRUCTOR_ARRAY = new Constructor[0];
      
      /**
       * ConstructorUtils instances should NOT be constructed in standard programming.
       * Instead, the class should be used as <code>ConstructorUtils.newInstance(...)</code>.
       * This constructor is public to permit tools that require a JavaBean instance
       * to operate.
       */
      public ConstructorUtils() {
      }
  
      // -------------------------------------------------------------------------
      
      /**
       * Gets a public <code>Constructor</code> object by exactly matching the
       * parameter types.
       *
       * @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 getConstructorExact(Class cls, Class[] types) {
          return getConstructorExact(cls, types, true);
      }
      
      /**
       * Gets a <code>Constructor</code> object by exactly matching the
       * parameter types.
       *
       * @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
       * @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) {
          if (cls == null) {
              throw new IllegalArgumentException("The class must not be null");
          }
          try {
              if (publicOnly) {
                  return cls.getConstructor(types);
              } else {
                  Constructor con = cls.getDeclaredConstructor(types);
                  if (Modifier.isPublic(con.getModifiers()) == false) {
                      con.setAccessible(true);
                  }
                  return con;
              }
  
          } catch (Throwable th) {
              throw new ReflectionException(ReflectionUtils.getThrowableText(
                  th, "invoking constructor", cls.getName(), types, null), th);
          }
      }
      
      // -------------------------------------------------------------------------
      
      /**
       * Creates a new instance using a <code>Constructor</code> and parameters.
       * 
       * @param con  Class object to find constructor for, must not be null
       * @param param  the single parameter to pass to the constructor, may be null
       * @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 param) {
          return newInstance(con, new Object[] {param}, true);
      }
      
      /**
       * Creates a new instance using a <code>Constructor</code> and parameters.
       * 
       * @param con  Class object to find constructor for, must not 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 constructor is null
       */
      public static Object newInstance(Constructor con, Object[] params) {
          return newInstance(con, params, true);
      }
      
      /**
       * Creates a new instance using a <code>Constructor</code> and parameters.
       * 
       * @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
       * @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) {
          if (con == null) {
              throw new IllegalArgumentException("The constructor must not be null");
          }
          try {
              if (publicOnly == false && Modifier.isPublic(con.getModifiers()) == false) {
                  con.setAccessible(true);
              }
              return con.newInstance(params);
      
          } catch (Throwable th) {
              throw new ReflectionException(ReflectionUtils.getThrowableText(
                  th, "invoking constructor", con.getDeclaringClass().getName(), con.getParameterTypes(), null), th);
          }
      }
      
      // -------------------------------------------------------------------------
      
      /**
       * Creates a new instance of the specified <code>Class</code> by name.
       * 
       * @param className  String class name to instantiate, must not be empty
       * @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) {
          return newInstance(className, true);
      }
      
      /**
       * Creates a new instance of the specified <code>Class</code> by name.
       * If the constructor is not public, <code>setAccessible(true)</code>
       * 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
       * @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) {
          Class cls = ReflectionUtils.getClass(className);
          return ConstructorUtils.newInstance(cls, publicOnly);
      }
      
      // -------------------------------------------------------------------------
      
      /**
       * Creates a new instance of the specified <code>Class</code>.
       * 
       * @param cls  Class object to instantiate, must not 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) {
          return newInstance(cls, true);
      }
      
      /**
       * 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.
       * 
       * @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
       * @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) {
              if (cls == null) {
                  throw new IllegalArgumentException("The constructor must not be null");
              }
              try {
                  return cls.newInstance();
          
              } catch (Throwable th) {
                  throw new ReflectionException(ReflectionUtils.getThrowableText(
                      th, "instantiating class", cls.getName(), null, null), th);
              }
          } else {
              Constructor con = ConstructorUtils.getConstructorExact(cls, null, publicOnly);
              return ConstructorUtils.newInstance(con, null, publicOnly);
          }
      }
      
      // -------------------------------------------------------------------------
      
      /**
       * Creates a new instance of the specified <code>Class</code>.
       * 
       * @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 newInstanceExact(Class cls, Class[] types, Object[] params) {
          return newInstanceExact(cls, types, params, true);
      }
      
      /**
       * 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.
       * 
       * @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
       * @return the newly created object
       * @throws ReflectionException if an error occurs during reflection
       * @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);
      }
      
      // -------------------------------------------------------------------------
      
  }
  
  
  
  1.1                  jakarta-commons-sandbox/lang/ArrayUtils.java
  
  Index: ArrayUtils.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 org.apache.commons.lang.builder.ToStringBuilder;
  import org.apache.commons.lang.builder.ToStringStyle;
  /**
   * <code>ArrayUtils</code> contains utility methods for working for
   * arrays.
   *
   * @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
   * @version $Id: ArrayUtils.java,v 1.1 2002/09/19 23:02:51 scolebourne Exp $
   */
  public class ArrayUtils {
  
      /** An empty immutable object array */
      public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
      /** An empty immutable class array */
      public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
      /** An empty immutable string array */
      public static final String[] EMPTY_STRING_ARRAY = new String[0];
      /** An empty immutable long array */
      public static final long[] EMPTY_LONG_ARRAY = new long[0];
      /** An empty immutable int array */
      public static final int[] EMPTY_INT_ARRAY = new int[0];
      /** An empty immutable short array */
      public static final short[] EMPTY_SHORT_ARRAY = new short[0];
      /** An empty immutable byte array */
      public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
      /** An empty immutable double array */
      public static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
      /** An empty immutable float array */
      public static final float[] EMPTY_FLOAT_ARRAY = new float[0];
      /** An empty immutable boolean array */
      public static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];
      
      /**
       * ArrayUtils instances should NOT be constructed in standard programming.
       * Instead, the class should be used as <code>ArrayUtils.clone(new int[] {2})</code>.
       * This constructor is public to permit tools that require a JavaBean instance
       * to operate.
       */
      public ArrayUtils() {
      }
  
      //--------------------------------------------------------------------------
      
      /**
       * Output the array as a String.
       * <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
       * @return a String representation of the array
       * @throws IllegalArgumentException if the array is null
       */
      public static String toString(Object[] array) {
          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
       * @return a String representation of the array
       * @throws IllegalArgumentException if the array is null
       */
      public static String toString(long[] array) {
          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
       * @return a String representation of the array
       * @throws IllegalArgumentException if the array is null
       */
      public static String toString(int[] array) {
          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
       * @return a String representation of the array
       * @throws IllegalArgumentException if the array is null
       */
      public static String toString(short[] array) {
          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
       * @return a String representation of the array
       * @throws IllegalArgumentException if the array is null
       */
      public static String toString(byte[] array) {
          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.0,2.0}.
       * 
       * @param array  the array to get a toString for
       * @return a String representation of the array
       * @throws IllegalArgumentException if the array is null
       */
      public static String toString(double[] array) {
          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.0,2.0}.
       * 
       * @param array  the array to get a toString for
       * @return a String representation of the array
       * @throws IllegalArgumentException if the array is null
       */
      public static String toString(float[] array) {
          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 {true,false}.
       * 
       * @param array  the array to get a toString for
       * @return a String representation of the array
       * @throws IllegalArgumentException if the array is null
       */
      public static String toString(boolean[] array) {
          return new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString();
      }
      
      //--------------------------------------------------------------------------
  
      /**
       * Shallow clone an array.
       * <p>
       * The objecs in the array are not cloned.
       * 
       * @param array  the array to shallow clone
       * @return the cloned array
       * @throws IllegalArgumentException if the array is null
       */
      public static Object[] clone(Object[] array) {
          if (array == null) {
              throw new IllegalArgumentException("The array must not be null");
          }
          return (Object[]) array.clone();
      }
      
      /**
       * Clone an array.
       * 
       * @param array  the array to clone
       * @return the cloned array
       * @throws IllegalArgumentException if the array is null
       */
      public static long[] clone(long[] array) {
          if (array == null) {
              throw new IllegalArgumentException("The array must not be null");
          }
          return (long[]) array.clone();
      }
      
      /**
       * Clone an array.
       * 
       * @param array  the array to clone
       * @return the cloned array
       * @throws IllegalArgumentException if the array is null
       */
      public static int[] clone(int[] array) {
          if (array == null) {
              throw new IllegalArgumentException("The array must not be null");
          }
          return (int[]) array.clone();
      }
      
      /**
       * Clone an array.
       * 
       * @param array  the array to clone
       * @return the cloned array
       * @throws IllegalArgumentException if the array is null
       */
      public static short[] clone(short[] array) {
          if (array == null) {
              throw new IllegalArgumentException("The array must not be null");
          }
          return (short[]) array.clone();
      }
      
      /**
       * Clone an array.
       * 
       * @param array  the array to clone
       * @return the cloned array
       * @throws IllegalArgumentException if the array is null
       */
      public static byte[] clone(byte[] array) {
          if (array == null) {
              throw new IllegalArgumentException("The array must not be null");
          }
          return (byte[]) array.clone();
      }
      
      /**
       * Clone an array.
       * 
       * @param array  the array to clone
       * @return the cloned array
       * @throws IllegalArgumentException if the array is null
       */
      public static double[] clone(double[] array) {
          if (array == null) {
              throw new IllegalArgumentException("The array must not be null");
          }
          return (double[]) array.clone();
      }
      
      /**
       * Clone an array.
       * 
       * @param array  the array to clone
       * @return the cloned array
       * @throws IllegalArgumentException if the array is null
       */
      public static float[] clone(float[] array) {
          if (array == null) {
              throw new IllegalArgumentException("The array must not be null");
          }
          return (float[]) array.clone();
      }
      
      /**
       * Clone an array.
       * 
       * @param array  the array to clone
       * @return the cloned array
       * @throws IllegalArgumentException if the array is null
       */
      public static boolean[] clone(boolean[] array) {
          if (array == null) {
              throw new IllegalArgumentException("The array must not be null");
          }
          return (boolean[]) array.clone();
      }
      
  }
  
  
  
  1.1                  jakarta-commons-sandbox/lang/ReflectionException.java
  
  Index: ReflectionException.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 org.apache.commons.lang.exception.NestableRuntimeException;
  /**
   * Exception thrown when the Reflection process fails. The original
   * error is wrapped within this one.
   *
   * @author <a href="mailto:scolebourne@joda.org">Stephen Colebourne</a>
   * @version $Id: ReflectionException.java,v 1.1 2002/09/19 23:02:51 scolebourne Exp $
   */
  public class ReflectionException extends NestableRuntimeException {
  
      /**
       * Constructs a new <code>ReflectionException</code> without specified
       * detail message.
       */
      public ReflectionException() {
          super();
      }
  
      /**
       * Constructs a new <code>ReflectionException</code> with specified
       * detail message.
       *
       * @param msg  The error message.
       */
      public ReflectionException(String msg) {
          super(msg);
      }
  
      /**
       * Constructs a new <code>ReflectionException</code> with specified
       * nested <code>Throwable</code>.
       *
       * @param cause  The exception or error that caused this exception
       *               to be thrown.
       */
      public ReflectionException(Throwable cause) {
          super(cause);
      }
  
      /**
       * Constructs a new <code>ReflectionException</code> with specified
       * detail message and nested <code>Throwable</code>.
       *
       * @param msg    The error message.
       * @param cause  The exception or error that caused this exception
       *               to be thrown.
       */
      public ReflectionException(String msg, Throwable cause) {
          super(msg, cause);
      }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/lang/ReflectionUtils.java
  
  Index: ReflectionUtils.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.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>MethodUtils</code> contains utility methods for working for
   * methods by reflection.
   *
   * @author Based on code from BeanUtils
   * @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
   * @version $Id: ReflectionUtils.java,v 1.1 2002/09/19 23:02:51 scolebourne Exp $
   */
  public class ReflectionUtils {
      
      // 
      // WORK IN PROGRESS - DOESN't COMPILE
      //
  
      /** 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.
       * 
       * @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
       */
      public static String getShortClassName(Class cls) {
          if (cls == null) {
              throw new IllegalArgumentException("The class must not be null");
          }
          return getShortClassName(cls.getName());
      }
      
      /**
       * 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
       */
      public static String getShortClassName(Object object) {
          if (object == null) {
              throw new IllegalArgumentException("The object must not be null");
          }
          return getShortClassName(object.getClass().getName());
      }
      
      /**
       * 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
       */
      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);
      }
      
      // -------------------------------------------------------------------------
      
      /**
       * 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 class object for the specified string.
       *
       * @param className  fully qualified class name to find, must not be empty
       * @return Class object for class
       * @throws ReflectionException if an error occurs during reflection
       * @throws IllegalArgumentException if the class name is empty
       */
      public static Class getClass(String className) throws ReflectionException {
          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);
          }
      }
      
      // -------------------------------------------------------------------------
      
      /**
       * <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 Field for the specified parameters.
       *
       * @return java.lang.reflect.Field
       * @param cls java.lang.Class
       * @param fieldName java.lang.String
       */
      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) {
          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 (InstantiationException ex) {
              message = "the class is abstract/interface/array/primitive";
          } catch (IllegalAccessException ex) {
              message = "the method was not public/accessible";
          } catch (IllegalArgumentException ex) {
              message = "the parameters did not match those expected";
          } catch (SecurityException ex) {
              message = "the security manager is blocking reflection";
          } catch (Throwable ex) {
              message = null;
          }
          StringBuffer buf = new StringBuffer();
          buf.append(ReflectionUtils.getShortClassName(th));
          buf.append(" while ");
          buf.append(desc);
          buf.append(" on Class '");
          buf.append(className);
          buf.append("'");
          if (types != null) {
              buf.append(" for types ");
              buf.append(ReflectionUtils.getClassArrayString(types));
          }
          if (methodName != null) {
              buf.append(" for method '");
              buf.append(methodName);
              buf.append("'");
          }
          if (message != null) {
              buf.append(" - ");
              buf.append(message);
          }
          return buf.toString();
      }
      
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>