scolebourne 2002/10/24 16:12:54 Added: lang/src/java/org/apache/commons/lang/reflect MethodUtils.java FieldUtils.java ConstructorUtils.java ReflectionException.java ReflectionUtils.java lang/src/java/org/apache/commons/lang ClassUtils.java Log: Initial checkin of reflection code (not all working) Revision Changes Path 1.1 jakarta-commons/lang/src/java/org/apache/commons/lang/reflect/MethodUtils.java Index: MethodUtils.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 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; // } // } 1.1 jakarta-commons/lang/src/java/org/apache/commons/lang/reflect/FieldUtils.java Index: FieldUtils.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 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); } } 1.1 jakarta-commons/lang/src/java/org/apache/commons/lang/reflect/ConstructorUtils.java Index: ConstructorUtils.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 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); } // ------------------------------------------------------------------------- } 1.1 jakarta-commons/lang/src/java/org/apache/commons/lang/reflect/ReflectionException.java Index: ReflectionException.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 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); } } 1.1 jakarta-commons/lang/src/java/org/apache/commons/lang/reflect/ReflectionUtils.java Index: ReflectionUtils.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 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(); } } 1.3 +489 -221 jakarta-commons/lang/src/java/org/apache/commons/lang/ClassUtils.java
-- To unsubscribe, e-mail: <mailto:commons-dev-unsubscribe@;jakarta.apache.org> For additional commands, e-mail: <mailto:commons-dev-help@;jakarta.apache.org>