You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2017/06/05 06:49:17 UTC

struts git commit: WW-4800 Executes aspects when chaining AOPed actions

Repository: struts
Updated Branches:
  refs/heads/master 2fb431d97 -> 8e9f9fb89


WW-4800 Executes aspects when chaining AOPed actions


Project: http://git-wip-us.apache.org/repos/asf/struts/repo
Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/8e9f9fb8
Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/8e9f9fb8
Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/8e9f9fb8

Branch: refs/heads/master
Commit: 8e9f9fb89ff84e3f383d0aef73443af919c271d7
Parents: 2fb431d
Author: Yasser Zamani <ya...@live.com>
Authored: Mon May 29 18:56:10 2017 +0430
Committer: Yasser Zamani <ya...@live.com>
Committed: Mon May 29 18:56:10 2017 +0430

----------------------------------------------------------------------
 .../xwork2/interceptor/ChainingInterceptor.java |  5 +-
 .../xwork2/ognl/OgnlReflectionProvider.java     |  7 ++-
 .../com/opensymphony/xwork2/ognl/OgnlUtil.java  | 25 +++++++-
 .../com/opensymphony/xwork2/util/ProxyUtil.java | 61 +++++++++++++-------
 .../util/reflection/ReflectionProvider.java     | 18 +++++-
 .../opensymphony/xwork2/ognl/OgnlUtilTest.java  | 26 +++++++++
 .../xwork2/spring/ActionsFromSpringTest.java    | 20 ++++---
 .../xwork2/spring/SpringProxyUtilTest.java      | 32 +++++-----
 .../opensymphony/xwork2/spring/TestAspect.java  | 46 +++++++++++++++
 .../xwork2/spring/actionContext-spring.xml      | 16 +++--
 10 files changed, 204 insertions(+), 52 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/struts/blob/8e9f9fb8/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java
