You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ni...@apache.org on 2008/03/13 17:21:50 UTC

svn commit: r636797 - in /commons/proper/beanutils/trunk/src: java/org/apache/commons/beanutils/MethodUtils.java test/org/apache/commons/beanutils/MethodUtilsTestCase.java

Author: niallp
Date: Thu Mar 13 09:21:49 2008
New Revision: 636797

URL: http://svn.apache.org/viewvc?rev=636797&view=rev
Log:
BEANUTILS-310 - Provide facility to configure and clear MethodUtils cache

Modified:
    commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/MethodUtils.java
    commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/MethodUtilsTestCase.java

Modified: commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/MethodUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/MethodUtils.java?rev=636797&r1=636796&r2=636797&view=diff
==============================================================================
--- commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/MethodUtils.java (original)
+++ commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/MethodUtils.java Thu Mar 13 09:21:49 2008
@@ -68,6 +68,16 @@
      * will get the warning in its logs but that should be good enough.
      */
     private static boolean loggedAccessibleWarning = false;
+    
+    /** 
+     * 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 CACHE_METHODS = true;
 
     /** An empty class array */
     private static final Class[] EMPTY_CLASS_PARAMETERS = new Class[0];
@@ -97,6 +107,30 @@
     private static WeakHashMap cache = new WeakHashMap();
     
     // --------------------------------------------------------- Public Methods
+
+    /**
+     * 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) {
+        CACHE_METHODS = cacheMethods;
+        if (!CACHE_METHODS) {
+            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>
@@ -677,14 +711,14 @@
         try {
             MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, true);
             // Check the cache first
-            Method method = (Method)cache.get(md);
+            Method method = getCachedMethod(md);
             if (method != null) {
                 return method;
             }
             
             method =  getAccessibleMethod
                     (clazz.getMethod(methodName, parameterTypes));
-            cache.put(md, method);
+            cacheMethod(md, method);
             return method;
         } catch (NoSuchMethodException e) {
             return (null);
@@ -873,7 +907,7 @@
         // most of the time this works and it's much faster
         try {
             // Check the cache first
-            Method method = (Method)cache.get(md);
+            Method method = getCachedMethod(md);
             if (method != null) {
                 return method;
             }
@@ -932,7 +966,7 @@
                         "Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.", 
                         se);
             }
-            cache.put(md, method);
+            cacheMethod(md, method);
             return method;
             
         } catch (NoSuchMethodException e) { /* SWALLOW */ }
@@ -1010,7 +1044,7 @@
             }
         }
         if ( bestMatch != null ){
-                 cache.put(md, bestMatch);  
+                 cacheMethod(md, bestMatch);
         } else {
         // didn't find a match
                log.trace("No match found.");
@@ -1194,6 +1228,33 @@
         }
     }
     
+
+    /**
+     * Return the method from the cache, if present.
+     *
+     * @param md The method descriptor
+     * @return The cached method
+     */
+    private static Method getCachedMethod(MethodDescriptor md) {
+        if (CACHE_METHODS) {
+            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 (CACHE_METHODS) {
+            if (method != null) {
+                cache.put(md, method);
+            }
+        }
+    }
 
     /**
      * Represents the key to looking up a Method by reflection.

Modified: commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/MethodUtilsTestCase.java
URL: http://svn.apache.org/viewvc/commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/MethodUtilsTestCase.java?rev=636797&r1=636796&r2=636797&view=diff
==============================================================================
--- commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/MethodUtilsTestCase.java (original)
+++ commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/MethodUtilsTestCase.java Thu Mar 13 09:21:49 2008
@@ -580,4 +580,51 @@
         MethodUtils.invokeMethod(a, "foo", ps);
         assertTrue("Method Invoked(2)", a.called);
     }
+
+    /**
+     * Test {@link MethodUtils#clearCache()}.
+     */
+    public void testClearCache() {
+
+        MethodUtils.clearCache(); // make sure it starts empty
+        PublicSubBean bean = new PublicSubBean();
+        try {
+            MethodUtils.invokeMethod(bean, "setFoo", "alpha");
+        } catch (Throwable t) {
+            fail("invokeMethod() threw " + t);
+        }
+        assertEquals(1, MethodUtils.clearCache());
+        assertEquals(0, MethodUtils.clearCache());
+    }
+
+    /**
+     * Test {@link MethodUtils#setCacheMethods(boolean)}.
+     */
+    public void testSetCacheMethods() {
+
+        MethodUtils.clearCache(); // make sure it starts empty
+
+        // caching
+        MethodUtils.setCacheMethods(true);
+        PublicSubBean bean = new PublicSubBean();
+        try {
+            MethodUtils.invokeMethod(bean, "setFoo", "alpha");
+        } catch (Throwable t) {
+            fail("invokeMethod() threw " + t);
+        }
+        assertEquals(1, MethodUtils.clearCache());
+        assertEquals(0, MethodUtils.clearCache());
+
+        // no caching
+        MethodUtils.setCacheMethods(false);
+        try {
+            MethodUtils.invokeMethod(bean, "setFoo", "alpha");
+        } catch (Throwable t) {
+            fail("invokeMethod() threw " + t);
+        }
+        assertEquals(0, MethodUtils.clearCache());
+
+        // reset default
+        MethodUtils.setCacheMethods(true);
+    }
 }