merge [LANG-416] from LANG_POST_2_4 branch

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@653918 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Matthew Jason Benson 2008-05-06 20:45:11 +00:00
parent 504af2f2ed
commit 04e9eb14e7
19 changed files with 3851 additions and 0 deletions

View File

@ -0,0 +1,340 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ClassUtils;
/**
* <p> Utility reflection methods focussed on constructors, modelled after {@link MethodUtils}. </p>
*
* <h3>Known Limitations</h3>
* <h4>Accessing Public Constructors In A Default Access Superclass</h4>
* <p>There is an issue when invoking public constructors contained in a default access superclass.
* Reflection locates these constructors fine and correctly assigns them as public.
* However, an <code>IllegalAccessException</code> is thrown if the constructors is invoked.</p>
*
* <p><code>ConstructorUtils</code> contains a workaround for this situation.
* It will attempt to call <code>setAccessible</code> on this constructor.
* If this call succeeds, then the method can be invoked as normal.
* This call will only succeed when the application has sufficient security privilages.
* If this call fails then a warning will be logged and the method may fail.</p>
*
* @author Craig R. McClanahan
* @author Ralph Schaer
* @author Chris Audley
* @author Rey Francois
* @author Gregor Rayman
* @author Jan Sorensen
* @author Robert Burrell Donkin
* @author Rodney Waldhoff
* @since 2.5
* @version $Id$
*/
public class ConstructorUtils {
/**
* <p>ConstructorUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as
* <code>ConstructorUtils.invokeConstructor(cls, args)</code>.</p>
*
* <p>This constructor is public to permit tools that require a JavaBean
* instance to operate.</p>
*/
public ConstructorUtils() {
super();
}
/**
* <p>Convenience method returning new instance of <code>klazz</code> using a single argument constructor.
* The formal parameter type is inferred from the actual values of <code>arg</code>.
* See {@link #invokeExactConstructor(Class, Object[], Class[])} for more details.</p>
*
* <p>The signatures should be assignment compatible.</p>
*
* @param cls the class to be constructed.
* @param arg the actual argument
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the constructor
* @throws InvocationTargetException If an error occurs invoking the constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
public static Object invokeConstructor(Class cls, Object arg)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
return invokeConstructor(cls, new Object[] { arg });
}
/**
* <p>Returns new instance of <code>klazz</code> created using the actual arguments <code>args</code>.
* The formal parameter types are inferred from the actual values of <code>args</code>.
* See {@link #invokeExactConstructor(Class, Object[], Class[])} for more details.</p>
*
* <p>The signatures should be assignment compatible.</p>
*
* @param cls the class to be constructed.
* @param args actual argument array
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the constructor
* @throws InvocationTargetException If an error occurs invoking the constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
public static Object invokeConstructor(Class cls, Object[] args)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
if (null == args) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
Class parameterTypes[] = new Class[args.length];
for (int i = 0; i < args.length; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeConstructor(cls, args, parameterTypes);
}
/**
* <p>Returns new instance of <code>klazz</code> created using constructor
* with signature <code>parameterTypes</code> and actual arguments <code>args</code>.</p>
*
* <p>The signatures should be assignment compatible.</p>
*
* @param cls the class to be constructed.
* @param args actual argument array
* @param parameterTypes parameter types array
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException if matching constructor cannot be found
* @throws IllegalAccessException thrown on the constructor's invocation
* @throws InvocationTargetException thrown on the constructor's invocation
* @throws InstantiationException thrown on the constructor's invocation
* @see Constructor#newInstance
*/
public static Object invokeConstructor(Class cls, Object[] args,
Class[] parameterTypes) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException,
InstantiationException {
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
Constructor ctor = getMatchingAccessibleConstructor(cls, parameterTypes);
if (null == ctor) {
throw new NoSuchMethodException(
"No such accessible constructor on object: "
+ cls.getName());
}
return ctor.newInstance(args);
}
/**
* <p>Convenience method returning new instance of <code>klazz</code> using a single argument constructor.
* The formal parameter type is inferred from the actual values of <code>arg</code>.
* See {@link #invokeExactConstructor(Class, Object[], Class[])} for more details.</p>
*
* <p>The signatures should match exactly.</p>
*
* @param cls the class to be constructed.
* @param arg the actual argument
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the constructor
* @throws InvocationTargetException If an error occurs invoking the constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
public static Object invokeExactConstructor(Class cls, Object arg)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
return invokeExactConstructor(cls, new Object[] { arg });
}
/**
* <p>Returns new instance of <code>klazz</code> created using the actual arguments <code>args</code>.
* The formal parameter types are inferred from the actual values of <code>args</code>.
* See {@link #invokeExactConstructor(Class, Object[], Class[])} for more details.</p>
*
* <p>The signatures should match exactly.</p>
*
* @param cls the class to be constructed.
* @param args actual argument array
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the constructor
* @throws InvocationTargetException If an error occurs invoking the constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
public static Object invokeExactConstructor(Class cls, Object[] args)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
if (null == args) {
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 invokeExactConstructor(cls, args, parameterTypes);
}
/**
* <p>Returns new instance of <code>klazz</code> created using constructor
* with signature <code>parameterTypes</code> and actual arguments
* <code>args</code>.</p>
*
* <p>The signatures should match exactly.</p>
*
* @param cls the class to be constructed.
* @param args actual argument array
* @param parameterTypes parameter types array
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException if matching constructor cannot be found
* @throws IllegalAccessException thrown on the constructor's invocation
* @throws InvocationTargetException thrown on the constructor's invocation
* @throws InstantiationException thrown on the constructor's invocation
* @see Constructor#newInstance
*/
public static Object invokeExactConstructor(Class cls, Object[] args,
Class[] parameterTypes) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException,
InstantiationException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
Constructor ctor = getAccessibleConstructor(cls, parameterTypes);
if (null == ctor) {
throw new NoSuchMethodException(
"No such accessible constructor on object: "
+ cls.getName());
}
return ctor.newInstance(args);
}
/**
* Returns a constructor with single argument.
* @param cls the class to be constructed
* @param parameterType The constructor parameter type
* @return null if matching accessible constructor can not be found.
* @see Class#getConstructor
* @see #getAccessibleConstructor(java.lang.reflect.Constructor)
*/
public static Constructor getAccessibleConstructor(Class cls,
Class parameterType) {
return getAccessibleConstructor(cls, new Class[] { parameterType });
}
/**
* Returns a constructor given a class and signature.
* @param cls the class to be constructed
* @param parameterTypes the parameter array
* @return null if matching accessible constructor can not be found
* @see Class#getConstructor
* @see #getAccessibleConstructor(java.lang.reflect.Constructor)
*/
public static Constructor getAccessibleConstructor(Class cls,
Class[] parameterTypes) {
try {
return getAccessibleConstructor(cls.getConstructor(parameterTypes));
} catch (NoSuchMethodException e) {
return (null);
}
}
/**
* Returns accessible version of the given constructor.
* @param ctor prototype constructor object.
* @return <code>null</code> if accessible constructor can not be found.
* @see java.lang.SecurityManager
*/
public static Constructor getAccessibleConstructor(Constructor ctor) {
return MemberUtils.isAccessible(ctor)
&& Modifier.isPublic(ctor.getDeclaringClass().getModifiers()) ? ctor
: null;
}
/**
* <p>Find an accessible constructor with compatible parameters.
* Compatible parameters mean that every method parameter is assignable from
* the given parameters. In other words, it finds constructor that will take
* the parameters given.</p>
*
* <p>First it checks if there is constructor matching the exact signature.
* If no such, all the constructors of the class are tested if their signatures
* are assignment compatible with the parameter types.
* The first matching constructor is returned.</p>
*
* @param cls find constructor for this class
* @param parameterTypes find method with compatible parameters
* @return a valid Constructor object. If there's no matching constructor, returns <code>null</code>.
*/
public static Constructor getMatchingAccessibleConstructor(Class cls,
Class[] parameterTypes) {
// see if we can find the constructor directly
// most of the time this works and it's much faster
try {
Constructor ctor = cls.getConstructor(parameterTypes);
MemberUtils.setAccessibleWorkaround(ctor);
return ctor;
} catch (NoSuchMethodException e) { /* SWALLOW */
}
Constructor result = null;
// search through all constructors
Constructor[] ctors = cls.getConstructors();
for (int i = 0; i < ctors.length; i++) {
// compare parameters
if (ClassUtils.isAssignable(parameterTypes, ctors[i]
.getParameterTypes(), true)) {
// get accessible version of method
Constructor ctor = getAccessibleConstructor(ctors[i]);
if (ctor != null) {
MemberUtils.setAccessibleWorkaround(ctor);
if (result == null
|| MemberUtils.compareParameterTypes(ctor
.getParameterTypes(), result
.getParameterTypes(), parameterTypes) < 0) {
result = ctor;
}
}
}
}
return result;
}
}

View File

@ -0,0 +1,605 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* Utilities for working with fields by reflection. Adapted and refactored
* from the dormant [reflect] Commons sandbox component.
* <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 Stephen Colebourne
* @author Matt Benson
* @since 2.5
* @version $Id$
*/
public class FieldUtils {
/**
* FieldUtils instances should NOT be constructed in standard programming.
* <p>
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public FieldUtils() {
super();
}
/**
* Gets an accessible <code>Field</code> 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
*/
public static Field getField(Class cls, String fieldName) {
Field field = getField(cls, fieldName, false);
MemberUtils.setAccessibleWorkaround(field);
return field;
}
/**
* Gets an accessible <code>Field</code> 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 forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
*/
public static Field getField(final Class cls, String fieldName, boolean forceAccess) {
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
// check up the superclass hierarchy
for (Class acls = cls; acls != null; acls = acls.getSuperclass()) {
try {
Field field = acls.getDeclaredField(fieldName);
// getDeclaredField checks for non-public scopes as well
// and it returns accurate results
if (!Modifier.isPublic(field.getModifiers())) {
if (forceAccess) {
field.setAccessible(true);
} else {
continue;
}
}
return field;
} catch (NoSuchFieldException ex) {
// ignore
}
}
// 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.
Field match = null;
for (Class acls = cls; acls != null; acls = acls.getSuperclass()) {
Class[] ints = acls.getInterfaces();
for (int i = 0; i < ints.length; i++) {
// getField is fine here, because everything is public, and thus it works
try {
Field test = ints[i].getField(fieldName);
if (match != null) {
if (match.getDeclaringClass().equals(test.getDeclaringClass())) {
continue;
}
throw new IllegalArgumentException(
"Reference to field "
+ fieldName
+ " is ambiguous relative to "
+ cls
+ "; a matching field exists on two or more parent interfaces.");
}
match = test;
} catch (NoSuchFieldException ex) {
// ignore
}
}
}
return match;
}
/**
* Gets an accessible <code>Field</code> 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
*/
public static Field getDeclaredField(Class cls, String fieldName) {
return getDeclaredField(cls, fieldName, false);
}
/**
* Gets an accessible <code>Field</code> 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 forceAccess 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
*/
public static Field getDeclaredField(Class cls, String fieldName, boolean forceAccess) {
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 (!MemberUtils.isAccessible(field)) {
if (forceAccess) {
field.setAccessible(true);
} else {
return null;
}
}
return field;
} catch (NoSuchFieldException e) {
}
return null;
}
/**
* Read an accessible static Field.
* @param field to read
* @return the field value
* @throws IllegalArgumentException if the field is null or not static
* @throws IllegalAccessException if the field is not accessible
*/
public static Object readStaticField(Field field) throws IllegalAccessException {
return readStaticField(field, false);
}
/**
* Read a static Field.
* @param field to read
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method.
* @return the field value
* @throws IllegalArgumentException if the field is null or not static
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readStaticField(Field field, boolean forceAccess) throws IllegalAccessException {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
if (!Modifier.isStatic(field.getModifiers())) {
throw new IllegalArgumentException("The field '" + field.getName() + "' is not static");
}
return readField(field, (Object) null, forceAccess);
}
/**
* Read the named public static field. 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 IllegalAccessException if the field is not accessible
*/
public static Object readStaticField(Class cls, String fieldName) throws IllegalAccessException {
return readStaticField(cls, fieldName, false);
}
/**
* Read the named static field. Superclasses will be considered.
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readStaticField(Class cls, String fieldName, boolean forceAccess) throws IllegalAccessException {
Field field = getField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate field " + fieldName + " on " + cls);
}
//already forced access above, don't repeat it here:
return readStaticField(field, false);
}
/**
* 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 IllegalAccessException if the field is not accessible
*/
public static Object readDeclaredStaticField(Class cls, String fieldName) throws IllegalAccessException {
return readDeclaredStaticField(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 forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readDeclaredStaticField(Class cls, String fieldName, boolean forceAccess)
throws IllegalAccessException {
Field field = getDeclaredField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
}
//already forced access above, don't repeat it here:
return readStaticField(field, false);
}
/**
* Read an accessible Field.
* @param field the field to use
* @param target the object to call on, may be null for static fields
* @return the field value
* @throws IllegalArgumentException if the field is null
* @throws IllegalAccessException if the field is not accessible
*/
public static Object readField(Field field, Object target) throws IllegalAccessException {
return readField(field, target, false);
}
/**
* Read a Field.
* @param field the field to use
* @param target the object to call on, may be null for static fields
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method.
* @return the field value
* @throws IllegalArgumentException if the field is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readField(Field field, Object target, boolean forceAccess) throws IllegalAccessException {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
if (forceAccess && !field.isAccessible()) {
field.setAccessible(true);
} else {
MemberUtils.setAccessibleWorkaround(field);
}
return field.get(target);
}
/**
* Read the named public field. Superclasses will be considered.
* @param target 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 IllegalAccessException if the named field is not public
*/
public static Object readField(Object target, String fieldName) throws IllegalAccessException {
return readField(target, fieldName, false);
}
/**
* Read the named field. Superclasses will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @return the field value
* @throws IllegalArgumentException if the class or field name is null
* @throws IllegalAccessException if the named field is not made accessible
*/
public static Object readField(Object target, String fieldName, boolean forceAccess) throws IllegalAccessException {
if (target == null) {
throw new IllegalArgumentException("target object must not be null");
}
Class cls = target.getClass();
Field field = getField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate field " + fieldName + " on " + cls);
}
//already forced access above, don't repeat it here:
return readField(field, target);
}
/**
* Read the named public field. Only the class of the specified object will be considered.
* @param target 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 IllegalAccessException if the named field is not public
*/
public static Object readDeclaredField(Object target, String fieldName) throws IllegalAccessException {
return readDeclaredField(target, fieldName, false);
}
/**
* <p<>Gets a Field value by name. Only the class of the specified
* object will be considered.
*
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @return the Field object
* @throws IllegalArgumentException if <code>target</code> or <code>fieldName</code> is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readDeclaredField(Object target, String fieldName, boolean forceAccess) throws IllegalAccessException {
if (target == null) {
throw new IllegalArgumentException("target object must not be null");
}
Class cls = target.getClass();
Field field = getDeclaredField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
}
//already forced access above, don't repeat it here:
return readField(field, target);
}
/**
* Write a public static Field.
* @param field to write
* @param value to set
* @throws IllegalArgumentException if the field is null or not static
* @throws IllegalAccessException if the field is not public or is final
*/
public static void writeStaticField(Field field, Object value) throws IllegalAccessException {
writeStaticField(field, value, false);
}
/**
* Write a static Field.
* @param field to write
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @throws IllegalArgumentException if the field is null or not static
* @throws IllegalAccessException if the field is not made accessible or is final
*/
public static void writeStaticField(Field field, Object value, boolean forceAccess) throws IllegalAccessException {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
if (!Modifier.isStatic(field.getModifiers())) {
throw new IllegalArgumentException("The field '" + field.getName() + "' is not static");
}
writeField(field, (Object) null, value, forceAccess);
}
/**
* Write a named public static Field. Superclasses will be considered.
* @param cls Class on which the Field is to be found
* @param fieldName to write
* @param value to set
* @throws IllegalArgumentException if the field cannot be located or is not static
* @throws IllegalAccessException if the field is not public or is final
*/
public static void writeStaticField(Class cls, String fieldName, Object value) throws IllegalAccessException {
writeStaticField(cls, fieldName, value, false);
}
/**
* Write a named static Field. Superclasses will be considered.
* @param cls Class on which the Field is to be found
* @param fieldName to write
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @throws IllegalArgumentException if the field cannot be located or is not static
* @throws IllegalAccessException if the field is not made accessible or is final
*/
public static void writeStaticField(Class cls, String fieldName, Object value, boolean forceAccess)
throws IllegalAccessException {
Field field = getField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate field " + fieldName + " on " + cls);
}
//already forced access above, don't repeat it here:
writeStaticField(field, value);
}
/**
* Write a named public static Field. Only the specified class will be considered.
* @param cls Class on which the Field is to be found
* @param fieldName to write
* @param value to set
* @throws IllegalArgumentException if the field cannot be located or is not static
* @throws IllegalAccessException if the field is not public or is final
*/
public static void writeDeclaredStaticField(Class cls, String fieldName, Object value)
throws IllegalAccessException {
writeDeclaredStaticField(cls, fieldName, value, false);
}
/**
* Write a named static Field. Only the specified class will be considered.
* @param cls Class on which the Field is to be found
* @param fieldName to write
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @throws IllegalArgumentException if the field cannot be located or is not static
* @throws IllegalAccessException if the field is not made accessible or is final
*/
public static void writeDeclaredStaticField(Class cls, String fieldName, Object value, boolean forceAccess)
throws IllegalAccessException {
Field field = getDeclaredField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
}
//already forced access above, don't repeat it here:
writeField(field, (Object) null, value);
}
/**
* Write an accessible field.
* @param field to write
* @param target the object to call on, may be null for static fields
* @param value to set
* @throws IllegalArgumentException if the field is null
* @throws IllegalAccessException if the field is not accessible or is final
*/
public static void writeField(Field field, Object target, Object value) throws IllegalAccessException {
writeField(field, target, value, false);
}
/**
* Write a field.
* @param field to write
* @param target the object to call on, may be null for static fields
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @throws IllegalArgumentException if the field is null
* @throws IllegalAccessException if the field is not made accessible or is final
*/
public static void writeField(Field field, Object target, Object value, boolean forceAccess) throws IllegalAccessException {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
if (forceAccess && !field.isAccessible()) {
field.setAccessible(true);
} else {
MemberUtils.setAccessibleWorkaround(field);
}
field.set(target, value);
}
/**
* Write a public field. Superclasses will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param value to set
* @throws IllegalArgumentException if <code>target</code> or <code>fieldName</code> is null
* @throws IllegalAccessException if the field is not accessible
*/
public static void writeField(Object target, String fieldName, Object value) throws IllegalAccessException {
writeField(target, fieldName, value, false);
}
/**
* Write a field. Superclasses will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @throws IllegalArgumentException if <code>target</code> or <code>fieldName</code> is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static void writeField(Object target, String fieldName, Object value, boolean forceAccess)
throws IllegalAccessException {
if (target == null) {
throw new IllegalArgumentException("target object must not be null");
}
Class cls = target.getClass();
Field field = getField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
}
//already forced access above, don't repeat it here:
writeField(field, target, value);
}
/**
* Write a public field. Only the specified class will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @throws IllegalArgumentException if <code>target</code> or <code>fieldName</code> is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static void writeDeclaredField(Object target, String fieldName, Object value) throws IllegalAccessException {
writeDeclaredField(target, fieldName, value, false);
}
/**
* Write a public field. Only the specified class will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* <code>setAccessible</code> method. <code>False</code> will only
* match public fields.
* @throws IllegalArgumentException if <code>target</code> or <code>fieldName</code> is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static void writeDeclaredField(Object target, String fieldName, Object value, boolean forceAccess)
throws IllegalAccessException {
if (target == null) {
throw new IllegalArgumentException("target object must not be null");
}
Class cls = target.getClass();
Field field = getDeclaredField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
}
//already forced access above, don't repeat it here:
writeField(field, target, value);
}
}

View File

@ -0,0 +1,220 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.SystemUtils;
/**
* Contains common code for working with Methods/Constructors, extracted and
* refactored from <code>MethodUtils</code> when it was imported from Commons BeanUtils.
*
* @author Steve Cohen
* @author Matt Benson
* @since 2.5
* @version $Id$
*/
abstract class MemberUtils {
// TODO extract an interface to implement compareParameterSets(...)?
private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
private static final Method IS_SYNTHETIC;
static {
Method isSynthetic = null;
if (SystemUtils.isJavaVersionAtLeast(1.5f)) {
// cannot call synthetic methods:
try {
isSynthetic = Member.class.getMethod("isSynthetic",
ArrayUtils.EMPTY_CLASS_ARRAY);
} catch (Exception e) {
}
}
IS_SYNTHETIC = isSynthetic;
}
/** Array of primitive number types ordered by "promotability" */
private static final Class[] ORDERED_PRIMITIVE_TYPES = { Byte.TYPE,
Short.TYPE, Character.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE,
Double.TYPE };
/**
* XXX Default access superclass workaround
*
* When a public class has a default access superclass with public
* members, these members are accessible. Calling them from
* compiled code works fine. Unfortunately, on some JVMs, using reflection to invoke these
* members seems to (wrongly) to prevent access even when the
* modifer is public. Calling setAccessible(true) solves the problem
* but will only work from sufficiently privileged code. Better
* workarounds would be gratefully accepted.
* @param o the AccessibleObject to set as accessible
*/
static void setAccessibleWorkaround(AccessibleObject o) {
if (o == null || o.isAccessible()) {
return;
}
Member m = (Member) o;
if (Modifier.isPublic(m.getModifiers()) && isPackageAccess(m.getDeclaringClass().getModifiers())) {
try {
o.setAccessible(true);
} catch (SecurityException e) {
// ignore in favor of subsequent IllegalAccessException
}
}
}
/**
* Learn whether a given set of modifiers implies package access.
* @param modifiers to test
* @return true unless package/protected/private modifier detected
*/
static boolean isPackageAccess(int modifiers) {
return (modifiers & ACCESS_TEST) == 0;
}
/**
* Check a Member for basic accessibility.
* @param m Member to check
* @return true if <code>m</code> is accessible
*/
static boolean isAccessible(Member m) {
return m != null && Modifier.isPublic(m.getModifiers())
&& !isSynthetic(m);
}
/**
* Try to learn whether a given member, on JDK >= 1.5, is synthetic.
* @param m Member to check
* @return true if <code>m</code> was introduced by the compiler.
*/
static boolean isSynthetic(Member m) {
if (IS_SYNTHETIC != null) {
try {
return ((Boolean) IS_SYNTHETIC.invoke(m, null)).booleanValue();
} catch (Exception e) {
}
}
return false;
}
/**
* Compare the relative fitness of two sets of parameter types in terms of
* matching a third set of runtime parameter types, such that a list ordered
* by the results of the comparison would return the best match first (least).
*
* @param left the "left" parameter set
* @param right the "right" parameter set
* @param actual the runtime parameter types to match against <code>left</code>/<code>right</code>
* @return int consistent with <code>compare</code> semantics
*/
static int compareParameterTypes(Class[] left, Class[] right, Class[] actual) {
float leftCost = getTotalTransformationCost(actual, left);
float rightCost = getTotalTransformationCost(actual, right);
return leftCost < rightCost ? -1 : rightCost < leftCost ? 1 : 0;
}
/**
* Returns the sum of the object transformation cost for each class in the source
* argument list.
* @param srcArgs The source arguments
* @param destArgs The destination arguments
* @return The total transformation cost
*/
private static float getTotalTransformationCost(Class[] srcArgs,
Class[] destArgs) {
float totalCost = 0.0f;
for (int i = 0; i < srcArgs.length; i++) {
Class srcClass, destClass;
srcClass = srcArgs[i];
destClass = destArgs[i];
totalCost += getObjectTransformationCost(srcClass, destClass);
}
return totalCost;
}
/**
* Gets the number of steps required needed to turn the source class into the
* destination class. This represents the number of steps in the object hierarchy
* graph.
* @param srcClass The source class
* @param destClass The destination class
* @return The cost of transforming an object
*/
private static float getObjectTransformationCost(Class srcClass,
Class destClass) {
if (destClass.isPrimitive()) {
return getPrimitivePromotionCost(srcClass, destClass);
}
float cost = 0.0f;
while (destClass != null && !destClass.equals(srcClass)) {
if (destClass.isInterface()
&& ClassUtils.isAssignable(srcClass, destClass)) {
// slight penalty for interface match.
// we still want an exact match to override an interface match,
// but
// an interface match should override anything where we have to
// get a superclass.
cost += 0.25f;
break;
}
cost++;
destClass = destClass.getSuperclass();
}
/*
* If the destination class is null, we've travelled all the way up to
* an Object match. We'll penalize this by adding 1.5 to the cost.
*/
if (destClass == null) {
cost += 1.5f;
}
return cost;
}
/**
* Get the number of steps required to promote a primitive number to another type.
* @param srcClass the (primitive) source class
* @param destClass the (primitive) destination class
* @return The cost of promoting the primitive
*/
private static float getPrimitivePromotionCost(final Class srcClass,
final Class destClass) {
float cost = 0.0f;
Class cls = srcClass;
if (!cls.isPrimitive()) {
// slight unwrapping penalty
cost += 0.1f;
cls = ClassUtils.wrapperToPrimitive(cls);
}
for (int i = 0; cls != destClass && i < ORDERED_PRIMITIVE_TYPES.length; i++) {
if (cls == ORDERED_PRIMITIVE_TYPES[i]) {
cost += 0.1f;
if (i < ORDERED_PRIMITIVE_TYPES.length - 1) {
cls = ORDERED_PRIMITIVE_TYPES[i + 1];
}
}
}
return cost;
}
}

View File

@ -0,0 +1,847 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.WeakHashMap;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ClassUtils;
/**
* <p> Utility reflection methods focused on methods, originally from Commons BeanUtils.
* Differences from the BeanUtils version may be noted, especially where similar functionality
* already existed within Lang.
* </p>
*
* <h3>Known Limitations</h3>
* <h4>Accessing Public Methods In A Default Access Superclass</h4>
* <p>There is an issue when invoking public methods contained in a default access superclass on JREs prior to 1.4.
* Reflection locates these methods fine and correctly assigns them as public.
* However, an <code>IllegalAccessException</code> is thrown if the method is invoked.</p>
*
* <p><code>MethodUtils</code> contains a workaround for this situation.
* It will attempt to call <code>setAccessible</code> on this method.
* If this call succeeds, then the method can be invoked as normal.
* This call will only succeed when the application has sufficient security privileges.
* If this call fails then the method may fail.</p>
*
* @author Craig R. McClanahan
* @author Ralph Schaer
* @author Chris Audley
* @author Rey Fran&#231;ois
* @author Gregor Ra&#253;man
* @author Jan Sorensen
* @author Robert Burrell Donkin
* @author Niall Pemberton
* @author Matt Benson
* @since 2.5
* @version $Id$
*/
public class MethodUtils {
/**
* Stores a cache of MethodDescriptor -> Method in a WeakHashMap.
* <p>
* The keys into this map only ever exist as temporary variables within
* methods of this class, and are never exposed to users of this class.
* This means that the WeakHashMap is used only as a mechanism for
* limiting the size of the cache, ie a way to tell the garbage collector
* that the contents of the cache can be completely garbage-collected
* whenever it needs the memory. Whether this is a good approach to
* this problem is doubtful; something like the commons-collections
* LRUMap may be more appropriate (though of course selecting an
* appropriate size is an issue).
* <p>
* This static variable is safe even when this code is deployed via a
* shared classloader because it is keyed via a MethodDescriptor object
* which has a Class as one of its members and that member is used in
* the MethodDescriptor.equals method. So two components that load the same
* class via different classloaders will generate non-equal MethodDescriptor
* objects and hence end up with different entries in the map.
*/
private static final WeakHashMap/* <MethodDescriptor, Method> */cache = new WeakHashMap();
/**
* Indicates whether methods should be cached for improved performance.
* <p>
* Note that when this class is deployed via a shared classloader in
* a container, this will affect all webapps. However making this
* configurable per webapp would mean having a map keyed by context classloader
* which may introduce memory-leak problems.
*/
private static boolean cacheMethods = true;
/**
* <p>MethodUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as
* <code>MethodUtils.getAccessibleMethod(method)</code>.</p>
*
* <p>This constructor is public to permit tools that require a JavaBean
* instance to operate.</p>
*/
public MethodUtils() {
super();
}
/**
* Set whether methods should be cached for greater performance or not,
* default is <code>true</code>.
*
* @param cacheMethods <code>true</code> if methods should be
* cached for greater performance, otherwise <code>false</code>
*/
public static synchronized void setCacheMethods(boolean cacheMethods) {
MethodUtils.cacheMethods = cacheMethods;
if (!MethodUtils.cacheMethods) {
clearCache();
}
}
/**
* Clear the method cache.
* @return the number of cached methods cleared
*/
public static synchronized int clearCache() {
int size = cache.size();
cache.clear();
return size;
}
/**
* <p>Invoke a named method whose parameter type matches the object type.</p>
*
* <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> object
* 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 object invoke method on this object
* @param methodName get method with this name
* @param arg use this argument
* @return The value returned by the invoked method
*
* @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 arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
return invokeMethod(object, methodName, new Object[] { arg });
}
/**
* <p>Invoke a named method whose parameter type matches the object type.</p>
*
* <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> object
* 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 object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @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) 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 invokeMethod(object, methodName, args, parameterTypes);
}
/**
* <p>Invoke a named method whose parameter type matches the object type.</p>
*
* <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> object
* 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
* @return The value returned by the invoked method
*
* @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;
}
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
* @return The value returned by the invoked method
*
* @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 {
return invokeExactMethod(object, methodName, new Object[] { arg });
}
/**
* <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
* <code>getAccessibleMethod()</code>.</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
* @return The value returned by the invoked method
*
* @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
* <code>getAccessibleMethod()</code>.</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
* @return The value returned by the invoked method
*
* @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>Invoke a static 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(Class, String, Class[])}.</p>
*
* @param cls invoke static method on this class
* @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
* @return The value returned by the invoked method
*
* @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 invokeExactStaticMethod(Class cls, 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(cls, methodName, parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on class: " + cls.getName());
}
return method.invoke(null, args);
}
/**
* <p>Invoke a named static method whose parameter type matches the object type.</p>
*
* <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</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 #invokeStaticMethod(Class objectClass,String methodName,Object [] args)}.
* </p>
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param arg use this argument
* @return The value returned by the invoked method
*
* @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 invokeStaticMethod(Class cls, String methodName,
Object arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
return invokeStaticMethod(cls, methodName, new Object[] { arg });
}
/**
* <p>Invoke a named static method whose parameter type matches the object type.</p>
*
* <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</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 #invokeStaticMethod(Class objectClass,String methodName,Object [] args,Class[] parameterTypes)}.
* </p>
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @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 invokeStaticMethod(Class cls, 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 invokeStaticMethod(cls, methodName, args, parameterTypes);
}
/**
* <p>Invoke a named static method whose parameter type matches the object type.</p>
*
* <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</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 cls invoke static method on this class
* @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
* @return The value returned by the invoked method
*
* @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 invokeStaticMethod(Class cls, 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;
}
Method method = getMatchingAccessibleMethod(cls, methodName,
parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on class: " + cls.getName());
}
return method.invoke(null, args);
}
/**
* <p>Invoke a static method whose parameter type matches exactly the object
* type.</p>
*
* <p> This is a convenient wrapper for
* {@link #invokeExactStaticMethod(Class objectClass,String methodName,Object [] args)}.
* </p>
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param arg use this argument
* @return The value returned by the invoked method
*
* @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 invokeExactStaticMethod(Class cls, String methodName,
Object arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
return invokeExactStaticMethod(cls, methodName, new Object[] { arg });
}
/**
* <p>Invoke a static 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(Class, String, Class[])}.</p>
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @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 invokeExactStaticMethod(Class cls, 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 invokeExactStaticMethod(cls, methodName, args, parameterTypes);
}
/**
* <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 cls get method from this class
* @param methodName get method with this name
* @param parameterType taking this type of parameter
* @return The accessible method
*/
public static Method getAccessibleMethod(Class cls, String methodName,
Class parameterType) {
return getAccessibleMethod(cls, methodName,
new Class[] { parameterType });
}
/**
* <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 cls get method from this class
* @param methodName get method with this name
* @param parameterTypes with these parameters types
* @return The accessible method
*/
public static Method getAccessibleMethod(Class cls, String methodName,
Class[] parameterTypes) {
try {
MethodDescriptor md = new MethodDescriptor(cls, methodName,
parameterTypes, true);
// Check the cache first
Method method = getCachedMethod(md);
if (method != null) {
return method;
}
method = getAccessibleMethod(cls.getMethod(methodName,
parameterTypes));
cacheMethod(md, method);
return method;
} 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
* @return The accessible method
*/
public static Method getAccessibleMethod(Method method) {
if (!MemberUtils.isAccessible(method)) {
return null;
}
// If the declaring class is public, we are done
Class cls = method.getDeclaringClass();
if (Modifier.isPublic(cls.getModifiers())) {
return method;
}
String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes();
// Check the implemented interfaces and subinterfaces
method = getAccessibleMethodFromInterfaceNest(cls, methodName,
parameterTypes);
// Check the superclass chain
if (method == null) {
method = getAccessibleMethodFromSuperclass(cls, methodName,
parameterTypes);
}
return method;
}
/**
* <p>Return an accessible method (that is, one that can be invoked via
* reflection) by scanning through the superclasses. If no such method
* can be found, return <code>null</code>.</p>
*
* @param cls Class to be checked
* @param methodName Method name of the method we wish to call
* @param parameterTypes The parameter type signatures
*/
private static Method getAccessibleMethodFromSuperclass(Class cls,
String methodName, Class[] parameterTypes) {
Class parentClass = cls.getSuperclass();
while (parentClass != null) {
if (Modifier.isPublic(parentClass.getModifiers())) {
try {
return parentClass.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
return null;
}
}
parentClass = parentClass.getSuperclass();
}
return null;
}
/**
* <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 cls 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 cls,
String methodName, Class[] parameterTypes) {
Method method = null;
// Search up the superclass chain
for (; cls != null; cls = cls.getSuperclass()) {
// Check the implemented interfaces of the parent class
Class[] interfaces = cls.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) {
/*
* Swallow, if no method is found after the loop then this
* method returns null.
*/
}
if (method != null) {
break;
}
// Recursively check our parent interfaces
method = getAccessibleMethodFromInterfaceNest(interfaces[i],
methodName, parameterTypes);
if (method != null) {
break;
}
}
}
return method;
}
/**
* <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 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 cls find method in this class
* @param methodName find method with this name
* @param parameterTypes find method with most compatible parameters
* @return The accessible method
*/
public static Method getMatchingAccessibleMethod(Class cls,
String methodName, Class[] parameterTypes) {
MethodDescriptor md = new MethodDescriptor(cls, methodName,
parameterTypes, false);
// Check the cache first
Method method = getCachedMethod(md);
if (method != null) {
return method;
}
// see if we can find the method directly
// most of the time this works and it's much faster
try {
method = cls.getMethod(methodName, parameterTypes);
MemberUtils.setAccessibleWorkaround(method);
cacheMethod(md, method);
return method;
} catch (NoSuchMethodException e) { /* SWALLOW */
}
// search through all methods
Method bestMatch = null;
Method[] methods = cls.getMethods();
for (int i = 0, size = methods.length; i < size; i++) {
if (methods[i].getName().equals(methodName)) {
// compare parameters
if (ClassUtils.isAssignable(parameterTypes, methods[i]
.getParameterTypes(), true)) {
// get accessible version of method
Method accessibleMethod = getAccessibleMethod(methods[i]);
if (accessibleMethod != null) {
if (bestMatch == null
|| MemberUtils.compareParameterTypes(
accessibleMethod.getParameterTypes(),
bestMatch.getParameterTypes(),
parameterTypes) < 0) {
bestMatch = accessibleMethod;
}
}
}
}
}
if (bestMatch != null) {
MemberUtils.setAccessibleWorkaround(bestMatch);
cacheMethod(md, bestMatch);
}
return bestMatch;
}
/**
* Return the method from the cache, if present.
*
* @param md The method descriptor
* @return The cached method
*/
private static Method getCachedMethod(MethodDescriptor md) {
if (cacheMethods) {
return (Method) cache.get(md);
}
return null;
}
/**
* Add a method to the cache.
*
* @param md The method descriptor
* @param method The method to cache
*/
private static void cacheMethod(MethodDescriptor md, Method method) {
if (cacheMethods) {
if (method != null) {
cache.put(md, method);
}
}
}
/**
* Represents the key to looking up a Method by reflection.
*/
private static class MethodDescriptor {
private Class cls;
private String methodName;
private Class[] paramTypes;
private boolean exact;
private int hashCode;
/**
* The sole constructor.
*
* @param cls the class to reflect, must not be null
* @param methodName the method name to obtain
* @param paramTypes the array of classes representing the paramater types
* @param exact whether the match has to be exact.
*/
public MethodDescriptor(Class cls, String methodName,
Class[] paramTypes, boolean exact) {
if (cls == null) {
throw new IllegalArgumentException("Class cannot be null");
}
if (methodName == null) {
throw new IllegalArgumentException("Method Name cannot be null");
}
if (paramTypes == null) {
paramTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
this.cls = cls;
this.methodName = methodName;
this.paramTypes = paramTypes;
this.exact = exact;
// is this adequate? :/
this.hashCode = methodName.length();
}
/**
* Checks for equality.
* @param obj object to be tested for equality
* @return true, if the object describes the same Method.
*/
public boolean equals(Object obj) {
if (!(obj instanceof MethodDescriptor)) {
return false;
}
MethodDescriptor md = (MethodDescriptor) obj;
return exact == md.exact && methodName.equals(md.methodName)
&& cls.equals(md.cls)
&& Arrays.equals(paramTypes, md.paramTypes);
}
/**
* Returns the string length of method name. I.e. if the
* hashcodes are different, the objects are different. If the
* hashcodes are the same, need to use the equals method to
* determine equality.
* @return the string length of method name.
*/
public int hashCode() {
return hashCode;
}
}
}

View File

@ -0,0 +1,28 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<title></title>
</head>
<body>
Accumulates common high-level uses of the <code>java.lang.reflect</code> APIs.
@since 2.5
</body>
</html>

View File

@ -26,6 +26,7 @@
import org.apache.commons.lang.exception.ExceptionTestSuite;
import org.apache.commons.lang.math.MathTestSuite;
import org.apache.commons.lang.mutable.MutableTestSuite;
import org.apache.commons.lang.reflect.ReflectTestSuite;
import org.apache.commons.lang.text.TextTestSuite;
import org.apache.commons.lang.time.TimeTestSuite;
@ -64,6 +65,7 @@ public static Test suite() {
suite.addTest(ExceptionTestSuite.suite());
suite.addTest(MathTestSuite.suite());
suite.addTest(MutableTestSuite.suite());
suite.addTest(ReflectTestSuite.suite());
suite.addTest(TextTestSuite.suite());
suite.addTest(TimeTestSuite.suite());
return suite;

View File

@ -0,0 +1,229 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.math.NumberUtils;
/**
* Unit tests ConstructorUtils
* @author mbenson
* @version $Id$
*/
public class ConstructorUtilsTest extends TestCase {
public static class TestBean {
private String toString;
public TestBean() {
toString = "()";
}
public TestBean(int i) {
toString = "(int)";
}
public TestBean(Integer i) {
toString = "(Integer)";
}
public TestBean(double d) {
toString = "(double)";
}
public TestBean(String s) {
toString = "(String)";
}
public TestBean(Object o) {
toString = "(Object)";
}
public String toString() {
return toString;
}
}
private static class PrivateClass {
public PrivateClass() {
}
}
private Map classCache;
public ConstructorUtilsTest(String name) {
super(name);
classCache = new HashMap();
}
/**
* Run the test cases as a suite.
* @return the Test
*/
public static Test suite() {
TestSuite suite = new TestSuite(ConstructorUtilsTest.class);
suite.setName("ConstructorUtils Tests");
return suite;
}
protected void setUp() throws Exception {
super.setUp();
classCache.clear();
}
public void testConstructor() throws Exception {
assertNotNull(MethodUtils.class.newInstance());
}
public void testInvokeConstructor() throws Exception {
assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class,
ArrayUtils.EMPTY_CLASS_ARRAY).toString());
assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class,
(Class[]) null).toString());
assertEquals("(String)", ConstructorUtils.invokeConstructor(
TestBean.class, "").toString());
assertEquals("(Object)", ConstructorUtils.invokeConstructor(
TestBean.class, new Object()).toString());
assertEquals("(Object)", ConstructorUtils.invokeConstructor(
TestBean.class, Boolean.TRUE).toString());
assertEquals("(Integer)", ConstructorUtils.invokeConstructor(
TestBean.class, NumberUtils.INTEGER_ONE).toString());
assertEquals("(int)", ConstructorUtils.invokeConstructor(
TestBean.class, NumberUtils.BYTE_ONE).toString());
assertEquals("(double)", ConstructorUtils.invokeConstructor(
TestBean.class, NumberUtils.LONG_ONE).toString());
assertEquals("(double)", ConstructorUtils.invokeConstructor(
TestBean.class, NumberUtils.DOUBLE_ONE).toString());
}
public void testInvokeExactConstructor() throws Exception {
assertEquals("()", ConstructorUtils.invokeExactConstructor(
TestBean.class, ArrayUtils.EMPTY_CLASS_ARRAY).toString());
assertEquals("()", ConstructorUtils.invokeExactConstructor(
TestBean.class, (Class[]) null).toString());
assertEquals("(String)", ConstructorUtils.invokeExactConstructor(
TestBean.class, "").toString());
assertEquals("(Object)", ConstructorUtils.invokeExactConstructor(
TestBean.class, new Object()).toString());
assertEquals("(Integer)", ConstructorUtils.invokeExactConstructor(
TestBean.class, NumberUtils.INTEGER_ONE).toString());
assertEquals("(double)", ConstructorUtils.invokeExactConstructor(
TestBean.class, new Object[] { NumberUtils.DOUBLE_ONE },
new Class[] { Double.TYPE }).toString());
try {
ConstructorUtils.invokeExactConstructor(TestBean.class,
NumberUtils.BYTE_ONE);
fail("should throw NoSuchMethodException");
} catch (NoSuchMethodException e) {
}
try {
ConstructorUtils.invokeExactConstructor(TestBean.class,
NumberUtils.LONG_ONE);
fail("should throw NoSuchMethodException");
} catch (NoSuchMethodException e) {
}
try {
ConstructorUtils.invokeExactConstructor(TestBean.class,
Boolean.TRUE);
fail("should throw NoSuchMethodException");
} catch (NoSuchMethodException e) {
}
}
public void testGetAccessibleConstructor() throws Exception {
assertNotNull(ConstructorUtils.getAccessibleConstructor(Object.class
.getConstructor(ArrayUtils.EMPTY_CLASS_ARRAY)));
assertNull(ConstructorUtils.getAccessibleConstructor(PrivateClass.class
.getConstructor(ArrayUtils.EMPTY_CLASS_ARRAY)));
}
public void testGetAccessibleConstructorFromDescription() throws Exception {
assertNotNull(ConstructorUtils.getAccessibleConstructor(Object.class,
ArrayUtils.EMPTY_CLASS_ARRAY));
assertNull(ConstructorUtils.getAccessibleConstructor(
PrivateClass.class, ArrayUtils.EMPTY_CLASS_ARRAY));
}
public void testGetMatchingAccessibleMethod() throws Exception {
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_CLASS_ARRAY);
expectMatchingAccessibleConstructorParameterTypes(TestBean.class, null,
ArrayUtils.EMPTY_CLASS_ARRAY);
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(String.class), singletonArray(String.class));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Object.class), singletonArray(Object.class));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Boolean.class), singletonArray(Object.class));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Byte.class), singletonArray(Integer.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Byte.TYPE), singletonArray(Integer.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Short.class), singletonArray(Integer.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Short.TYPE), singletonArray(Integer.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Character.class), singletonArray(Integer.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Character.TYPE), singletonArray(Integer.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Integer.class), singletonArray(Integer.class));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Integer.TYPE), singletonArray(Integer.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Long.class), singletonArray(Double.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Long.TYPE), singletonArray(Double.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Float.class), singletonArray(Double.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Float.TYPE), singletonArray(Double.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Double.class), singletonArray(Double.TYPE));
expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
singletonArray(Double.TYPE), singletonArray(Double.TYPE));
}
private void expectMatchingAccessibleConstructorParameterTypes(Class cls,
Class[] requestTypes, Class[] actualTypes) {
Constructor c = ConstructorUtils.getMatchingAccessibleConstructor(cls,
requestTypes);
assertTrue(Arrays.toString(c.getParameterTypes()) + " not equals "
+ Arrays.toString(actualTypes), Arrays.equals(actualTypes, c
.getParameterTypes()));
}
private Class[] singletonArray(Class c) {
Class[] result = (Class[]) classCache.get(c);
if (result == null) {
result = new Class[] { c };
classCache.put(c, result);
}
return result;
}
}

View File

@ -0,0 +1,920 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect;
import java.lang.reflect.Field;
import org.apache.commons.lang.reflect.testbed.Ambig;
import org.apache.commons.lang.reflect.testbed.Foo;
import org.apache.commons.lang.reflect.testbed.PrivatelyShadowedChild;
import org.apache.commons.lang.reflect.testbed.PublicChild;
import org.apache.commons.lang.reflect.testbed.PubliclyShadowedChild;
import org.apache.commons.lang.reflect.testbed.StaticContainer;
import org.apache.commons.lang.reflect.testbed.StaticContainerChild;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit tests FieldUtils
* @author mbenson
* @version $Id$
*/
public class FieldUtilsTest extends TestCase {
static final String S = "s";
static final String SS = "ss";
static final Integer I0 = new Integer(0);
static final Integer I1 = new Integer(1);
static final Double D0 = new Double(0.0);
static final Double D1 = new Double(1.0);
private PublicChild publicChild;
private PubliclyShadowedChild publiclyShadowedChild;
private PrivatelyShadowedChild privatelyShadowedChild;
private Class parentClass = PublicChild.class.getSuperclass();
/**
* Run the test cases as a suite.
* @return the Test
*/
public static Test suite() {
TestSuite suite = new TestSuite(FieldUtilsTest.class);
suite.setName("FieldUtils Tests");
return suite;
}
protected void setUp() throws Exception {
super.setUp();
StaticContainer.reset();
publicChild = new PublicChild();
publiclyShadowedChild = new PubliclyShadowedChild();
privatelyShadowedChild = new PrivatelyShadowedChild();
}
public void testGetField() {
assertEquals(Foo.class, FieldUtils.getField(PublicChild.class, "VALUE").getDeclaringClass());
assertEquals(parentClass, FieldUtils.getField(PublicChild.class, "s").getDeclaringClass());
assertNull(FieldUtils.getField(PublicChild.class, "b"));
assertNull(FieldUtils.getField(PublicChild.class, "i"));
assertNull(FieldUtils.getField(PublicChild.class, "d"));
assertEquals(Foo.class, FieldUtils.getField(PubliclyShadowedChild.class, "VALUE").getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "s")
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "b")
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "i")
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "d")
.getDeclaringClass());
assertEquals(Foo.class, FieldUtils.getField(PrivatelyShadowedChild.class, "VALUE").getDeclaringClass());
assertEquals(parentClass, FieldUtils.getField(PrivatelyShadowedChild.class, "s").getDeclaringClass());
assertNull(FieldUtils.getField(PrivatelyShadowedChild.class, "b"));
assertNull(FieldUtils.getField(PrivatelyShadowedChild.class, "i"));
assertNull(FieldUtils.getField(PrivatelyShadowedChild.class, "d"));
}
public void testGetFieldForceAccess() {
assertEquals(PublicChild.class, FieldUtils.getField(PublicChild.class, "VALUE", true).getDeclaringClass());
assertEquals(parentClass, FieldUtils.getField(PublicChild.class, "s", true).getDeclaringClass());
assertEquals(parentClass, FieldUtils.getField(PublicChild.class, "b", true).getDeclaringClass());
assertEquals(parentClass, FieldUtils.getField(PublicChild.class, "i", true).getDeclaringClass());
assertEquals(parentClass, FieldUtils.getField(PublicChild.class, "d", true).getDeclaringClass());
assertEquals(Foo.class, FieldUtils.getField(PubliclyShadowedChild.class, "VALUE", true).getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "s", true)
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "b", true)
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "i", true)
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "d", true)
.getDeclaringClass());
assertEquals(Foo.class, FieldUtils.getField(PrivatelyShadowedChild.class, "VALUE", true).getDeclaringClass());
assertEquals(PrivatelyShadowedChild.class, FieldUtils.getField(PrivatelyShadowedChild.class, "s", true)
.getDeclaringClass());
assertEquals(PrivatelyShadowedChild.class, FieldUtils.getField(PrivatelyShadowedChild.class, "b", true)
.getDeclaringClass());
assertEquals(PrivatelyShadowedChild.class, FieldUtils.getField(PrivatelyShadowedChild.class, "i", true)
.getDeclaringClass());
assertEquals(PrivatelyShadowedChild.class, FieldUtils.getField(PrivatelyShadowedChild.class, "d", true)
.getDeclaringClass());
}
public void testGetDeclaredField() {
assertNull(FieldUtils.getDeclaredField(PublicChild.class, "VALUE"));
assertNull(FieldUtils.getDeclaredField(PublicChild.class, "s"));
assertNull(FieldUtils.getDeclaredField(PublicChild.class, "b"));
assertNull(FieldUtils.getDeclaredField(PublicChild.class, "i"));
assertNull(FieldUtils.getDeclaredField(PublicChild.class, "d"));
assertNull(FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "VALUE"));
assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "s")
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "b")
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "i")
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "d")
.getDeclaringClass());
assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "VALUE"));
assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "s"));
assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "b"));
assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "i"));
assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "d"));
}
public void testGetDeclaredFieldForceAccess() {
assertEquals(PublicChild.class, FieldUtils.getDeclaredField(PublicChild.class, "VALUE", true)
.getDeclaringClass());
assertNull(FieldUtils.getDeclaredField(PublicChild.class, "s", true));
assertNull(FieldUtils.getDeclaredField(PublicChild.class, "b", true));
assertNull(FieldUtils.getDeclaredField(PublicChild.class, "i", true));
assertNull(FieldUtils.getDeclaredField(PublicChild.class, "d", true));
assertNull(FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "VALUE", true));
assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "s", true)
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "b", true)
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "i", true)
.getDeclaringClass());
assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "d", true)
.getDeclaringClass());
assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "VALUE", true));
assertEquals(PrivatelyShadowedChild.class, FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "s", true)
.getDeclaringClass());
assertEquals(PrivatelyShadowedChild.class, FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "b", true)
.getDeclaringClass());
assertEquals(PrivatelyShadowedChild.class, FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "i", true)
.getDeclaringClass());
assertEquals(PrivatelyShadowedChild.class, FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "d", true)
.getDeclaringClass());
}
public void testReadStaticField() throws Exception {
assertEquals(Foo.VALUE, FieldUtils.readStaticField(FieldUtils.getField(Foo.class, "VALUE")));
}
public void testReadStaticFieldForceAccess() throws Exception {
assertEquals(Foo.VALUE, FieldUtils.readStaticField(FieldUtils.getField(Foo.class, "VALUE")));
assertEquals(Foo.VALUE, FieldUtils.readStaticField(FieldUtils.getField(PublicChild.class, "VALUE")));
}
public void testReadNamedStaticField() throws Exception {
assertEquals(Foo.VALUE, FieldUtils.readStaticField(Foo.class, "VALUE"));
assertEquals(Foo.VALUE, FieldUtils.readStaticField(PubliclyShadowedChild.class, "VALUE"));
assertEquals(Foo.VALUE, FieldUtils.readStaticField(PrivatelyShadowedChild.class, "VALUE"));
assertEquals(Foo.VALUE, FieldUtils.readStaticField(PublicChild.class, "VALUE"));
}
public void testReadNamedStaticFieldForceAccess() throws Exception {
assertEquals(Foo.VALUE, FieldUtils.readStaticField(Foo.class, "VALUE", true));
assertEquals(Foo.VALUE, FieldUtils.readStaticField(PubliclyShadowedChild.class, "VALUE", true));
assertEquals(Foo.VALUE, FieldUtils.readStaticField(PrivatelyShadowedChild.class, "VALUE", true));
assertEquals("child", FieldUtils.readStaticField(PublicChild.class, "VALUE", true));
}
public void testReadDeclaredNamedStaticField() throws Exception {
assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(Foo.class, "VALUE"));
try {
assertEquals("child", FieldUtils.readDeclaredStaticField(PublicChild.class, "VALUE"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(PubliclyShadowedChild.class, "VALUE"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(PrivatelyShadowedChild.class, "VALUE"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
}
public void testReadDeclaredNamedStaticFieldForceAccess() throws Exception {
assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(Foo.class, "VALUE", true));
assertEquals("child", FieldUtils.readDeclaredStaticField(PublicChild.class, "VALUE", true));
try {
assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(PubliclyShadowedChild.class, "VALUE", true));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(PrivatelyShadowedChild.class, "VALUE", true));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
}
public void testReadField() throws Exception {
Field parentS = FieldUtils.getDeclaredField(parentClass, "s");
assertEquals("s", FieldUtils.readField(parentS, publicChild));
assertEquals("s", FieldUtils.readField(parentS, publiclyShadowedChild));
assertEquals("s", FieldUtils.readField(parentS, privatelyShadowedChild));
Field parentB = FieldUtils.getDeclaredField(parentClass, "b", true);
assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, publicChild));
assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, publiclyShadowedChild));
assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, privatelyShadowedChild));
Field parentI = FieldUtils.getDeclaredField(parentClass, "i", true);
assertEquals(I0, FieldUtils.readField(parentI, publicChild));
assertEquals(I0, FieldUtils.readField(parentI, publiclyShadowedChild));
assertEquals(I0, FieldUtils.readField(parentI, privatelyShadowedChild));
Field parentD = FieldUtils.getDeclaredField(parentClass, "d", true);
assertEquals(D0, FieldUtils.readField(parentD, publicChild));
assertEquals(D0, FieldUtils.readField(parentD, publiclyShadowedChild));
assertEquals(D0, FieldUtils.readField(parentD, privatelyShadowedChild));
}
public void testReadFieldForceAccess() throws Exception {
Field parentS = FieldUtils.getDeclaredField(parentClass, "s");
parentS.setAccessible(false);
assertEquals("s", FieldUtils.readField(parentS, publicChild, true));
assertEquals("s", FieldUtils.readField(parentS, publiclyShadowedChild, true));
assertEquals("s", FieldUtils.readField(parentS, privatelyShadowedChild, true));
Field parentB = FieldUtils.getDeclaredField(parentClass, "b", true);
parentB.setAccessible(false);
assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, publicChild, true));
assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, publiclyShadowedChild, true));
assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, privatelyShadowedChild, true));
Field parentI = FieldUtils.getDeclaredField(parentClass, "i", true);
parentI.setAccessible(false);
assertEquals(I0, FieldUtils.readField(parentI, publicChild, true));
assertEquals(I0, FieldUtils.readField(parentI, publiclyShadowedChild, true));
assertEquals(I0, FieldUtils.readField(parentI, privatelyShadowedChild, true));
Field parentD = FieldUtils.getDeclaredField(parentClass, "d", true);
parentD.setAccessible(false);
assertEquals(D0, FieldUtils.readField(parentD, publicChild, true));
assertEquals(D0, FieldUtils.readField(parentD, publiclyShadowedChild, true));
assertEquals(D0, FieldUtils.readField(parentD, privatelyShadowedChild, true));
}
public void testReadNamedField() throws Exception {
assertEquals("s", FieldUtils.readField(publicChild, "s"));
assertEquals("ss", FieldUtils.readField(publiclyShadowedChild, "s"));
assertEquals("s", FieldUtils.readField(privatelyShadowedChild, "s"));
try {
assertEquals(Boolean.FALSE, FieldUtils.readField(publicChild, "b"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals(Boolean.TRUE, FieldUtils.readField(publiclyShadowedChild, "b"));
try {
assertEquals(Boolean.FALSE, FieldUtils.readField(privatelyShadowedChild, "b"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
assertEquals(I0, FieldUtils.readField(publicChild, "i"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals(I1, FieldUtils.readField(publiclyShadowedChild, "i"));
try {
assertEquals(I0, FieldUtils.readField(privatelyShadowedChild, "i"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
assertEquals(D0, FieldUtils.readField(publicChild, "d"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals(D1, FieldUtils.readField(publiclyShadowedChild, "d"));
try {
assertEquals(D0, FieldUtils.readField(privatelyShadowedChild, "d"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
}
public void testReadNamedFieldForceAccess() throws Exception {
assertEquals("s", FieldUtils.readField(publicChild, "s", true));
assertEquals("ss", FieldUtils.readField(publiclyShadowedChild, "s", true));
assertEquals("ss", FieldUtils.readField(privatelyShadowedChild, "s", true));
assertEquals(Boolean.FALSE, FieldUtils.readField(publicChild, "b", true));
assertEquals(Boolean.TRUE, FieldUtils.readField(publiclyShadowedChild, "b", true));
assertEquals(Boolean.TRUE, FieldUtils.readField(privatelyShadowedChild, "b", true));
assertEquals(I0, FieldUtils.readField(publicChild, "i", true));
assertEquals(I1, FieldUtils.readField(publiclyShadowedChild, "i", true));
assertEquals(I1, FieldUtils.readField(privatelyShadowedChild, "i", true));
assertEquals(D0, FieldUtils.readField(publicChild, "d", true));
assertEquals(D1, FieldUtils.readField(publiclyShadowedChild, "d", true));
assertEquals(D1, FieldUtils.readField(privatelyShadowedChild, "d", true));
}
public void testReadDeclaredNamedField() throws Exception {
try {
assertEquals("s", FieldUtils.readDeclaredField(publicChild, "s"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals("ss", FieldUtils.readDeclaredField(publiclyShadowedChild, "s"));
try {
assertEquals("s", FieldUtils.readDeclaredField(privatelyShadowedChild, "s"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(publicChild, "b"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals(Boolean.TRUE, FieldUtils.readDeclaredField(publiclyShadowedChild, "b"));
try {
assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(privatelyShadowedChild, "b"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
assertEquals(I0, FieldUtils.readDeclaredField(publicChild, "i"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals(I1, FieldUtils.readDeclaredField(publiclyShadowedChild, "i"));
try {
assertEquals(I0, FieldUtils.readDeclaredField(privatelyShadowedChild, "i"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
assertEquals(D0, FieldUtils.readDeclaredField(publicChild, "d"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals(D1, FieldUtils.readDeclaredField(publiclyShadowedChild, "d"));
try {
assertEquals(D0, FieldUtils.readDeclaredField(privatelyShadowedChild, "d"));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
}
public void testReadDeclaredNamedFieldForceAccess() throws Exception {
try {
assertEquals("s", FieldUtils.readDeclaredField(publicChild, "s", true));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals("ss", FieldUtils.readDeclaredField(publiclyShadowedChild, "s", true));
assertEquals("ss", FieldUtils.readDeclaredField(privatelyShadowedChild, "s", true));
try {
assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(publicChild, "b", true));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals(Boolean.TRUE, FieldUtils.readDeclaredField(publiclyShadowedChild, "b", true));
assertEquals(Boolean.TRUE, FieldUtils.readDeclaredField(privatelyShadowedChild, "b", true));
try {
assertEquals(I0, FieldUtils.readDeclaredField(publicChild, "i", true));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals(I1, FieldUtils.readDeclaredField(publiclyShadowedChild, "i", true));
assertEquals(I1, FieldUtils.readDeclaredField(privatelyShadowedChild, "i", true));
try {
assertEquals(D0, FieldUtils.readDeclaredField(publicChild, "d", true));
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
assertEquals(D1, FieldUtils.readDeclaredField(publiclyShadowedChild, "d", true));
assertEquals(D1, FieldUtils.readDeclaredField(privatelyShadowedChild, "d", true));
}
public void testWriteStaticField() throws Exception {
Field field = StaticContainer.class.getDeclaredField("mutablePublic");
FieldUtils.writeStaticField(field, "new");
assertEquals("new", StaticContainer.mutablePublic);
field = StaticContainer.class.getDeclaredField("mutableProtected");
try {
FieldUtils.writeStaticField(field, "new");
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
field = StaticContainer.class.getDeclaredField("mutablePackage");
try {
FieldUtils.writeStaticField(field, "new");
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
field = StaticContainer.class.getDeclaredField("mutablePrivate");
try {
FieldUtils.writeStaticField(field, "new");
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
field = StaticContainer.class.getDeclaredField("IMMUTABLE_PUBLIC");
try {
FieldUtils.writeStaticField(field, "new");
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
field = StaticContainer.class.getDeclaredField("IMMUTABLE_PROTECTED");
try {
FieldUtils.writeStaticField(field, "new");
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
field = StaticContainer.class.getDeclaredField("IMMUTABLE_PACKAGE");
try {
FieldUtils.writeStaticField(field, "new");
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
field = StaticContainer.class.getDeclaredField("IMMUTABLE_PRIVATE");
try {
FieldUtils.writeStaticField(field, "new");
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
}
public void testWriteStaticFieldForceAccess() throws Exception {
Field field = StaticContainer.class.getDeclaredField("mutablePublic");
FieldUtils.writeStaticField(field, "new", true);
assertEquals("new", StaticContainer.mutablePublic);
field = StaticContainer.class.getDeclaredField("mutableProtected");
FieldUtils.writeStaticField(field, "new", true);
assertEquals("new", StaticContainer.getMutableProtected());
field = StaticContainer.class.getDeclaredField("mutablePackage");
FieldUtils.writeStaticField(field, "new", true);
assertEquals("new", StaticContainer.getMutablePackage());
field = StaticContainer.class.getDeclaredField("mutablePrivate");
FieldUtils.writeStaticField(field, "new", true);
assertEquals("new", StaticContainer.getMutablePrivate());
field = StaticContainer.class.getDeclaredField("IMMUTABLE_PUBLIC");
try {
FieldUtils.writeStaticField(field, "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
field = StaticContainer.class.getDeclaredField("IMMUTABLE_PROTECTED");
try {
FieldUtils.writeStaticField(field, "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
field = StaticContainer.class.getDeclaredField("IMMUTABLE_PACKAGE");
try {
FieldUtils.writeStaticField(field, "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
field = StaticContainer.class.getDeclaredField("IMMUTABLE_PRIVATE");
try {
FieldUtils.writeStaticField(field, "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
}
public void testWriteNamedStaticField() throws Exception {
FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePublic", "new");
assertEquals("new", StaticContainer.mutablePublic);
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "mutableProtected", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePackage", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePrivate", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PUBLIC", "new");
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PROTECTED", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PACKAGE", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PRIVATE", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
}
public void testWriteNamedStaticFieldForceAccess() throws Exception {
FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePublic", "new", true);
assertEquals("new", StaticContainer.mutablePublic);
FieldUtils.writeStaticField(StaticContainerChild.class, "mutableProtected", "new", true);
assertEquals("new", StaticContainer.getMutableProtected());
FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePackage", "new", true);
assertEquals("new", StaticContainer.getMutablePackage());
FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePrivate", "new", true);
assertEquals("new", StaticContainer.getMutablePrivate());
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PUBLIC", "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PROTECTED", "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PACKAGE", "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
try {
FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PRIVATE", "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
}
public void testWriteDeclaredNamedStaticField() throws Exception {
FieldUtils.writeStaticField(StaticContainer.class, "mutablePublic", "new");
assertEquals("new", StaticContainer.mutablePublic);
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutableProtected", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutablePackage", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutablePrivate", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PUBLIC", "new");
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PROTECTED", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PACKAGE", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PRIVATE", "new");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
}
public void testWriteDeclaredNamedStaticFieldForceAccess() throws Exception {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutablePublic", "new", true);
assertEquals("new", StaticContainer.mutablePublic);
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutableProtected", "new", true);
assertEquals("new", StaticContainer.getMutableProtected());
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutablePackage", "new", true);
assertEquals("new", StaticContainer.getMutablePackage());
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutablePrivate", "new", true);
assertEquals("new", StaticContainer.getMutablePrivate());
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PUBLIC", "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PROTECTED", "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PACKAGE", "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
try {
FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PRIVATE", "new", true);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
}
public void testWriteField() throws Exception {
Field field = parentClass.getDeclaredField("s");
FieldUtils.writeField(field, publicChild, "S");
assertEquals("S", field.get(publicChild));
field = parentClass.getDeclaredField("b");
try {
FieldUtils.writeField(field, publicChild, Boolean.TRUE);
fail("Expected IllegalAccessException");
} catch (IllegalAccessException e) {
// pass
}
field = parentClass.getDeclaredField("i");
try {
FieldUtils.writeField(field, publicChild, new Integer(Integer.MAX_VALUE));
} catch (IllegalAccessException e) {
// pass
}
field = parentClass.getDeclaredField("d");
try {
FieldUtils.writeField(field, publicChild, new Double(Double.MAX_VALUE));
} catch (IllegalAccessException e) {
// pass
}
}
public void testWriteFieldForceAccess() throws Exception {
Field field = parentClass.getDeclaredField("s");
FieldUtils.writeField(field, publicChild, "S", true);
assertEquals("S", field.get(publicChild));
field = parentClass.getDeclaredField("b");
FieldUtils.writeField(field, publicChild, Boolean.TRUE, true);
assertEquals(Boolean.TRUE, field.get(publicChild));
field = parentClass.getDeclaredField("i");
FieldUtils.writeField(field, publicChild, new Integer(Integer.MAX_VALUE), true);
assertEquals(new Integer(Integer.MAX_VALUE), field.get(publicChild));
field = parentClass.getDeclaredField("d");
FieldUtils.writeField(field, publicChild, new Double(Double.MAX_VALUE), true);
assertEquals(new Double(Double.MAX_VALUE), field.get(publicChild));
}
public void testWriteNamedField() throws Exception {
FieldUtils.writeField(publicChild, "s", "S");
assertEquals("S", FieldUtils.readField(publicChild, "s"));
try {
FieldUtils.writeField(publicChild, "b", Boolean.TRUE);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeField(publicChild, "i", new Integer(1));
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeField(publicChild, "d", new Double(1.0));
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
FieldUtils.writeField(publiclyShadowedChild, "s", "S");
assertEquals("S", FieldUtils.readField(publiclyShadowedChild, "s"));
FieldUtils.writeField(publiclyShadowedChild, "b", Boolean.FALSE);
assertEquals(Boolean.FALSE, FieldUtils.readField(publiclyShadowedChild, "b"));
FieldUtils.writeField(publiclyShadowedChild, "i", new Integer(0));
assertEquals(new Integer(0), FieldUtils.readField(publiclyShadowedChild, "i"));
FieldUtils.writeField(publiclyShadowedChild, "d", new Double(0.0));
assertEquals(new Double(0.0), FieldUtils.readField(publiclyShadowedChild, "d"));
FieldUtils.writeField(privatelyShadowedChild, "s", "S");
assertEquals("S", FieldUtils.readField(privatelyShadowedChild, "s"));
try {
FieldUtils.writeField(privatelyShadowedChild, "b", Boolean.TRUE);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeField(privatelyShadowedChild, "i", new Integer(1));
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeField(privatelyShadowedChild, "d", new Double(1.0));
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
}
public void testWriteNamedFieldForceAccess() throws Exception {
FieldUtils.writeField(publicChild, "s", "S", true);
assertEquals("S", FieldUtils.readField(publicChild, "s", true));
FieldUtils.writeField(publicChild, "b", Boolean.TRUE, true);
assertEquals(Boolean.TRUE, FieldUtils.readField(publicChild, "b", true));
FieldUtils.writeField(publicChild, "i", new Integer(1), true);
assertEquals(new Integer(1), FieldUtils.readField(publicChild, "i", true));
FieldUtils.writeField(publicChild, "d", new Double(1.0), true);
assertEquals(new Double(1.0), FieldUtils.readField(publicChild, "d", true));
FieldUtils.writeField(publiclyShadowedChild, "s", "S", true);
assertEquals("S", FieldUtils.readField(publiclyShadowedChild, "s", true));
FieldUtils.writeField(publiclyShadowedChild, "b", Boolean.FALSE, true);
assertEquals(Boolean.FALSE, FieldUtils.readField(publiclyShadowedChild, "b", true));
FieldUtils.writeField(publiclyShadowedChild, "i", new Integer(0), true);
assertEquals(new Integer(0), FieldUtils.readField(publiclyShadowedChild, "i", true));
FieldUtils.writeField(publiclyShadowedChild, "d", new Double(0.0), true);
assertEquals(new Double(0.0), FieldUtils.readField(publiclyShadowedChild, "d", true));
FieldUtils.writeField(privatelyShadowedChild, "s", "S", true);
assertEquals("S", FieldUtils.readField(privatelyShadowedChild, "s", true));
FieldUtils.writeField(privatelyShadowedChild, "b", Boolean.FALSE, true);
assertEquals(Boolean.FALSE, FieldUtils.readField(privatelyShadowedChild, "b", true));
FieldUtils.writeField(privatelyShadowedChild, "i", new Integer(0), true);
assertEquals(new Integer(0), FieldUtils.readField(privatelyShadowedChild, "i", true));
FieldUtils.writeField(privatelyShadowedChild, "d", new Double(0.0), true);
assertEquals(new Double(0.0), FieldUtils.readField(privatelyShadowedChild, "d", true));
}
public void testWriteDeclaredNamedField() throws Exception {
try {
FieldUtils.writeDeclaredField(publicChild, "s", "S");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredField(publicChild, "b", Boolean.TRUE);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredField(publicChild, "i", new Integer(1));
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredField(publicChild, "d", new Double(1.0));
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
FieldUtils.writeDeclaredField(publiclyShadowedChild, "s", "S");
assertEquals("S", FieldUtils.readDeclaredField(publiclyShadowedChild, "s"));
FieldUtils.writeDeclaredField(publiclyShadowedChild, "b", Boolean.FALSE);
assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(publiclyShadowedChild, "b"));
FieldUtils.writeDeclaredField(publiclyShadowedChild, "i", new Integer(0));
assertEquals(new Integer(0), FieldUtils.readDeclaredField(publiclyShadowedChild, "i"));
FieldUtils.writeDeclaredField(publiclyShadowedChild, "d", new Double(0.0));
assertEquals(new Double(0.0), FieldUtils.readDeclaredField(publiclyShadowedChild, "d"));
try {
FieldUtils.writeDeclaredField(privatelyShadowedChild, "s", "S");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredField(privatelyShadowedChild, "b", Boolean.TRUE);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredField(privatelyShadowedChild, "i", new Integer(1));
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredField(privatelyShadowedChild, "d", new Double(1.0));
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
}
public void testWriteDeclaredNamedFieldForceAccess() throws Exception {
try {
FieldUtils.writeDeclaredField(publicChild, "s", "S", true);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredField(publicChild, "b", Boolean.TRUE, true);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredField(publicChild, "i", new Integer(1), true);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
try {
FieldUtils.writeDeclaredField(publicChild, "d", new Double(1.0), true);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// pass
}
FieldUtils.writeDeclaredField(publiclyShadowedChild, "s", "S", true);
assertEquals("S", FieldUtils.readDeclaredField(publiclyShadowedChild, "s", true));
FieldUtils.writeDeclaredField(publiclyShadowedChild, "b", Boolean.FALSE, true);
assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(publiclyShadowedChild, "b", true));
FieldUtils.writeDeclaredField(publiclyShadowedChild, "i", new Integer(0), true);
assertEquals(new Integer(0), FieldUtils.readDeclaredField(publiclyShadowedChild, "i", true));
FieldUtils.writeDeclaredField(publiclyShadowedChild, "d", new Double(0.0), true);
assertEquals(new Double(0.0), FieldUtils.readDeclaredField(publiclyShadowedChild, "d", true));
FieldUtils.writeDeclaredField(privatelyShadowedChild, "s", "S", true);
assertEquals("S", FieldUtils.readDeclaredField(privatelyShadowedChild, "s", true));
FieldUtils.writeDeclaredField(privatelyShadowedChild, "b", Boolean.FALSE, true);
assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(privatelyShadowedChild, "b", true));
FieldUtils.writeDeclaredField(privatelyShadowedChild, "i", new Integer(0), true);
assertEquals(new Integer(0), FieldUtils.readDeclaredField(privatelyShadowedChild, "i", true));
FieldUtils.writeDeclaredField(privatelyShadowedChild, "d", new Double(0.0), true);
assertEquals(new Double(0.0), FieldUtils.readDeclaredField(privatelyShadowedChild, "d", true));
}
public void testAmbig() {
try {
FieldUtils.getField(Ambig.class, "VALUE");
fail("should have failed on interface field ambiguity");
} catch (IllegalArgumentException e) {
// pass
}
}
}

View File

@ -0,0 +1,342 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.mutable.Mutable;
import org.apache.commons.lang.mutable.MutableObject;
/**
* Unit tests MethodUtils
* @author mbenson
* @version $Id$
*/
public class MethodUtilsTest extends TestCase {
public static class TestBean {
public static String bar() {
return "bar()";
}
public static String bar(int i) {
return "bar(int)";
}
public static String bar(Integer i) {
return "bar(Integer)";
}
public static String bar(double d) {
return "bar(double)";
}
public static String bar(String s) {
return "bar(String)";
}
public static String bar(Object o) {
return "bar(Object)";
}
public String foo() {
return "foo()";
}
public String foo(int i) {
return "foo(int)";
}
public String foo(Integer i) {
return "foo(Integer)";
}
public String foo(double d) {
return "foo(double)";
}
public String foo(String s) {
return "foo(String)";
}
public String foo(Object o) {
return "foo(Object)";
}
}
private static class TestMutable implements Mutable {
public Object getValue() {
return null;
}
public void setValue(Object value) {
}
}
private TestBean testBean;
private Map classCache;
public MethodUtilsTest(String name) {
super(name);
classCache = new HashMap();
}
/**
* Run the test cases as a suite.
* @return the Test
*/
public static Test suite() {
TestSuite suite = new TestSuite(MethodUtilsTest.class);
suite.setName("MethodUtils Tests");
return suite;
}
protected void setUp() throws Exception {
super.setUp();
testBean = new TestBean();
classCache.clear();
}
public void testConstructor() throws Exception {
assertNotNull(MethodUtils.class.newInstance());
}
public void testInvokeMethod() throws Exception {
assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo",
ArrayUtils.EMPTY_CLASS_ARRAY));
assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo",
(Class[]) null));
assertEquals("foo(String)", MethodUtils.invokeMethod(testBean, "foo",
""));
assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo",
new Object()));
assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo",
Boolean.TRUE));
assertEquals("foo(Integer)", MethodUtils.invokeMethod(testBean, "foo",
NumberUtils.INTEGER_ONE));
assertEquals("foo(int)", MethodUtils.invokeMethod(testBean, "foo",
NumberUtils.BYTE_ONE));
assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo",
NumberUtils.LONG_ONE));
assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo",
NumberUtils.DOUBLE_ONE));
}
public void testInvokeExactMethod() throws Exception {
assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo",
ArrayUtils.EMPTY_CLASS_ARRAY));
assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo",
(Class[]) null));
assertEquals("foo(String)", MethodUtils.invokeExactMethod(testBean,
"foo", ""));
assertEquals("foo(Object)", MethodUtils.invokeExactMethod(testBean,
"foo", new Object()));
assertEquals("foo(Integer)", MethodUtils.invokeExactMethod(testBean,
"foo", NumberUtils.INTEGER_ONE));
assertEquals("foo(double)", MethodUtils.invokeExactMethod(testBean,
"foo", new Object[] { NumberUtils.DOUBLE_ONE },
new Class[] { Double.TYPE }));
try {
MethodUtils
.invokeExactMethod(testBean, "foo", NumberUtils.BYTE_ONE);
fail("should throw NoSuchMethodException");
} catch (NoSuchMethodException e) {
}
try {
MethodUtils
.invokeExactMethod(testBean, "foo", NumberUtils.LONG_ONE);
fail("should throw NoSuchMethodException");
} catch (NoSuchMethodException e) {
}
try {
MethodUtils.invokeExactMethod(testBean, "foo", Boolean.TRUE);
fail("should throw NoSuchMethodException");
} catch (NoSuchMethodException e) {
}
}
public void testInvokeStaticMethod() throws Exception {
assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class,
"bar", ArrayUtils.EMPTY_CLASS_ARRAY));
assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class,
"bar", (Class[]) null));
assertEquals("bar(String)", MethodUtils.invokeStaticMethod(
TestBean.class, "bar", ""));
assertEquals("bar(Object)", MethodUtils.invokeStaticMethod(
TestBean.class, "bar", new Object()));
assertEquals("bar(Object)", MethodUtils.invokeStaticMethod(
TestBean.class, "bar", Boolean.TRUE));
assertEquals("bar(Integer)", MethodUtils.invokeStaticMethod(
TestBean.class, "bar", NumberUtils.INTEGER_ONE));
assertEquals("bar(int)", MethodUtils.invokeStaticMethod(TestBean.class,
"bar", NumberUtils.BYTE_ONE));
assertEquals("bar(double)", MethodUtils.invokeStaticMethod(
TestBean.class, "bar", NumberUtils.LONG_ONE));
assertEquals("bar(double)", MethodUtils.invokeStaticMethod(
TestBean.class, "bar", NumberUtils.DOUBLE_ONE));
}
public void testInvokeExactStaticMethod() throws Exception {
assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class,
"bar", ArrayUtils.EMPTY_CLASS_ARRAY));
assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class,
"bar", (Class[]) null));
assertEquals("bar(String)", MethodUtils.invokeExactStaticMethod(
TestBean.class, "bar", ""));
assertEquals("bar(Object)", MethodUtils.invokeExactStaticMethod(
TestBean.class, "bar", new Object()));
assertEquals("bar(Integer)", MethodUtils.invokeExactStaticMethod(
TestBean.class, "bar", NumberUtils.INTEGER_ONE));
assertEquals("bar(double)", MethodUtils.invokeExactStaticMethod(
TestBean.class, "bar", new Object[] { NumberUtils.DOUBLE_ONE },
new Class[] { Double.TYPE }));
try {
MethodUtils.invokeExactStaticMethod(TestBean.class, "bar",
NumberUtils.BYTE_ONE);
fail("should throw NoSuchMethodException");
} catch (NoSuchMethodException e) {
}
try {
MethodUtils.invokeExactStaticMethod(TestBean.class, "bar",
NumberUtils.LONG_ONE);
fail("should throw NoSuchMethodException");
} catch (NoSuchMethodException e) {
}
try {
MethodUtils.invokeExactStaticMethod(TestBean.class, "bar",
Boolean.TRUE);
fail("should throw NoSuchMethodException");
} catch (NoSuchMethodException e) {
}
}
public void testGetAccessibleInterfaceMethod() throws Exception {
Class[][] p = { ArrayUtils.EMPTY_CLASS_ARRAY, null };
for (int i = 0; i < p.length; i++) {
Method method = TestMutable.class.getMethod("getValue", p[i]);
Method accessibleMethod = MethodUtils.getAccessibleMethod(method);
assertNotSame(accessibleMethod, method);
assertSame(Mutable.class, accessibleMethod.getDeclaringClass());
}
}
public void testGetAccessibleInterfaceMethodFromDescription()
throws Exception {
Class[][] p = { ArrayUtils.EMPTY_CLASS_ARRAY, null };
for (int i = 0; i < p.length; i++) {
Method accessibleMethod = MethodUtils.getAccessibleMethod(
TestMutable.class, "getValue", p[i]);
assertSame(Mutable.class, accessibleMethod.getDeclaringClass());
}
}
public void testGetAccessiblePublicMethod() throws Exception {
assertSame(MutableObject.class, MethodUtils.getAccessibleMethod(
MutableObject.class.getMethod("getValue",
ArrayUtils.EMPTY_CLASS_ARRAY)).getDeclaringClass());
}
public void testGetAccessiblePublicMethodFromDescription() throws Exception {
assertSame(MutableObject.class, MethodUtils.getAccessibleMethod(
MutableObject.class, "getValue", ArrayUtils.EMPTY_CLASS_ARRAY)
.getDeclaringClass());
}
public void testGetMatchingAccessibleMethod() throws Exception {
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_CLASS_ARRAY);
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
null, ArrayUtils.EMPTY_CLASS_ARRAY);
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(String.class), singletonArray(String.class));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Object.class), singletonArray(Object.class));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Boolean.class), singletonArray(Object.class));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Byte.class), singletonArray(Integer.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Byte.TYPE), singletonArray(Integer.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Short.class), singletonArray(Integer.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Short.TYPE), singletonArray(Integer.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Character.class), singletonArray(Integer.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Character.TYPE), singletonArray(Integer.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Integer.class), singletonArray(Integer.class));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Integer.TYPE), singletonArray(Integer.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Long.class), singletonArray(Double.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Long.TYPE), singletonArray(Double.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Float.class), singletonArray(Double.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Float.TYPE), singletonArray(Double.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Double.class), singletonArray(Double.TYPE));
expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
singletonArray(Double.TYPE), singletonArray(Double.TYPE));
}
private void expectMatchingAccessibleMethodParameterTypes(Class cls,
String methodName, Class[] requestTypes, Class[] actualTypes) {
Method m = MethodUtils.getMatchingAccessibleMethod(cls, methodName,
requestTypes);
assertTrue(Arrays.toString(m.getParameterTypes()) + " not equals "
+ Arrays.toString(actualTypes), Arrays.equals(actualTypes, m
.getParameterTypes()));
}
public void testSetCacheMethods() throws Exception {
MethodUtils.clearCache();
MethodUtils.setCacheMethods(true);
MethodUtils.invokeMethod(testBean, "foo", "");
assertEquals(1, MethodUtils.clearCache());
assertEquals(0, MethodUtils.clearCache());
MethodUtils.setCacheMethods(false);
MethodUtils.invokeMethod(testBean, "foo", "");
assertEquals(0, MethodUtils.clearCache());
MethodUtils.setCacheMethods(true);
}
private Class[] singletonArray(Class c) {
Class[] result = (Class[]) classCache.get(c);
if (result == null) {
result = new Class[] { c };
classCache.put(c, result);
}
return result;
}
}

View File

@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.textui.TestRunner;
/**
* Test suite for the reflect package.
*
* @author Matt Benson
* @version $Id$
*/
public class ReflectTestSuite extends TestCase {
/**
* Construct a new instance.
*/
public ReflectTestSuite(String name) {
super(name);
}
/**
* Command-line interface.
*/
public static void main(String[] args) {
TestRunner.run(suite());
}
/**
* Get the suite of tests
*/
public static Test suite() {
TestSuite suite = new TestSuite();
suite.setName("Commons-Lang-Reflect Tests");
suite.addTest(ConstructorUtilsTest.suite());
suite.addTest(FieldUtilsTest.suite());
suite.addTest(MethodUtilsTest.suite());
return suite;
}
}

View File

@ -0,0 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect.testbed;
/**
* @author mbenson
* @version $Id$
*/
public class Ambig implements Foo, Bar {
}

View File

@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect.testbed;
/**
* @author mbenson
* @version $Id$
*/
public interface Bar {
public static final String VALUE = "bar";
}

View File

@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect.testbed;
/**
* @author mbenson
* @version $Id$
*/
public interface Foo {
public static final String VALUE = "foo";
}

View File

@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect.testbed;
/**
* @author mbenson
* @version $Id$
*/
class Parent implements Foo {
public String s = "s";
protected boolean b = false;
int i = 0;
private double d = 0.0;
}

View File

@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect.testbed;
/**
* @author mbenson
* @version $Id$
*/
public class PrivatelyShadowedChild extends Parent {
private String s = "ss";
private boolean b = true;
private int i = 1;
private double d = 1.0;
}

View File

@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect.testbed;
/**
* @author mbenson
* @version $Id$
*/
public class PublicChild extends Parent {
static final String VALUE = "child";
}

View File

@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect.testbed;
/**
* @author mbenson
* @version $Id$
*/
public class PubliclyShadowedChild extends Parent {
public String s = "ss";
public boolean b = true;
public int i = 1;
public double d = 1.0;
}

View File

@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect.testbed;
/**
* @author mbenson
* @version $Id$
*/
public class StaticContainer {
public static final Object IMMUTABLE_PUBLIC = "public";
protected static final Object IMMUTABLE_PROTECTED = "protected";
static final Object IMMUTABLE_PACKAGE = "";
private static final Object IMMUTABLE_PRIVATE = "private";
public static Object mutablePublic;
protected static Object mutableProtected;
static Object mutablePackage;
private static Object mutablePrivate;
public static void reset() {
mutablePublic = null;
mutableProtected = null;
mutablePackage = null;
mutablePrivate = null;
}
public static Object getMutableProtected() {
return mutableProtected;
}
public static Object getMutablePackage() {
return mutablePackage;
}
public static Object getMutablePrivate() {
return mutablePrivate;
}
}

View File

@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect.testbed;
/**
* @author mbenson
* @version $Id$
*/
public class StaticContainerChild extends StaticContainer {
}