index 59b1d88..430edcc 100644
--- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java
+++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java
@@ -163,10 +163,11 @@ public class ChainingInterceptor extends AbstractInterceptor {
         for (Object object : list) {
             if (shouldCopy(object)) {
                 Object action = invocation.getAction();
+                Class<?> editable = null;
                 if(ProxyUtil.isSpringAopProxy(action)) {
-                    action = ProxyUtil.getSpringUltimateTargetObject(action);
+                    editable = ProxyUtil.springUltimateTargetClass(action);
                 }
-                reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes);
+                reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes, editable);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/struts/blob/8e9f9fb8/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionProvider.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionProvider.java
index 34f3043..b1cd339 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionProvider.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionProvider.java
@@ -70,7 +70,12 @@ public class OgnlReflectionProvider implements ReflectionProvider {
 
     public void copy(Object from, Object to, Map<String, Object> context,
             Collection<String> exclusions, Collection<String> inclusions) {
-        ognlUtil.copy(from, to, context, exclusions, inclusions);
+        copy(from, to, context, exclusions, inclusions, null);
+    }
+
+    public void copy(Object from, Object to, Map<String, Object> context,
+                     Collection<String> exclusions, Collection<String> inclusions, Class<?> editable) {
+        ognlUtil.copy(from, to, context, exclusions, inclusions, editable);
     }
 
     public Object getRealTarget(String property, Map<String, Object> context, Object root)

http://git-wip-us.apache.org/repos/asf/struts/blob/8e9f9fb8/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
index fe64d8f..ced8eff 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
@@ -450,6 +450,24 @@ public class OgnlUtil {
      *                   note if exclusions AND inclusions are supplied and not null nothing will get copied.
      */
     public void copy(final Object from, final Object to, final Map<String, Object> context, Collection<String> exclusions, Collection<String> inclusions) {
+        copy(from, to, context, exclusions, inclusions, null);
+    }
+
+    /**
+     * Copies the properties in the object "from" and sets them in the object "to"
+     * only setting properties defined in the given "editable" class (or interface)
+     * using specified type converter, or {@link com.opensymphony.xwork2.conversion.impl.XWorkConverter} if none
+     * is specified.
+     *
+     * @param from       the source object
+     * @param to         the target object
+     * @param context    the action context we're running under
+     * @param exclusions collection of method names to excluded from copying ( can be null)
+     * @param inclusions collection of method names to included copying  (can be null)
+     *                   note if exclusions AND inclusions are supplied and not null nothing will get copied.
+     * @param editable the class (or interface) to restrict property setting to
+     */
+    public void copy(final Object from, final Object to, final Map<String, Object> context, Collection<String> exclusions, Collection<String> inclusions, Class<?> editable) {
         if (from == null || to == null) {
             LOG.warn("Attempting to copy from or to a null source. This is illegal and is bein skipped. This may be due to an error in an OGNL expression, action chaining, or some other event.");
             return;
@@ -466,7 +484,12 @@ public class OgnlUtil {
 
         try {
             fromPds = getPropertyDescriptors(from);
-            toPds = getPropertyDescriptors(to);
+            if (editable != null) {
+                toPds = getPropertyDescriptors(editable);
+            }
+            else {
+                toPds = getPropertyDescriptors(to);
+            }
         } catch (IntrospectionException e) {
             LOG.error("An error occurred", e);
             return;

http://git-wip-us.apache.org/repos/asf/struts/blob/8e9f9fb8/core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java b/core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java
index 6a8ac53..a3f8740 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java
@@ -29,31 +29,32 @@ import java.lang.reflect.Proxy;
 public class ProxyUtil {
     private static final String SPRING_ADVISED_CLASS_NAME = "org.springframework.aop.framework.Advised";
     private static final String SPRING_SPRINGPROXY_CLASS_NAME = "org.springframework.aop.SpringProxy";
+    private static final String SPRING_SINGLETONTARGETSOURCE_CLASS_NAME = "org.springframework.aop.target.SingletonTargetSource";
+    private static final String SPRING_TARGETCLASSAWARE_CLASS_NAME = "org.springframework.aop.TargetClassAware";
 
     /**
-     * Get the ultimate <em>target</em> object of the supplied {@code candidate}
-     * object, unwrapping not only a top-level proxy but also any number of
-     * nested proxies.
-     * <p>If the supplied {@code candidate} is a Spring proxy, the ultimate target of all
-     * nested proxies will be returned; otherwise, the {@code candidate}
-     * will be returned <em>as is</em>.
-     * @param candidate the instance to check (potentially a Spring AOP proxy;
-     * never {@code null})
-     * @return the target object or the {@code candidate} (never {@code null})
-     * @throws IllegalStateException if an error occurs while unwrapping a proxy
+     * Determine the ultimate target class of the given spring bean instance, traversing
+     * not only a top-level spring proxy but any number of nested spring proxies as well &mdash;
+     * as long as possible without side effects, that is, just for singleton targets.
+     * @param candidate the instance to check (might be a spring AOP proxy)
+     * @return the ultimate target class (or the plain class of the given
+     * object as fallback; never {@code null})
      */
-    public static <T> T getSpringUltimateTargetObject(Object candidate) {
-        try {
-            if (isSpringAopProxy(candidate) && implementsInterface(candidate.getClass(), SPRING_ADVISED_CLASS_NAME)) {
-                Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource");
-                Object target = MethodUtils.invokeMethod(targetSource, "getTarget");
-                return getSpringUltimateTargetObject(target);
+    public static Class<?> springUltimateTargetClass(Object candidate) {
+        Object current = candidate;
+        Class<?> result = null;
+        while (null != current && implementsInterface(current.getClass(), SPRING_TARGETCLASSAWARE_CLASS_NAME)) {
+            try {
+                result = (Class<?>) MethodUtils.invokeMethod(current, "getTargetClass");
+            } catch (Throwable ignored) {
             }
+            current = getSingletonTarget(current);
         }
-        catch (Throwable ex) {
-            throw new IllegalStateException("Failed to unwrap proxied object", ex);
+        if (result == null) {
+            Class<?> clazz = candidate.getClass();
+            result = (isCglibProxyClass(clazz) ? clazz.getSuperclass() : candidate.getClass());
         }
-        return (T) candidate;
+        return result;
     }
 
     /**
@@ -67,6 +68,26 @@ public class ProxyUtil {
     }
 
     /**
+     * Obtain the singleton target object behind the given spring proxy, if any.
+     * @param candidate the (potential) spring proxy to check
+     * @return the singleton target object, or {@code null} in any other case
+     * (not a spring proxy, not an existing singleton target)
+     */
+    private static Object getSingletonTarget(Object candidate) {
+        try {
+            if (implementsInterface(candidate.getClass(), SPRING_ADVISED_CLASS_NAME)) {
+                Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource");
+                if (implementsInterface(targetSource.getClass(), SPRING_SINGLETONTARGETSOURCE_CLASS_NAME)) {
+                    return MethodUtils.invokeMethod(targetSource, "getTarget");
+                }
+            }
+        } catch (Throwable ignored) {
+        }
+
+        return null;
+    }
+
+    /**
      * Check whether the specified class is a CGLIB-generated class.
      * @param clazz the class to check
      */
@@ -81,7 +102,7 @@ public class ProxyUtil {
      */
     private static boolean implementsInterface(Class<?> clazz, String ifaceClassName) {
         try {
-            Class ifaceClass = ClassLoaderUtil.loadClass(ifaceClassName, ProxyUtil.class);
+            Class<?> ifaceClass = ClassLoaderUtil.loadClass(ifaceClassName, ProxyUtil.class);
             return ifaceClass.isAssignableFrom(clazz);
         } catch (ClassNotFoundException e) {
             return false;

http://git-wip-us.apache.org/repos/asf/struts/blob/8e9f9fb8/core/src/main/java/com/opensymphony/xwork2/util/reflection/ReflectionProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/reflection/ReflectionProvider.java b/core/src/main/java/com/opensymphony/xwork2/util/reflection/ReflectionProvider.java
index 029163e..72211ec 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/reflection/ReflectionProvider.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/reflection/ReflectionProvider.java
@@ -72,7 +72,23 @@ public interface ReflectionProvider {
      *                   note if exclusions AND inclusions are supplied and not null nothing will get copied.
      */
     void copy(Object from, Object to, Map<String, Object> context, Collection<String> exclusions, Collection<String> inclusions);
-    
+
+    /**
+     * Copies the properties in the object "from" and sets them in the object "to"
+     * only setting properties defined in the given "editable" class (or interface)
+     * using specified type converter, or {@link com.opensymphony.xwork2.conversion.impl.XWorkConverter} if none
+     * is specified.
+     *
+     * @param from       the source object
+     * @param to         the target object
+     * @param context    the action context we're running under
+     * @param exclusions collection of method names to excluded from copying ( can be null)
+     * @param inclusions collection of method names to included copying  (can be null)
+     *                   note if exclusions AND inclusions are supplied and not null nothing will get copied.
+     * @param editable the class (or interface) to restrict property setting to
+     */
+    void copy(Object from, Object to, Map<String, Object> context, Collection<String> exclusions, Collection<String> inclusions, Class<?> editable);
+
     /**
      * Looks for the real target with the specified property given a root Object which may be a
      * CompoundRoot.

http://git-wip-us.apache.org/repos/asf/struts/blob/8e9f9fb8/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
index a8bc7da..c0b0107 100644
--- a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
@@ -209,6 +209,32 @@ public class OgnlUtilTest extends XWorkTestCase {
 
     }
 
+    public void testCopyEditable() {
+        Foo foo1 = new Foo();
+        Foo foo2 = new Foo();
+
+        Map<String, Object> context = ognlUtil.createDefaultContext(foo1);
+
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(Calendar.MONTH, Calendar.MAY);
+        cal.set(Calendar.DAY_OF_MONTH, 29);
+        cal.set(Calendar.YEAR, 2017);
+
+        foo1.setTitle("blah");
+        foo1.setNumber(1);
+        foo1.setPoints(new long[]{1, 2, 3});
+        foo1.setBirthday(cal.getTime());
+        foo1.setUseful(false);
+
+        ognlUtil.copy(foo1, foo2, context, null, null, Bar.class);
+
+        assertEquals(foo1.getTitle(), foo2.getTitle());
+        assertEquals(0, foo2.getNumber());
+        assertNull(foo2.getPoints());
+        assertNull(foo2.getBirthday());
+    }
+
 
     public void testCopyUnevenObjects() {
         Foo foo = new Foo();

http://git-wip-us.apache.org/repos/asf/struts/blob/8e9f9fb8/core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java b/core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java
index 4bbe429..f31a614 100644
--- a/core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java
@@ -84,14 +84,20 @@ public class ActionsFromSpringTest extends XWorkTestCase {
 
         proxy.execute();
 
-        TestSubBean chaintoAOPedAction = (TestSubBean) appContext.getBean("pointcutted-test-sub-bean");
-        TestSubBean aspectState = (TestSubBean) appContext.getBean("aspected-test-sub-bean");
+        // check if AOP works
+        TestAspect aspectState = (TestAspect) appContext.getBean("test-aspect");
+        // chainedAction.actionMethodName sets name then chainedAction.getCount sets count
+        // then chaintoAction.setCount sets count2 then chainedAction.getName sets name again
+        // then chaintoAction.actionMethodName sets issueId of the aspect object.
+        assertEquals("setName(WW-4105)-setCount(1)-setCount2(1)-setName(WW-4105)-setIssueId(WW-4105)-", aspectState.log);
+        assertEquals(aspectState.getName(), aspectState.getIssueId());
+        assertEquals("WW-4105", aspectState.getIssueId());
+        assertEquals(aspectState.getCount(), aspectState.getCount2());
+        assertEquals(1, aspectState.getCount());
 
-        assertEquals(1, chaintoAOPedAction.getCount()); //check if chain
+        // check if chain works
+        TestSubBean chaintoAOPedAction = (TestSubBean) appContext.getBean("pointcutted-test-sub-bean");
+        assertEquals(1, chaintoAOPedAction.getCount());
         assertEquals("WW-4105", chaintoAOPedAction.getName());
-        assertNotNull(aspectState.getIssueId());   //and AOP proxied actions
-        assertNotNull(aspectState.getName());
-        assertEquals(aspectState.getName(), aspectState.getIssueId());
-        assertEquals("WW-4105", aspectState.getIssueId());   //work together without any problem
     }
 }

http://git-wip-us.apache.org/repos/asf/struts/blob/8e9f9fb8/core/src/test/java/com/opensymphony/xwork2/spring/SpringProxyUtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/spring/SpringProxyUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/spring/SpringProxyUtilTest.java
index 9c047b8..7ae9883 100644
--- a/core/src/test/java/com/opensymphony/xwork2/spring/SpringProxyUtilTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/spring/SpringProxyUtilTest.java
@@ -53,33 +53,33 @@ public class SpringProxyUtilTest extends XWorkTestCase {
         Object pointcuttedTestSubBean = appContext.getBean("pointcutted-test-sub-bean");
         assertTrue(ProxyUtil.isSpringAopProxy(pointcuttedTestSubBean));
 
-        Object aspectedTestSubBean = appContext.getBean("aspected-test-sub-bean");
-        assertFalse(ProxyUtil.isSpringAopProxy(aspectedTestSubBean));
+        Object testAspect = appContext.getBean("test-aspect");
+        assertFalse(ProxyUtil.isSpringAopProxy(testAspect));
     }
 
-    public void testGetSpringUltimateTargetObject() throws Exception {
+    public void testSpringUltimateTargetClass() throws Exception {
         Object simpleAction = appContext.getBean("simple-action");
-        Object simpleActionUltimateTargetObject = ProxyUtil.getSpringUltimateTargetObject(simpleAction);
-        assertEquals(simpleAction, simpleActionUltimateTargetObject);
+        Class<?> simpleActionUltimateTargetClass = ProxyUtil.springUltimateTargetClass(simpleAction);
+        assertEquals(SimpleAction.class, simpleActionUltimateTargetClass);
 
         Object proxiedAction = appContext.getBean("proxied-action");
-        Object proxiedActionUltimateTargetObject = ProxyUtil.getSpringUltimateTargetObject(proxiedAction);
-        assertEquals(SimpleAction.class, proxiedActionUltimateTargetObject.getClass());
+        Class<?> proxiedActionUltimateTargetClass = ProxyUtil.springUltimateTargetClass(proxiedAction);
+        assertEquals(SimpleAction.class, proxiedActionUltimateTargetClass);
 
         Object autoProxiedAction = appContext.getBean("auto-proxied-action");
-        Object autoProxiedActionUltimateTargetObject = ProxyUtil.getSpringUltimateTargetObject(autoProxiedAction);
-        assertEquals(SimpleAction.class, autoProxiedActionUltimateTargetObject.getClass());
+        Class<?> autoProxiedActionUltimateTargetClass = ProxyUtil.springUltimateTargetClass(autoProxiedAction);
+        assertEquals(SimpleAction.class, autoProxiedActionUltimateTargetClass);
 
         Object pointcuttedTestBean = appContext.getBean("pointcutted-test-bean");
-        Object pointcuttedTestBeanUltimateTargetObject = ProxyUtil.getSpringUltimateTargetObject(pointcuttedTestBean);
-        assertEquals(TestBean.class, pointcuttedTestBeanUltimateTargetObject.getClass());
+        Class<?> pointcuttedTestBeanUltimateTargetClass = ProxyUtil.springUltimateTargetClass(pointcuttedTestBean);
+        assertEquals(TestBean.class, pointcuttedTestBeanUltimateTargetClass);
 
         Object pointcuttedTestSubBean = appContext.getBean("pointcutted-test-sub-bean");
-        Object pointcuttedTestSubBeanUltimateTargetObject = ProxyUtil.getSpringUltimateTargetObject(pointcuttedTestSubBean);
-        assertEquals(TestSubBean.class, pointcuttedTestSubBeanUltimateTargetObject.getClass());
+        Class<?> pointcuttedTestSubBeanUltimateTargetClass = ProxyUtil.springUltimateTargetClass(pointcuttedTestSubBean);
+        assertEquals(TestSubBean.class, pointcuttedTestSubBeanUltimateTargetClass);
 
-        Object aspectedTestSubBean = appContext.getBean("aspected-test-sub-bean");
-        Object aspectedTestSubBeanUltimateTargetObject = ProxyUtil.getSpringUltimateTargetObject(aspectedTestSubBean);
-        assertEquals(aspectedTestSubBean, aspectedTestSubBeanUltimateTargetObject);
+        Object testAspect = appContext.getBean("test-aspect");
+        Class<?> testAspectUltimateTargetClass = ProxyUtil.springUltimateTargetClass(testAspect);
+        assertEquals(TestAspect.class, testAspectUltimateTargetClass);
     }
 }

http://git-wip-us.apache.org/repos/asf/struts/blob/8e9f9fb8/core/src/test/java/com/opensymphony/xwork2/spring/TestAspect.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/spring/TestAspect.java b/core/src/test/java/com/opensymphony/xwork2/spring/TestAspect.java
new file mode 100644
index 0000000..a428c65
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/spring/TestAspect.java
@@ -0,0 +1,46 @@
+package com.opensymphony.xwork2.spring;
+
+public class TestAspect {
+	protected String log = "";
+	
+	private String issueId;
+	private int count;
+	private String name;
+	private int count2;
+
+	String getIssueId() {
+		return issueId;
+	}
+
+	public void setIssueId(String issueId) {
+		log = log + "setIssueId(" + issueId + ")-";
+		this.issueId = issueId;
+	}
+
+	public int getCount() {
+		return count;
+	}
+
+	public void setCount(int count) {
+		log = log + "setCount(" + count + ")-";
+		this.count = count;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		log = log + "setName(" + name + ")-";
+		this.name = name;
+	}
+
+	int getCount2() {
+		return count2;
+	}
+
+	public void setCount2(int count2) {
+		log = log + "setCount2(" + count2 + ")-";
+		this.count2 = count2;
+	}
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/8e9f9fb8/core/src/test/resources/com/opensymphony/xwork2/spring/actionContext-spring.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/com/opensymphony/xwork2/spring/actionContext-spring.xml b/core/src/test/resources/com/opensymphony/xwork2/spring/actionContext-spring.xml
index 5c18f6e..078107e 100644
--- a/core/src/test/resources/com/opensymphony/xwork2/spring/actionContext-spring.xml
+++ b/core/src/test/resources/com/opensymphony/xwork2/spring/actionContext-spring.xml
@@ -51,17 +51,25 @@
     <bean id="pointcutted-test-sub-bean" class="com.opensymphony.xwork2.TestSubBean">
         <property name="issueId"><value>WW-4105</value></property>
     </bean>
-    <bean id="aspected-test-sub-bean" class="com.opensymphony.xwork2.TestSubBean" />
+    <bean id="test-aspect" class="com.opensymphony.xwork2.spring.TestAspect" />
     <aop:config>
-        <aop:aspect id="myAspect" ref="aspected-test-sub-bean">
+        <aop:aspect id="myAspect" ref="test-aspect">
             <aop:pointcut id="testBeanGetName"
                 expression="execution(String com.opensymphony.xwork2.TestBean.getName()) and bean(pointcutted-test-bean)" />
             <aop:after-returning pointcut-ref="testBeanGetName"
-                method="setIssueId" returning="issueId" />
+                method="setName" returning="name" />
+            <aop:pointcut id="testBeanGetCount"
+                expression="execution(int com.opensymphony.xwork2.TestBean.getCount()) and bean(pointcutted-test-bean)" />
+            <aop:after-returning pointcut-ref="testBeanGetCount"
+                method="setCount" returning="count" />
             <aop:pointcut id="testSubBeanGetIssueId"
                 expression="execution(String com.opensymphony.xwork2.TestSubBean.getIssueId()) and bean(pointcutted-test-sub-bean)" />
             <aop:after-returning pointcut-ref="testSubBeanGetIssueId"
-                method="setName" returning="name" />
+                method="setIssueId" returning="issueId" />
+            <aop:pointcut id="testBeanSetCount"
+                expression="execution(void com.opensymphony.xwork2.TestBean.setCount(int)) and args(count2) and bean(pointcutted-test-sub-bean)" />
+            <aop:before pointcut-ref="testBeanSetCount"
+                method="setCount2" arg-names="count2"/>
         </aop:aspect>
     </aop:config>
 </beans>