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