Updated method utils with latest code from the beanutils version.
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137124 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
15508a27a2
commit
4914d5c807
|
@ -74,12 +74,20 @@ import org.apache.commons.lang.StringUtils;
|
||||||
* programmer. This can break an implementation if used incorrectly. This
|
* programmer. This can break an implementation if used incorrectly. This
|
||||||
* facility should be used with care.
|
* facility should be used with care.
|
||||||
*
|
*
|
||||||
* @author Based on code from BeanUtils
|
|
||||||
* @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
|
* @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
|
||||||
* @version $Id: MethodUtils.java,v 1.1 2002/10/24 23:12:54 scolebourne Exp $
|
* @author Based on code from <code>BeanUtils</code> by: Craig R. McClanahan
|
||||||
|
* @author Ralph Schaer
|
||||||
|
* @author Chris Audley
|
||||||
|
* @author Rey François
|
||||||
|
* @author Gregor Raýman
|
||||||
|
* @author Jan Sorensen
|
||||||
|
* @author Robert Burrell Donkin
|
||||||
|
* @version $Id: MethodUtils.java,v 1.2 2002/11/14 18:51:57 rdonkin Exp $
|
||||||
*/
|
*/
|
||||||
public class MethodUtils {
|
public class MethodUtils {
|
||||||
|
|
||||||
|
public static final boolean debug = true;
|
||||||
|
|
||||||
/** An empty method array */
|
/** An empty method array */
|
||||||
public static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
|
public static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
|
||||||
|
|
||||||
|
@ -329,15 +337,15 @@ public class MethodUtils {
|
||||||
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
//return null;
|
||||||
// Method method = getMatchingAccessibleMethod(
|
Method method = getMatchingAccessibleMethod(
|
||||||
// object.getClass(),
|
object.getClass(),
|
||||||
// methodName,
|
methodName,
|
||||||
// parameterTypes);
|
parameterTypes);
|
||||||
// if (method == null)
|
if (method == null)
|
||||||
// throw new NoSuchMethodException("No such accessible method: " +
|
throw new NoSuchMethodException("No such accessible method: " +
|
||||||
// methodName + "() on object: " + object.getClass().getName());
|
methodName + "() on object: " + object.getClass().getName());
|
||||||
// return method.invoke(object, args);
|
return method.invoke(object, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -608,143 +616,202 @@ return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * <p>Find an accessible method that matches the given name and has compatible parameters.
|
/**
|
||||||
// * Compatible parameters mean that every method parameter is assignable from
|
* <p>Find an accessible method that matches the given name and has compatible parameters.
|
||||||
// * the given parameters.
|
* Compatible parameters mean that every method parameter is assignable from
|
||||||
// * In other words, it finds a method with the given name
|
* the given parameters.
|
||||||
// * that will take the parameters given.<p>
|
* In other words, it finds a method with the given name
|
||||||
// *
|
* that will take the parameters given.<p>
|
||||||
// * <p>This method is slightly undeterminstic since it loops
|
*
|
||||||
// * through methods names and return the first matching method.</p>
|
* <p>This method is slightly undeterminstic since it loops
|
||||||
// *
|
* through methods names and return the first matching method.</p>
|
||||||
// * <p>This method is used by
|
*
|
||||||
// * {@link
|
* <p>This method is used by
|
||||||
// * #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
|
* {@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>
|
* <p>This method can match primitive parameter by passing in wrapper classes.
|
||||||
// * parameter.
|
* For example, a <code>Boolean</code> will match a primitive <code>boolean</code>
|
||||||
// *
|
* parameter.
|
||||||
// * @param clazz find method in this class
|
*
|
||||||
// * @param methodName find method with this name
|
* @param clazz find method in this class
|
||||||
// * @param parameterTypes find method with compatible parameters
|
* @param methodName find method with this name
|
||||||
// */
|
* @param parameterTypes find method with compatible parameters
|
||||||
// private static Method getMatchingAccessibleMethod(
|
*/
|
||||||
// Class clazz,
|
private static Method getMatchingAccessibleMethod(
|
||||||
// String methodName,
|
Class clazz,
|
||||||
// Class[] parameterTypes) {
|
String methodName,
|
||||||
// // trace logging
|
Class[] parameterTypes) {
|
||||||
// if (log.isTraceEnabled()) {
|
// trace logging
|
||||||
// log.trace("Matching name=" + methodName + " on " + clazz);
|
if (debug) {
|
||||||
// }
|
log("Matching name=" + methodName + " on " + clazz);
|
||||||
//
|
}
|
||||||
// // see if we can find the method directly
|
|
||||||
// // most of the time this works and it's much faster
|
// see if we can find the method directly
|
||||||
// try {
|
// most of the time this works and it's much faster
|
||||||
// Method method = clazz.getMethod(methodName, parameterTypes);
|
try {
|
||||||
// return method;
|
Method method = clazz.getMethod(methodName, parameterTypes);
|
||||||
//
|
if (debug) {
|
||||||
// } catch (NoSuchMethodException e) { /* SWALLOW */ }
|
log("Found straight match: " + method);
|
||||||
//
|
log("isPublic:" + Modifier.isPublic(method.getModifiers()));
|
||||||
// // search through all methods
|
}
|
||||||
// int paramSize = parameterTypes.length;
|
|
||||||
// Method[] methods = clazz.getMethods();
|
try {
|
||||||
// for (int i = 0, size = methods.length; i < size ; i++) {
|
//
|
||||||
// if (methods[i].getName().equals(methodName)) {
|
// XXX Default access superclass workaround
|
||||||
// // log some trace information
|
//
|
||||||
// if (log.isTraceEnabled()) {
|
// When a public class has a default access superclass
|
||||||
// log.trace("Found matching name:");
|
// with public methods, these methods are accessible.
|
||||||
// log.trace(methods[i]);
|
// Calling them from compiled code works fine.
|
||||||
// }
|
//
|
||||||
//
|
// Unfortunately, using reflection to invoke these methods
|
||||||
// // compare parameters
|
// seems to (wrongly) to prevent access even when the method
|
||||||
// Class[] methodsParams = methods[i].getParameterTypes();
|
// modifer is public.
|
||||||
// int methodParamSize = methodsParams.length;
|
//
|
||||||
// if (methodParamSize == paramSize) {
|
// The following workaround solves the problem but will only
|
||||||
// boolean match = true;
|
// work from sufficiently privilages code.
|
||||||
// for (int n = 0 ; n < methodParamSize; n++) {
|
//
|
||||||
// if (log.isTraceEnabled()) {
|
// Better workarounds would be greatfully accepted.
|
||||||
// log.trace("Param=" + parameterTypes[n].getName());
|
//
|
||||||
// log.trace("Method=" + methodsParams[n].getName());
|
method.setAccessible(true);
|
||||||
// }
|
|
||||||
// if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) {
|
} catch (SecurityException se) {
|
||||||
// if (log.isTraceEnabled()) {
|
// log but continue just in case the method.invoke works anyway
|
||||||
// log.trace(methodsParams[n] + " is not assignable from "
|
log(
|
||||||
// + parameterTypes[n]);
|
"Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.",
|
||||||
// }
|
se);
|
||||||
// match = false;
|
}
|
||||||
// break;
|
return method;
|
||||||
// }
|
|
||||||
// }
|
} catch (NoSuchMethodException e) { /* SWALLOW */ }
|
||||||
//
|
|
||||||
// if (match) {
|
// search through all methods
|
||||||
// // get accessible version of method
|
int paramSize = parameterTypes.length;
|
||||||
// Method method = getAccessibleMethod(methods[i]);
|
Method[] methods = clazz.getMethods();
|
||||||
// if (method != null) {
|
for (int i = 0, size = methods.length; i < size ; i++) {
|
||||||
// if (log.isTraceEnabled()) {
|
if (methods[i].getName().equals(methodName)) {
|
||||||
// log.trace(method + " accessible version of "
|
// log some trace information
|
||||||
// + methods[i]);
|
if (debug) {
|
||||||
// }
|
log("Found matching name:");
|
||||||
// return method;
|
log(methods[i]);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// log.trace("Couldn't find accessible method.");
|
// compare parameters
|
||||||
// }
|
Class[] methodsParams = methods[i].getParameterTypes();
|
||||||
// }
|
int methodParamSize = methodsParams.length;
|
||||||
// }
|
if (methodParamSize == paramSize) {
|
||||||
// }
|
boolean match = true;
|
||||||
//
|
for (int n = 0 ; n < methodParamSize; n++) {
|
||||||
// // didn't find a match
|
if (debug) {
|
||||||
// log.trace("No match found.");
|
log("Param=" + parameterTypes[n].getName());
|
||||||
// return null;
|
log("Method=" + methodsParams[n].getName());
|
||||||
// }
|
}
|
||||||
//
|
if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) {
|
||||||
// /**
|
if (debug) {
|
||||||
// * <p>Determine whether a type can be used as a parameter in a method invocation.
|
log(methodsParams[n] + " is not assignable from "
|
||||||
// * This method handles primitive conversions correctly.</p>
|
+ parameterTypes[n]);
|
||||||
// *
|
}
|
||||||
// * <p>In order words, it will match a <code>Boolean</code> to a <code>boolean</code>,
|
match = false;
|
||||||
// * a <code>Long</code> to a <code>long</code>,
|
break;
|
||||||
// * a <code>Float</code> to a <code>float</code>,
|
}
|
||||||
// * a <code>Integer</code> to a <code>int</code>,
|
}
|
||||||
// * and a <code>Double</code> to a <code>double</code>.
|
|
||||||
// * Now logic widening matches are allowed.
|
if (match) {
|
||||||
// * For example, a <code>Long</code> will not match a <code>int</code>.
|
// get accessible version of method
|
||||||
// *
|
Method method = getAccessibleMethod(methods[i]);
|
||||||
// * @param parameterType the type of parameter accepted by the method
|
if (method != null) {
|
||||||
// * @param parameterization the type of parameter being tested
|
if (debug) {
|
||||||
// *
|
log(method + " accessible version of "
|
||||||
// * @return true if the assignement is compatible.
|
+ methods[i]);
|
||||||
// */
|
}
|
||||||
// private static final boolean isAssignmentCompatible(Class parameterType, Class parameterization) {
|
try {
|
||||||
// // try plain assignment
|
//
|
||||||
// if (parameterType.isAssignableFrom(parameterization)) {
|
// XXX Default access superclass workaround
|
||||||
// return true;
|
// (See above for more details.)
|
||||||
// }
|
//
|
||||||
//
|
method.setAccessible(true);
|
||||||
// if (parameterType.isPrimitive()) {
|
|
||||||
// // does anyone know a better strategy than comparing names?
|
} catch (SecurityException se) {
|
||||||
// // also, this method does *not* do widening - you must specify exactly
|
// log but continue just in case the method.invoke works anyway
|
||||||
// // is this the right behaviour?
|
log(
|
||||||
// if (boolean.class.equals(parameterType)) {
|
"Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.",
|
||||||
// return Boolean.class.equals(parameterization);
|
se);
|
||||||
// }
|
}
|
||||||
// if (float.class.equals(parameterType)) {
|
return method;
|
||||||
// return Float.class.equals(parameterization);
|
}
|
||||||
// }
|
|
||||||
// if (long.class.equals(parameterType)) {
|
log("Couldn't find accessible method.");
|
||||||
// return Long.class.equals(parameterization);
|
}
|
||||||
// }
|
}
|
||||||
// if (int.class.equals(parameterType)) {
|
}
|
||||||
// return Integer.class.equals(parameterization);
|
}
|
||||||
// }
|
|
||||||
// if (double.class.equals(parameterType)) {
|
// didn't find a match
|
||||||
// return Double.class.equals(parameterization);
|
log("No match found.");
|
||||||
// }
|
return null;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// return false;
|
|
||||||
// }
|
/**
|
||||||
//
|
* <p>Determine whether a type can be used as a parameter in a method invocation.
|
||||||
|
* This method handles primitive conversions correctly.</p>
|
||||||
|
*
|
||||||
|
* <p>In order words, it will match a <code>Boolean</code> to a <code>boolean</code>,
|
||||||
|
* a <code>Long</code> to a <code>long</code>,
|
||||||
|
* a <code>Float</code> to a <code>float</code>,
|
||||||
|
* a <code>Integer</code> to a <code>int</code>,
|
||||||
|
* and a <code>Double</code> to a <code>double</code>.
|
||||||
|
* Now logic widening matches are allowed.
|
||||||
|
* For example, a <code>Long</code> will not match a <code>int</code>.
|
||||||
|
*
|
||||||
|
* @param parameterType the type of parameter accepted by the method
|
||||||
|
* @param parameterization the type of parameter being tested
|
||||||
|
*
|
||||||
|
* @return true if the assignement is compatible.
|
||||||
|
*/
|
||||||
|
private static final boolean isAssignmentCompatible(Class parameterType, Class parameterization) {
|
||||||
|
// try plain assignment
|
||||||
|
if (parameterType.isAssignableFrom(parameterization)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameterType.isPrimitive()) {
|
||||||
|
// does anyone know a better strategy than comparing names?
|
||||||
|
// also, this method does *not* do widening - you must specify exactly
|
||||||
|
// is this the right behaviour?
|
||||||
|
if (boolean.class.equals(parameterType)) {
|
||||||
|
return Boolean.class.equals(parameterization);
|
||||||
|
}
|
||||||
|
if (float.class.equals(parameterType)) {
|
||||||
|
return Float.class.equals(parameterization);
|
||||||
|
}
|
||||||
|
if (long.class.equals(parameterType)) {
|
||||||
|
return Long.class.equals(parameterization);
|
||||||
|
}
|
||||||
|
if (int.class.equals(parameterType)) {
|
||||||
|
return Integer.class.equals(parameterization);
|
||||||
|
}
|
||||||
|
if (double.class.equals(parameterType)) {
|
||||||
|
return Double.class.equals(parameterization);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void log(Object o) {
|
||||||
|
if (debug) {
|
||||||
|
System.err.println(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void log(Object o, Throwable t) {
|
||||||
|
if (debug) {
|
||||||
|
System.err.println(o);
|
||||||
|
System.err.println(t);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue