LANG-436 Remove caching from MethodUtils

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@654159 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Niall Pemberton 2008-05-07 16:06:21 +00:00
parent e0da000caa
commit 585e4c6eb3
2 changed files with 2 additions and 182 deletions

View File

@ -58,38 +58,6 @@ import org.apache.commons.lang.ClassUtils;
*/
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
@ -102,30 +70,6 @@ public class 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>
*
@ -561,17 +505,8 @@ public class MethodUtils {
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,
return getAccessibleMethod(cls.getMethod(methodName,
parameterTypes));
cacheMethod(md, method);
return method;
} catch (NoSuchMethodException e) {
return (null);
}
@ -708,19 +643,9 @@ public class MethodUtils {
*/
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);
Method method = cls.getMethod(methodName, parameterTypes);
MemberUtils.setAccessibleWorkaround(method);
cacheMethod(md, method);
return method;
} catch (NoSuchMethodException e) { /* SWALLOW */
}
@ -748,100 +673,7 @@ public class MethodUtils {
}
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

@ -318,18 +318,6 @@ public class MethodUtilsTest extends TestCase {
.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 String toString(Class[] c) {
return Arrays.asList(c).toString();
}