Utility reflection methods focussed on methods in general rather than properties in particular.
There is an issue when invoking public methods contained in a default access superclass.
Reflection locates these methods fine and correctly assigns them as public.
However, an IllegalAccessException is thrown if the method is invoked.
| Method from org.apache.commons.beanutils.MethodUtils Detail: |
public static synchronized int clearCache() {
int size = cache.size();
cache.clear();
return size;
}
|
public static Method getAccessibleMethod(Method method) {
// Make sure we have a method to check
if (method == null) {
return (null);
}
return getAccessibleMethod(method.getDeclaringClass(), method);
}
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 null.
|
public static Method getAccessibleMethod(Class clazz,
Method method) {
// Make sure we have a method to check
if (method == null) {
return (null);
}
// If the requested method is not public we cannot call it
if (!Modifier.isPublic(method.getModifiers())) {
return (null);
}
boolean sameClass = true;
if (clazz == null) {
clazz = method.getDeclaringClass();
} else {
sameClass = clazz.equals(method.getDeclaringClass());
if (!method.getDeclaringClass().isAssignableFrom(clazz)) {
throw new IllegalArgumentException(clazz.getName() +
" is not assignable from " + method.getDeclaringClass().getName());
}
}
// If the class is public, we are done
if (Modifier.isPublic(clazz.getModifiers())) {
if (!sameClass && !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
setMethodAccessible(method); // Default access superclass workaround
}
return (method);
}
String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes();
// Check the implemented interfaces and subinterfaces
method =
getAccessibleMethodFromInterfaceNest(clazz,
methodName,
parameterTypes);
// Check the superclass chain
if (method == null) {
method = getAccessibleMethodFromSuperclass(clazz,
methodName,
parameterTypes);
}
return (method);
}
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 null.
|
public static Method getAccessibleMethod(Class clazz,
String methodName,
Class parameterType) {
Class[] parameterTypes = {parameterType};
return getAccessibleMethod(clazz, methodName, parameterTypes);
}
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 null.
Basically, a convenience wrapper that constructs a Class
array for you.
|
public static Method getAccessibleMethod(Class clazz,
String methodName,
Class[] parameterTypes) {
try {
MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, true);
// Check the cache first
Method method = getCachedMethod(md);
if (method != null) {
return method;
}
method = getAccessibleMethod
(clazz, clazz.getMethod(methodName, parameterTypes));
cacheMethod(md, method);
return method;
} catch (NoSuchMethodException e) {
return (null);
}
}
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 null.
This is just a convenient wrapper for
#getAccessibleMethod(Method method) .
|
public static Method getMatchingAccessibleMethod(Class clazz,
String methodName,
Class[] parameterTypes) {
// trace logging
Log log = LogFactory.getLog(MethodUtils.class);
if (log.isTraceEnabled()) {
log.trace("Matching name=" + methodName + " on " + clazz);
}
MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, false);
// see if we can find the method directly
// most of the time this works and it's much faster
try {
// Check the cache first
Method method = getCachedMethod(md);
if (method != null) {
return method;
}
method = clazz.getMethod(methodName, parameterTypes);
if (log.isTraceEnabled()) {
log.trace("Found straight match: " + method);
log.trace("isPublic:" + Modifier.isPublic(method.getModifiers()));
}
setMethodAccessible(method); // Default access superclass workaround
cacheMethod(md, method);
return method;
} catch (NoSuchMethodException e) { /* SWALLOW */ }
// search through all methods
int paramSize = parameterTypes.length;
Method bestMatch = null;
Method[] methods = clazz.getMethods();
float bestMatchCost = Float.MAX_VALUE;
float myCost = Float.MAX_VALUE;
for (int i = 0, size = methods.length; i < size ; i++) {
if (methods[i].getName().equals(methodName)) {
// log some trace information
if (log.isTraceEnabled()) {
log.trace("Found matching name:");
log.trace(methods[i]);
}
// compare parameters
Class[] methodsParams = methods[i].getParameterTypes();
int methodParamSize = methodsParams.length;
if (methodParamSize == paramSize) {
boolean match = true;
for (int n = 0 ; n < methodParamSize; n++) {
if (log.isTraceEnabled()) {
log.trace("Param=" + parameterTypes[n].getName());
log.trace("Method=" + methodsParams[n].getName());
}
if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) {
if (log.isTraceEnabled()) {
log.trace(methodsParams[n] + " is not assignable from "
+ parameterTypes[n]);
}
match = false;
break;
}
}
if (match) {
// get accessible version of method
Method method = getAccessibleMethod(clazz, methods[i]);
if (method != null) {
if (log.isTraceEnabled()) {
log.trace(method + " accessible version of "
+ methods[i]);
}
setMethodAccessible(method); // Default access superclass workaround
myCost = getTotalTransformationCost(parameterTypes,method.getParameterTypes());
if ( myCost < bestMatchCost ) {
bestMatch = method;
bestMatchCost = myCost;
}
}
log.trace("Couldn't find accessible method.");
}
}
}
}
if ( bestMatch != null ){
cacheMethod(md, bestMatch);
} else {
// didn't find a match
log.trace("No match found.");
}
return bestMatch;
}
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.
This method is slightly undeterminstic since it loops
through methods names and return the first matching method.
This method is used by
#invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes) .
This method can match primitive parameter by passing in wrapper classes.
For example, a Boolean will match a primitive boolean
parameter.
|
public static Class getPrimitiveType(Class wrapperType) {
// does anyone know a better strategy than comparing names?
if (Boolean.class.equals(wrapperType)) {
return boolean.class;
} else if (Float.class.equals(wrapperType)) {
return float.class;
} else if (Long.class.equals(wrapperType)) {
return long.class;
} else if (Integer.class.equals(wrapperType)) {
return int.class;
} else if (Short.class.equals(wrapperType)) {
return short.class;
} else if (Byte.class.equals(wrapperType)) {
return byte.class;
} else if (Double.class.equals(wrapperType)) {
return double.class;
} else if (Character.class.equals(wrapperType)) {
return char.class;
} else {
Log log = LogFactory.getLog(MethodUtils.class);
if (log.isDebugEnabled()) {
log.debug("Not a known primitive wrapper class: " + wrapperType);
}
return null;
}
}
Gets the class for the primitive type corresponding to the primitive wrapper class given.
For example, an instance of Boolean.class returns a boolean.class. |
public static Class getPrimitiveWrapper(Class primitiveType) {
// does anyone know a better strategy than comparing names?
if (boolean.class.equals(primitiveType)) {
return Boolean.class;
} else if (float.class.equals(primitiveType)) {
return Float.class;
} else if (long.class.equals(primitiveType)) {
return Long.class;
} else if (int.class.equals(primitiveType)) {
return Integer.class;
} else if (short.class.equals(primitiveType)) {
return Short.class;
} else if (byte.class.equals(primitiveType)) {
return Byte.class;
} else if (double.class.equals(primitiveType)) {
return Double.class;
} else if (char.class.equals(primitiveType)) {
return Character.class;
} else {
return null;
}
}
Gets the wrapper object class for the given primitive type class.
For example, passing boolean.class returns Boolean.class |
public static Object invokeExactMethod(Object object,
String methodName,
Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Object[] args = {arg};
return invokeExactMethod(object, methodName, args);
}
|
public static Object invokeExactMethod(Object object,
String methodName,
Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (args == null) {
args = 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);
}
Invoke a method whose parameter types match exactly the object
types.
This uses reflection to invoke the method obtained from a call to
getAccessibleMethod().
|
public static Object invokeExactMethod(Object object,
String methodName,
Object[] args,
Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (args == null) {
args = EMPTY_OBJECT_ARRAY;
}
if (parameterTypes == null) {
parameterTypes = EMPTY_CLASS_PARAMETERS;
}
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);
}
Invoke a method whose parameter types match exactly the parameter
types given.
This uses reflection to invoke the method obtained from a call to
getAccessibleMethod().
|
public static Object invokeExactStaticMethod(Class objectClass,
String methodName,
Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Object[] args = {arg};
return invokeExactStaticMethod (objectClass, methodName, args);
}
|
public static Object invokeExactStaticMethod(Class objectClass,
String methodName,
Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (args == null) {
args = 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(objectClass, methodName, args, parameterTypes);
}
|
public static Object invokeExactStaticMethod(Class objectClass,
String methodName,
Object[] args,
Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (args == null) {
args = EMPTY_OBJECT_ARRAY;
}
if (parameterTypes == null) {
parameterTypes = EMPTY_CLASS_PARAMETERS;
}
Method method = getAccessibleMethod(
objectClass,
methodName,
parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: " +
methodName + "() on class: " + objectClass.getName());
}
return method.invoke(null, args);
}
|
public static Object invokeMethod(Object object,
String methodName,
Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Object[] args = {arg};
return invokeMethod(object, methodName, args);
}
Invoke a named method whose parameter type matches the object type.
The behaviour of this method is less deterministic
than invokeExactMethod().
It loops through all methods with names that match
and then executes the first it finds with compatable parameters.
This method supports calls to methods taking primitive parameters
via passing in wrapping classes. So, for example, a Boolean class
would match a boolean primitive.
This is a convenient wrapper for
#invokeMethod(Object object,String methodName,Object [] args) .
|
public static Object invokeMethod(Object object,
String methodName,
Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (args == null) {
args = 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);
}
|
public static Object invokeMethod(Object object,
String methodName,
Object[] args,
Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (parameterTypes == null) {
parameterTypes = EMPTY_CLASS_PARAMETERS;
}
if (args == null) {
args = 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);
}
Invoke a named method whose parameter type matches the object type.
The behaviour of this method is less deterministic
than #invokeExactMethod(Object object,String methodName,Object [] args,Class[] parameterTypes) .
It loops through all methods with names that match
and then executes the first it finds with compatable parameters.
This method supports calls to methods taking primitive parameters
via passing in wrapping classes. So, for example, a Boolean class
would match a boolean primitive.
|
public static Object invokeStaticMethod(Class objectClass,
String methodName,
Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Object[] args = {arg};
return invokeStaticMethod (objectClass, methodName, args);
}
|
public static Object invokeStaticMethod(Class objectClass,
String methodName,
Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (args == null) {
args = 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 (objectClass, methodName, args, parameterTypes);
}
|
public static Object invokeStaticMethod(Class objectClass,
String methodName,
Object[] args,
Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (parameterTypes == null) {
parameterTypes = EMPTY_CLASS_PARAMETERS;
}
if (args == null) {
args = EMPTY_OBJECT_ARRAY;
}
Method method = getMatchingAccessibleMethod(
objectClass,
methodName,
parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: " +
methodName + "() on class: " + objectClass.getName());
}
return method.invoke(null, args);
}
Invoke a named static method whose parameter type matches the object type.
The behaviour of this method is less deterministic
than #invokeExactStaticMethod(Class objectClass,String methodName,Object [] args,Class[] parameterTypes) .
It loops through all methods with names that match
and then executes the first it finds with compatable parameters.
This method supports calls to methods taking primitive parameters
via passing in wrapping classes. So, for example, a Boolean class
would match a boolean primitive.
|
public static final boolean isAssignmentCompatible(Class parameterType,
Class parameterization) {
// try plain assignment
if (parameterType.isAssignableFrom(parameterization)) {
return true;
}
if (parameterType.isPrimitive()) {
// this method does *not* do widening - you must specify exactly
// is this the right behaviour?
Class parameterWrapperClazz = getPrimitiveWrapper(parameterType);
if (parameterWrapperClazz != null) {
return parameterWrapperClazz.equals(parameterization);
}
}
return false;
}
Determine whether a type can be used as a parameter in a method invocation.
This method handles primitive conversions correctly.
In order words, it will match a Boolean to a boolean,
a Long to a long,
a Float to a float,
a Integer to a int,
and a Double to a double.
Now logic widening matches are allowed.
For example, a Long will not match a int.
|
public static synchronized void setCacheMethods(boolean cacheMethods) {
CACHE_METHODS = cacheMethods;
if (!CACHE_METHODS) {
clearCache();
}
}
Set whether methods should be cached for greater performance or not,
default is true. |
public static Class toNonPrimitiveClass(Class clazz) {
if (clazz.isPrimitive()) {
Class primitiveClazz = MethodUtils.getPrimitiveWrapper(clazz);
// the above method returns
if (primitiveClazz != null) {
return primitiveClazz;
} else {
return clazz;
}
} else {
return clazz;
}
}
Find a non primitive representation for given primitive class. |