📄 methodutils.java
字号:
/*
* 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.beanutils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.WeakHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* <p> Utility reflection methods focussed on methods in general rather than properties in particular. </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.
* 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 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 François
* @author Gregor Raýman
* @author Jan Sorensen
* @author Robert Burrell Donkin
*/
public class MethodUtils {
// --------------------------------------------------------- Private Methods
/**
* Only log warning about accessibility work around once.
* <p>
* Note that this is broken when this class is deployed via a shared
* classloader in a container, as the warning message will be emitted
* only once, not once per webapp. However making the warning appear
* once per webapp means having a map keyed by context classloader
* which introduces nasty memory-leak problems. As this warning is
* really optional we can ignore this problem; only one of the webapps
* will get the warning in its logs but that should be good enough.
*/
private static boolean loggedAccessibleWarning = false;
/** An empty class array */
private static final Class[] EMPTY_CLASS_PARAMETERS = new Class[0];
/** An empty object array */
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
/**
* 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 WeakHashMap cache = new WeakHashMap();
// --------------------------------------------------------- Public Methods
/**
* <p>Invoke a named method whose parameter type matches the object type.</p>
*
* <p>The behaviour of this method is less deterministic
* than <code>invokeExactMethod()</code>.
* It loops through all methods with names that match
* and then executes the first it finds with compatable parameters.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> class
* would match a <code>boolean</code> primitive.</p>
*
* <p> This is a convenient wrapper for
* {@link #invokeMethod(Object object,String methodName,Object [] args)}.
* </p>
*
* @param 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 {
Object[] args = {arg};
return invokeMethod(object, methodName, args);
}
/**
* <p>Invoke a named method whose parameter type matches the object type.</p>
*
* <p>The behaviour of this method is less deterministic
* than {@link #invokeExactMethod(Object object,String methodName,Object [] args)}.
* It loops through all methods with names that match
* and then executes the first it finds with compatable parameters.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> class
* would match a <code>boolean</code> primitive.</p>
*
* <p> This is a convenient wrapper for
* {@link #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
* </p>
*
* @param 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 = 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>The behaviour of this method is less deterministic
* than {@link
* #invokeExactMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
* It loops through all methods with names that match
* and then executes the first it finds with compatable parameters.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> class
* would match a <code>boolean</code> primitive.</p>
*
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
* @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 = 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);
}
/**
* <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 {
Object[] args = {arg};
return invokeExactMethod(object, methodName, args);
}
/**
* <p>Invoke a method whose parameter types match exactly the object
* types.</p>
*
* <p> This uses reflection to invoke the method obtained from a call to
* <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 = 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -