Revision: 314
Author:   tfenne
Date:     2006-05-12 19:11:11 -0700 (Fri, 12 May 2006)
ViewCVS:  http://svn.sourceforge.net/stripes/?rev=314&view=rev

Log Message:
-----------
Fix for STS-201: Make it possible to execute before/after methods that are 
protected/package/private access.

Modified Paths:
--------------
    trunk/stripes/src/net/sourceforge/stripes/action/After.java
    trunk/stripes/src/net/sourceforge/stripes/action/Before.java
    
trunk/stripes/src/net/sourceforge/stripes/controller/BeforeAfterMethodInterceptor.java
    trunk/stripes/src/net/sourceforge/stripes/util/ReflectUtil.java
    
trunk/tests/src/net/sourceforge/stripes/controller/BeforeAfterMethodInterceptorTests.java
    trunk/tests/tests.iml
Modified: trunk/stripes/src/net/sourceforge/stripes/action/After.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/action/After.java 2006-05-13 
00:29:48 UTC (rev 313)
+++ trunk/stripes/src/net/sourceforge/stripes/action/After.java 2006-05-13 
02:11:11 UTC (rev 314)
@@ -29,9 +29,10 @@
  * method will be run after each stage completes. If no LifecycleStage is 
specified then the
  * default is to execute the method after [EMAIL PROTECTED] 
LifecycleStage#EventHandling}.</p>
  *
- * <p>The method may have any name, but must by public and take no arguments. 
Methods may return
- * values; if the value is a [EMAIL PROTECTED] 
net.sourceforge.stripes.action.Resolution} it will be used
- * immediately to terminate the request.  Any other values returned will be 
ignored.</p>
+ * <p>The method may have any name, any access specifier (public, private 
etc.) and must take
+ * no arguments. Methods may return values; if the value is a
+ * [EMAIL PROTECTED] net.sourceforge.stripes.action.Resolution} it will be 
used immediately to terminate
+ * the request.  Any other values returned will be ignored.</p>
  *
  * <p>Examples:</p>
  *<pre>

Modified: trunk/stripes/src/net/sourceforge/stripes/action/Before.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/action/Before.java        
2006-05-13 00:29:48 UTC (rev 313)
+++ trunk/stripes/src/net/sourceforge/stripes/action/Before.java        
2006-05-13 02:11:11 UTC (rev 314)
@@ -31,9 +31,10 @@
  * [EMAIL PROTECTED] LifecycleStage#ActionBeanResolution} <b>cannot</b> be 
specified because there is
  * no ActionBean to run a method on before the ActionBean has been 
resolved!</p>
  *
- * <p>The method may have any name, but must by public and take no arguments. 
Methods may return
- * values; if the value is a [EMAIL PROTECTED] 
net.sourceforge.stripes.action.Resolution} it will be used
- * immediately to terminate the request.  Any other values returned will be 
ignored.</p>
+ * <p>The method may have any name, any access specifier (public, private 
etc.) and must take
+ * no arguments. Methods may return values; if the value is a
+ * [EMAIL PROTECTED] net.sourceforge.stripes.action.Resolution} it will be 
used immediately to terminate
+ * the request.  Any other values returned will be ignored.</p>
  *
  * <p>Examples:</p>
  *<pre>

Modified: 
trunk/stripes/src/net/sourceforge/stripes/controller/BeforeAfterMethodInterceptor.java
===================================================================
--- 
trunk/stripes/src/net/sourceforge/stripes/controller/BeforeAfterMethodInterceptor.java
      2006-05-13 00:29:48 UTC (rev 313)
+++ 
trunk/stripes/src/net/sourceforge/stripes/controller/BeforeAfterMethodInterceptor.java
      2006-05-13 02:11:11 UTC (rev 314)
@@ -19,6 +19,7 @@
 import net.sourceforge.stripes.action.Before;
 import net.sourceforge.stripes.action.Resolution;
 import net.sourceforge.stripes.util.Log;
+import net.sourceforge.stripes.util.ReflectUtil;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationTargetException;
@@ -29,6 +30,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Collection;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -181,37 +183,49 @@
                        filterMethodsCache.put(beanClass, filterMethods);
                
                        // Look for @Before and @After annotations on the 
methods in the ActionBean class
-                       Method[] methods = beanClass.getMethods();
+                       Collection<Method> methods = 
ReflectUtil.getMethods(beanClass);
             for (Method method : methods) {
-                int mods = method.getModifiers();
+                if (method.isAnnotationPresent(Before.class) || 
method.isAnnotationPresent(After.class)) {
+                    // Check to ensure that the method has an appropriate 
signature
+                    int mods = method.getModifiers();
+                    if (method.getParameterTypes().length != 0 || 
Modifier.isAbstract(mods)) {
+                        log.warn("Method '", beanClass.getName(), ".", 
method.getName(), "' is ",
+                                 "annotated with @Before or @After but has an 
incompatible ",
+                                 "signature. @Before/@After methods must be 
non-abstract ",
+                                 "zero-argument methods.");
+                        continue;
+                    }
 
-                if (method.isAnnotationPresent(Before.class)) {
-                    if (method.getParameterTypes().length == 0 && 
!Modifier.isAbstract(mods)) {
-                        Before annotation = method.getAnnotation(Before.class);
-                        filterMethods.addBeforeMethod(annotation.value(), 
method);
+                    // Now try and make private/protected/package methods 
callable
+                    if (!method.isAccessible()) {
+                        try {
+                            method.setAccessible(true);
+                        }
+                        catch (SecurityException se) {
+                            log.warn("Method '", beanClass.getName(), ".", 
method.getName(), "' is ",
+                                     "annotated with @Before or @After but is 
not public and  ",
+                                     "calling setAccessible(true) on it threw 
a SecurityException. ",
+                                     "Please either declare the method as 
public, or change your ",
+                                     "JVM security policy to allow Stripes 
code to call ",
+                                     "Method.setAccessible() on your code 
base.");
+                            continue;
+                        }
                     }
-                    else {
-                        log.warn("Method '", beanClass.getName(), ".", 
method.getName(), "' is ",
-                                 "annotated with @Before but has an 
incompatible signature. ",
-                                 "@Before methods must be non-abstract 
zero-argument methods.");
+
+                    if (method.isAnnotationPresent(Before.class)) {
+                            Before annotation = 
method.getAnnotation(Before.class);
+                            filterMethods.addBeforeMethod(annotation.value(), 
method);
                     }
-                }
 
-                if (method.isAnnotationPresent(After.class)) {
-                    if (method.getParameterTypes().length == 0 && 
!Modifier.isAbstract(mods)) {
+                    if (method.isAnnotationPresent(After.class)) {
                         After annotation = method.getAnnotation(After.class);
                         filterMethods.addAfterMethod(annotation.value(), 
method);
                     }
-                    else {
-                        log.warn("Method '", beanClass.getName(), ".", 
method.getName(), "' is ",
-                                 "annotated with @After but has an 
incompatible signature. ",
-                                 "@After methods must be non-abstract 
zero-argument methods.");
-                    }
                 }
-
             }
                }
-               return filterMethods;
+
+        return filterMethods;
        }
        
        /**

Modified: trunk/stripes/src/net/sourceforge/stripes/util/ReflectUtil.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/util/ReflectUtil.java     
2006-05-13 00:29:48 UTC (rev 313)
+++ trunk/stripes/src/net/sourceforge/stripes/util/ReflectUtil.java     
2006-05-13 02:11:11 UTC (rev 314)
@@ -193,4 +193,35 @@
             return ann.toString();
         }
     }
+
+    /**
+     * Fetches all methods of all access types from the supplied class and 
super
+     * classes. Methods that have been overridden in the inheritance hierachy 
are
+     * only returned once, using the instance lowest down the hierarchy.
+     *
+     * @param clazz the class to inspect
+     * @return a collection of methods
+     */
+    public static Collection<Method> getMethods(Class<?> clazz) {
+        Collection<Method> found = new ArrayList<Method>();
+        while (clazz != null) {
+            for (Method m1 : clazz.getDeclaredMethods()) {
+                boolean overridden = false;
+
+                for (Method m2 : found) {
+                    if ( m2.getName().equals(m1.getName()) &&
+                            Arrays.deepEquals(m1.getParameterTypes(), 
m2.getParameterTypes())) {
+                        overridden = true;
+                        break;
+                    }
+                }
+
+                if (!overridden) found.add(m1);
+            }
+
+            clazz = clazz.getSuperclass();
+        }
+
+        return found;
+    }
 }

Modified: 
trunk/tests/src/net/sourceforge/stripes/controller/BeforeAfterMethodInterceptorTests.java
===================================================================
--- 
trunk/tests/src/net/sourceforge/stripes/controller/BeforeAfterMethodInterceptorTests.java
   2006-05-13 00:29:48 UTC (rev 313)
+++ 
trunk/tests/src/net/sourceforge/stripes/controller/BeforeAfterMethodInterceptorTests.java
   2006-05-13 02:11:11 UTC (rev 314)
@@ -16,7 +16,7 @@
  */
 public class BeforeAfterMethodInterceptorTests {
 
-    @Test
+    @Test(groups="fast")
     public void testInterceptAtLifeCycleStage_ActionBeanResolution() throws 
Exception {
         ExecutionContext context = new TestExecutionContext();
         TestActionBean2 actionBean = new TestActionBean2();
@@ -45,7 +45,7 @@
         Assert.assertEquals(actionBean.getHasCalledProtectedBeforeMethod(), 0);
     }
 
-    @Test
+    @Test(groups="fast")
     public void testInterceptAtLifeCycleStage_BindingAndValidation() throws 
Exception {
         ExecutionContext context = new TestExecutionContext();
         TestActionBean2 actionBean = new TestActionBean2();
@@ -75,7 +75,7 @@
         Assert.assertEquals(actionBean.getHasCalledProtectedBeforeMethod(), 0);
     }
 
-    @Test
+    @Test(groups="fast")
     public void testInterceptAtLifeCycleStage_CustomValidation() throws 
Exception {
         ExecutionContext context = new TestExecutionContext();
         TestActionBean2 actionBean = new TestActionBean2();
@@ -105,7 +105,7 @@
         Assert.assertEquals(actionBean.getHasCalledProtectedBeforeMethod(), 0);
     }
 
-    @Test
+    @Test(groups="fast")
     public void testInterceptAtLifeCycleStage_EventHandling() throws Exception 
{
         ExecutionContext context = new TestExecutionContext();
         TestActionBean2 actionBean = new TestActionBean2();
@@ -132,11 +132,11 @@
         Assert.assertEquals(actionBean.getHasCalledBeforeWithParameter(), 0);
         
Assert.assertEquals(actionBean.getHasCalledBeforeWithReturnAndParameter(), 0);
         Assert.assertEquals(actionBean.getHasCalledDummyMethod(), 0);
-        Assert.assertEquals(actionBean.getHasCalledProtectedAfterMethod(), 0);
-        Assert.assertEquals(actionBean.getHasCalledProtectedBeforeMethod(), 0);
+        Assert.assertEquals(actionBean.getHasCalledProtectedAfterMethod(), 1);
+        Assert.assertEquals(actionBean.getHasCalledProtectedBeforeMethod(), 1);
     }
 
-    @Test
+    @Test(groups="fast")
     public void testInterceptAtLifeCycleStage_HandlerResolution() throws 
Exception {
         ExecutionContext context = new TestExecutionContext();
         TestActionBean2 actionBean = new TestActionBean2();

Modified: trunk/tests/tests.iml
===================================================================
--- trunk/tests/tests.iml       2006-05-13 00:29:48 UTC (rev 313)
+++ trunk/tests/tests.iml       2006-05-13 02:11:11 UTC (rev 314)
@@ -9,7 +9,7 @@
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="module" module-name="stripes" />
+    <orderEntry type="module" module-name="stripes" exported="" />
     <orderEntry type="module-library">
       <library>
         <CLASSES>


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to