Initial checkin of reflection code (not all working)
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137101 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d86483672f
commit
870097e4b1
|
@ -0,0 +1,489 @@
|
||||||
|
/* ====================================================================
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.lang;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
/**
|
||||||
|
* <code>ClassUtils</code> contains utility methods for working for
|
||||||
|
* classes without using reflection.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
|
||||||
|
* @version $Id: ClassUtils.java,v 1.3 2002/10/24 23:12:54 scolebourne Exp $
|
||||||
|
*/
|
||||||
|
public class ClassUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
public ClassUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 class name must not be empty");
|
||||||
|
}
|
||||||
|
char[] chars = className.toCharArray();
|
||||||
|
int lastDot = 0;
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
if (chars[i] == '.') {
|
||||||
|
lastDot = i + 1;
|
||||||
|
} else if (chars[i] == '$') { // handle inner classes
|
||||||
|
chars[i] = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new String(chars, lastDot, chars.length - lastDot);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 class name 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.
|
||||||
|
*
|
||||||
|
* @param cls the class to find subclasses for
|
||||||
|
* @return the list of subclass String class names
|
||||||
|
* @throws IllegalArgumentException if the class is null
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param cls the class to find subclasses for
|
||||||
|
* @return the list of subclasses
|
||||||
|
* @throws IllegalArgumentException if the class is null
|
||||||
|
*/
|
||||||
|
public static List getAllSubclasses(Class cls) {
|
||||||
|
List names = getAllSubclassNames(cls);
|
||||||
|
return convertClassNamesToClasses(names);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param cls the class to find sub classes for
|
||||||
|
* @return the list of implementation String class names
|
||||||
|
* @throws IllegalArgumentException if the class is null
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a list of class names, this method converts them into classes.
|
||||||
|
* A new list is returned. If the class name cannot be found, null is
|
||||||
|
* stored in the list. If the class name in the list is null, null is
|
||||||
|
* stored in the output list.
|
||||||
|
*
|
||||||
|
* @param classes the classNames to change, the class is stored back
|
||||||
|
* into the list. null will be stored in the list if no class is found.
|
||||||
|
* @return the list of Class objects corresponding to the class names
|
||||||
|
* @throws IllegalArgumentException if the classNames is null
|
||||||
|
*/
|
||||||
|
public static List convertClassNamesToClasses(List classNames) {
|
||||||
|
if (classNames == null) {
|
||||||
|
throw new IllegalArgumentException("The class names must not be null");
|
||||||
|
}
|
||||||
|
List classes = new ArrayList(classNames.size());
|
||||||
|
for (Iterator it = classNames.iterator(); it.hasNext();) {
|
||||||
|
String className = (String) it.next();
|
||||||
|
try {
|
||||||
|
classes.add(Class.forName(className));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
classes.add(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an array of Classes can be assigned to another array of Classes.
|
||||||
|
* <p>
|
||||||
|
* This can be used to check if parameter types are suitably compatable for
|
||||||
|
* reflection invocation.
|
||||||
|
* <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 classArray the array of Classes to check, may be null
|
||||||
|
* @param toClassArray the array of Classes to try to assign into, may be null
|
||||||
|
* @return true if assignment possible
|
||||||
|
*/
|
||||||
|
public static boolean isAssignable(Class[] classArray, Class[] toClassArray) {
|
||||||
|
if (ArrayUtils.isSameLength(classArray, toClassArray) == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (classArray == null) {
|
||||||
|
classArray = ArrayUtils.EMPTY_CLASS_ARRAY;
|
||||||
|
}
|
||||||
|
if (toClassArray == null) {
|
||||||
|
toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < classArray.length; i++) {
|
||||||
|
if (isAssignable(classArray[i], toClassArray[i]) == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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");
|
||||||
|
}
|
||||||
|
// have to check for null, as isAssignableFrom doesn't
|
||||||
|
if (cls == null) {
|
||||||
|
return !(toClass.isPrimitive());
|
||||||
|
}
|
||||||
|
if (cls.equals(toClass)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,428 @@
|
||||||
|
/* ====================================================================
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.lang.reflect;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.ArrayUtils;
|
||||||
|
/**
|
||||||
|
* <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: ConstructorUtils.java,v 1.1 2002/10/24 23:12:54 scolebourne Exp $
|
||||||
|
*/
|
||||||
|
public class ConstructorUtils {
|
||||||
|
|
||||||
|
/** An empty constructor 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 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.
|
||||||
|
*
|
||||||
|
* @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, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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 breakScope) {
|
||||||
|
if (cls == null) {
|
||||||
|
throw new IllegalArgumentException("The class must not be null");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (breakScope) {
|
||||||
|
Constructor con = cls.getDeclaredConstructor(types);
|
||||||
|
if (Modifier.isPublic(con.getModifiers()) == false) {
|
||||||
|
con.setAccessible(true);
|
||||||
|
}
|
||||||
|
return con;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return cls.getConstructor(types);
|
||||||
|
}
|
||||||
|
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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 breakScope) {
|
||||||
|
if (con == null) {
|
||||||
|
throw new IllegalArgumentException("The constructor must not be null");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (breakScope && Modifier.isPublic(con.getModifiers()) == false) {
|
||||||
|
con.setAccessible(true);
|
||||||
|
}
|
||||||
|
return con.newInstance(params);
|
||||||
|
|
||||||
|
} 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(
|
||||||
|
ex, "invoking constructor", con.getDeclaringClass().getName(), con.getParameterTypes(), null), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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 breakScope) {
|
||||||
|
Class cls = ReflectionUtils.getClass(className);
|
||||||
|
return newInstance(cls, breakScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, 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.
|
||||||
|
*
|
||||||
|
* @param cls Class object to instantiate, must not 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 class is null
|
||||||
|
*/
|
||||||
|
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 (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(
|
||||||
|
ex, "instantiating class", cls.getName(), null, null), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @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, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,492 @@
|
||||||
|
/* ====================================================================
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.lang.reflect;
|
||||||
|
|
||||||
|
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/10/24 23:12:54 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 an accessible Field by name repecting scope.
|
||||||
|
* Superclasses/interfaces 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 an accessible Field by name breaking scope if requested.
|
||||||
|
* Superclasses/interfaces 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");
|
||||||
|
}
|
||||||
|
// Sun Java 1.3 has a bugged implementation of getField hence we write the
|
||||||
|
// code ourselves
|
||||||
|
|
||||||
|
// getField() will return the Field object with the declaring class
|
||||||
|
// set correctly to the class that declares the field. Thus requesting the
|
||||||
|
// field on a subclass will return the field from the superclass.
|
||||||
|
//
|
||||||
|
// priority order for lookup:
|
||||||
|
// searchclass private/protected/package/public
|
||||||
|
// superclass protected/package/public
|
||||||
|
// private/different package blocks access to further superclasses
|
||||||
|
// implementedinterface public
|
||||||
|
try {
|
||||||
|
// check up the superclass hierarchy
|
||||||
|
Class acls = cls;
|
||||||
|
Field match = null;
|
||||||
|
while (acls != null && acls != Object.class) {
|
||||||
|
// getDeclaredField checks for non-public scopes as well
|
||||||
|
// and it returns accurate results
|
||||||
|
try {
|
||||||
|
Field field = acls.getDeclaredField(fieldName);
|
||||||
|
if (Modifier.isPublic(field.getModifiers()) == false) {
|
||||||
|
field.setAccessible(breakScope);
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
if (breakScope == false) {
|
||||||
|
// only public acceptable if not breaking scope
|
||||||
|
throw new IllegalAccessException("The field '" + fieldName +
|
||||||
|
"' was found, but it's scope prevents direct access by reflection");
|
||||||
|
}
|
||||||
|
field.setAccessible(true);
|
||||||
|
match = field;
|
||||||
|
break;
|
||||||
|
|
||||||
|
} catch (NoSuchFieldException ex) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
// next superclass
|
||||||
|
acls = acls.getSuperclass();
|
||||||
|
}
|
||||||
|
// check the public interface case. This must be manually searched for
|
||||||
|
// incase there is a public supersuperclass field hidden by a private/package
|
||||||
|
// superclass field.
|
||||||
|
// check up the superclass hierarchy
|
||||||
|
Class[] ints = cls.getInterfaces();
|
||||||
|
for (int i = 0; i < ints.length; i++) {
|
||||||
|
// getField is fine here, because everything is public, and thus it works
|
||||||
|
try {
|
||||||
|
Field field = ints[i].getField(fieldName);
|
||||||
|
return field;
|
||||||
|
|
||||||
|
} catch (NoSuchFieldException ex) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match != null) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
throw new NoSuchFieldException("The field '" + fieldName + "' could not be found");
|
||||||
|
|
||||||
|
} 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 an accessible Field by name respecting scope.
|
||||||
|
* 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 an accessible Field by name breaking scope if requested.
|
||||||
|
* 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 {
|
||||||
|
// only consider the specified class by using getDeclaredField()
|
||||||
|
Field field = cls.getDeclaredField(fieldName);
|
||||||
|
if (Modifier.isPublic(field.getModifiers()) == false) {
|
||||||
|
if (breakScope) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
} else {
|
||||||
|
throw new IllegalAccessException("The field '" + fieldName + "' was found, but it's scope prevents direct access by reflection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,750 @@
|
||||||
|
/* ====================================================================
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.lang.reflect;
|
||||||
|
|
||||||
|
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.ArrayUtils;
|
||||||
|
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/10/24 23:12:54 scolebourne Exp $
|
||||||
|
*/
|
||||||
|
public class MethodUtils {
|
||||||
|
|
||||||
|
/** 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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a Method by name. The method must be public and take no parameters.
|
||||||
|
* Superclasses will be considered.
|
||||||
|
*
|
||||||
|
* @param cls the class to reflect, must not be null
|
||||||
|
* @param methodName the field name to obtain
|
||||||
|
* @return the Method object
|
||||||
|
* @throws IllegalArgumentException if the class or method name is null
|
||||||
|
* @throws ReflectionException if an error occurs during reflection
|
||||||
|
*/
|
||||||
|
public static Method getMethod(Class cls, String methodName) {
|
||||||
|
return getMethod(cls, methodName, ArrayUtils.EMPTY_CLASS_ARRAY, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a Method by name. The method must be public.
|
||||||
|
* Superclasses will be considered.
|
||||||
|
*
|
||||||
|
* @param cls the class to reflect, must not be null
|
||||||
|
* @param methodName the field name to obtain
|
||||||
|
* @return the Method object
|
||||||
|
* @throws IllegalArgumentException if the class or method name is null
|
||||||
|
* @throws ReflectionException if an error occurs during reflection
|
||||||
|
*/
|
||||||
|
public static Method getMethod(Class cls, String methodName, Class[] paramTypes) {
|
||||||
|
return getMethod(cls, methodName, paramTypes, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a Method by name.
|
||||||
|
* Superclasses will be considered.
|
||||||
|
*
|
||||||
|
* @param cls the class to reflect, must not be null
|
||||||
|
* @param methodName the method name to obtain
|
||||||
|
* @param breakScope whether to break scope restrictions using the
|
||||||
|
* <code>setAccessible</code> method. False will only match public fields.
|
||||||
|
* @return the Method object
|
||||||
|
* @throws IllegalArgumentException if the class or field name is null
|
||||||
|
* @throws ReflectionException if an error occurs during reflection
|
||||||
|
*/
|
||||||
|
public static Method getMethod(Class cls, String methodName, Class[] paramTypes, boolean breakScope) {
|
||||||
|
if (cls == null) {
|
||||||
|
throw new IllegalArgumentException("The class must not be null");
|
||||||
|
}
|
||||||
|
if (methodName == null) {
|
||||||
|
throw new IllegalArgumentException("The method name must not be null");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (breakScope) {
|
||||||
|
try {
|
||||||
|
// most common case, always do this for speed
|
||||||
|
return cls.getMethod(methodName, paramTypes); // must be public
|
||||||
|
} catch (NoSuchMethodException ex) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
Class acls = cls;
|
||||||
|
while (acls != null) {
|
||||||
|
Method[] methods = acls.getDeclaredMethods();
|
||||||
|
for (int i = 0; i < methods.length; i++) {
|
||||||
|
if (methods[i].getName().equals(methodName) &&
|
||||||
|
ReflectionUtils.isCompatable(paramTypes, methods[i].getParameterTypes())) {
|
||||||
|
if (Modifier.isPublic(methods[i].getModifiers())) {
|
||||||
|
methods[i].setAccessible(true);
|
||||||
|
}
|
||||||
|
return methods[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acls = acls.getSuperclass(); // TODO interfaces
|
||||||
|
}
|
||||||
|
throw new NoSuchMethodException("The method '" + methodName + "' could not be found");
|
||||||
|
} else {
|
||||||
|
return cls.getMethod(methodName, paramTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (ReflectionException ex) {
|
||||||
|
throw ex;
|
||||||
|
} catch (LinkageError ex) {
|
||||||
|
throw new ReflectionException(ReflectionUtils.getThrowableText(
|
||||||
|
ex, "getting method", cls.getName(), null, methodName), ex);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new ReflectionException(ReflectionUtils.getThrowableText(
|
||||||
|
ex, "getting method", cls.getName(), null, methodName), 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 = ArrayUtils.EMPTY_CLASS_ARRAY;
|
||||||
|
}
|
||||||
|
if (args == null) {
|
||||||
|
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
// 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 = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
||||||
|
}
|
||||||
|
int arguments = args.length;
|
||||||
|
Class parameterTypes [] = new Class[arguments];
|
||||||
|
for (int i = 0; i < arguments; i++) {
|
||||||
|
parameterTypes[i] = args[i].getClass();
|
||||||
|
}
|
||||||
|
return invokeExactMethod(object, methodName, args, parameterTypes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Invoke a method whose parameter types match exactly the parameter
|
||||||
|
* types given.</p>
|
||||||
|
*
|
||||||
|
* <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 = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameterTypes == null) {
|
||||||
|
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/* ====================================================================
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.lang.reflect;
|
||||||
|
|
||||||
|
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/10/24 23:12:54 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,336 @@
|
||||||
|
/* ====================================================================
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.lang.reflect;
|
||||||
|
|
||||||
|
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.*;
|
||||||
|
import org.apache.commons.lang.ArrayUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
/**
|
||||||
|
* <code>ReflectionUtils</code> contains utility methods for working for
|
||||||
|
* reflection.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
|
||||||
|
* @version $Id: ReflectionUtils.java,v 1.1 2002/10/24 23:12:54 scolebourne Exp $
|
||||||
|
*/
|
||||||
|
public class ReflectionUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the specified field or method is
|
||||||
|
* <code>static</code>.
|
||||||
|
*
|
||||||
|
* @param member the member to test, must not be null
|
||||||
|
* @return true if the member is static
|
||||||
|
*/
|
||||||
|
public static boolean isStatic(Member member) {
|
||||||
|
if (member == null) {
|
||||||
|
throw new IllegalArgumentException("The member must not be null");
|
||||||
|
}
|
||||||
|
return Modifier.isStatic(member.getModifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the specified field or method is
|
||||||
|
* <code>static</code>.
|
||||||
|
*
|
||||||
|
* @param member the member to test, must not be null
|
||||||
|
* @return true if the member is final
|
||||||
|
*/
|
||||||
|
public static boolean isFinal(Member member) {
|
||||||
|
if (member == null) {
|
||||||
|
throw new IllegalArgumentException("The member must not be null");
|
||||||
|
}
|
||||||
|
return Modifier.isFinal(member.getModifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the specified field, method or constructor is
|
||||||
|
* <code>public</code>.
|
||||||
|
*
|
||||||
|
* @param member the member to test, must not be null
|
||||||
|
* @return true if the member is public scoped
|
||||||
|
*/
|
||||||
|
public static boolean isPublicScope(Member member) {
|
||||||
|
if (member == null) {
|
||||||
|
throw new IllegalArgumentException("The member must not be null");
|
||||||
|
}
|
||||||
|
return Modifier.isStatic(member.getModifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the specified field, method or constructor is
|
||||||
|
* <code>protected</code>.
|
||||||
|
*
|
||||||
|
* @param member the member to test, must not be null
|
||||||
|
* @return true if the member is protected scoped
|
||||||
|
*/
|
||||||
|
public static boolean isProtectedScope(Member member) {
|
||||||
|
if (member == null) {
|
||||||
|
throw new IllegalArgumentException("The member must not be null");
|
||||||
|
}
|
||||||
|
return Modifier.isProtected(member.getModifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the specified field, method or constructor is
|
||||||
|
* package (default) scoped.
|
||||||
|
*
|
||||||
|
* @param member the member to test, must not be null
|
||||||
|
* @return true if the member is package scoped
|
||||||
|
*/
|
||||||
|
public static boolean isPackageScope(Member member) {
|
||||||
|
return !(isPublicScope(member) || isProtectedScope(member) || isPrivateScope(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the specified field, method or constructor is
|
||||||
|
* <code>private</code>.
|
||||||
|
*
|
||||||
|
* @param member the member to test, must not be null
|
||||||
|
* @return true if the member is private scoped
|
||||||
|
*/
|
||||||
|
public static boolean isPrivateScope(Member member) {
|
||||||
|
if (member == null) {
|
||||||
|
throw new IllegalArgumentException("The member must not be null");
|
||||||
|
}
|
||||||
|
return Modifier.isPrivate(member.getModifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 (LinkageError 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the requested Class array is compatable with the specified
|
||||||
|
* parameter array.
|
||||||
|
* Primitive classes are handled correctly .
|
||||||
|
* <p>
|
||||||
|
* In other words, a <code>boolean</code> Class will be converted to
|
||||||
|
* a <code>Boolean</code> Class and so on.
|
||||||
|
*
|
||||||
|
* @param requestedTypes the class array requested
|
||||||
|
* @param paramTypes the actual class array for the method
|
||||||
|
* @return true if the parameters are compatable
|
||||||
|
*/
|
||||||
|
public static boolean isCompatable(Class[] requestedTypes, Class[] paramTypes) {
|
||||||
|
if (ArrayUtils.isSameLength(requestedTypes, paramTypes) == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (requestedTypes == null) {
|
||||||
|
requestedTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
|
||||||
|
}
|
||||||
|
if (paramTypes == null) {
|
||||||
|
paramTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < requestedTypes.length; i++) {
|
||||||
|
if (ClassUtils.isAssignable(requestedTypes[i], paramTypes[i]) == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces nicely formatted informational error messages for reflection errors.
|
||||||
|
*
|
||||||
|
* @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 String getThrowableText(Throwable th, String desc, String className, Class[] types, String memberName) {
|
||||||
|
String message = null;
|
||||||
|
try {
|
||||||
|
throw th;
|
||||||
|
|
||||||
|
} 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) {
|
||||||
|
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 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(ClassUtils.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(ArrayUtils.toString(types));
|
||||||
|
}
|
||||||
|
if (memberName != null) {
|
||||||
|
buf.append(" for method '");
|
||||||
|
buf.append(memberName);
|
||||||
|
buf.append("'");
|
||||||
|
}
|
||||||
|
if (message != null) {
|
||||||
|
buf.append(" - ");
|
||||||
|
buf.append(message);
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue