Skip to content

Commit 63e8609

Browse files
committed
Test status quo for 'after' advice invocation order
See gh-25186
1 parent 70b3de4 commit 63e8609

File tree

5 files changed

+360
-25
lines changed

5 files changed

+360
-25
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 2002-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.aop.config;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import org.junit.jupiter.api.Nested;
23+
import org.junit.jupiter.api.Test;
24+
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.test.annotation.DirtiesContext;
27+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
31+
32+
/**
33+
* Integration tests for advice invocation order for advice configured via the
34+
* AOP namespace.
35+
*
36+
* @author Sam Brannen
37+
* @since 5.0.18
38+
* @see org.springframework.aop.framework.autoproxy.AspectJAutoProxyAdviceOrderIntegrationTests
39+
*/
40+
class AopNamespaceHandlerAdviceOrderIntegrationTests {
41+
42+
@Nested
43+
@SpringJUnitConfig(locations = "AopNamespaceHandlerAdviceOrderIntegrationTests-afterFirst.xml")
44+
@DirtiesContext
45+
class AfterAdviceFirstTests {
46+
47+
@Test
48+
void afterAdviceIsInvokedFirst(@Autowired Echo echo, @Autowired EchoAspect aspect) throws Exception {
49+
assertThat(aspect.invocations).isEmpty();
50+
assertThat(echo.echo(42)).isEqualTo(42);
51+
assertThat(aspect.invocations).containsExactly("after", "after returning");
52+
53+
aspect.invocations.clear();
54+
assertThatExceptionOfType(Exception.class).isThrownBy(() -> echo.echo(new Exception()));
55+
assertThat(aspect.invocations).containsExactly("after", "after throwing");
56+
}
57+
}
58+
59+
@Nested
60+
@SpringJUnitConfig(locations = "AopNamespaceHandlerAdviceOrderIntegrationTests-afterLast.xml")
61+
@DirtiesContext
62+
class AfterAdviceLastTests {
63+
64+
@Test
65+
void afterAdviceIsInvokedLast(@Autowired Echo echo, @Autowired EchoAspect aspect) throws Exception {
66+
assertThat(aspect.invocations).isEmpty();
67+
assertThat(echo.echo(42)).isEqualTo(42);
68+
assertThat(aspect.invocations).containsExactly("after returning", "after");
69+
70+
aspect.invocations.clear();
71+
assertThatExceptionOfType(Exception.class).isThrownBy(() -> echo.echo(new Exception()));
72+
assertThat(aspect.invocations).containsExactly("after throwing", "after");
73+
}
74+
}
75+
76+
77+
static class Echo {
78+
79+
Object echo(Object obj) throws Exception {
80+
if (obj instanceof Exception) {
81+
throw (Exception) obj;
82+
}
83+
return obj;
84+
}
85+
}
86+
87+
static class EchoAspect {
88+
89+
List<String> invocations = new ArrayList<>();
90+
91+
void echo() {
92+
}
93+
94+
void succeeded() {
95+
invocations.add("after returning");
96+
}
97+
98+
void failed() {
99+
invocations.add("after throwing");
100+
}
101+
102+
void after() {
103+
invocations.add("after");
104+
}
105+
}
106+
107+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* Copyright 2002-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.aop.framework.autoproxy;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import org.aspectj.lang.annotation.After;
23+
import org.aspectj.lang.annotation.AfterReturning;
24+
import org.aspectj.lang.annotation.AfterThrowing;
25+
import org.aspectj.lang.annotation.Aspect;
26+
import org.aspectj.lang.annotation.Pointcut;
27+
import org.junit.jupiter.api.Nested;
28+
import org.junit.jupiter.api.Test;
29+
30+
import org.springframework.beans.factory.annotation.Autowired;
31+
import org.springframework.context.annotation.Bean;
32+
import org.springframework.context.annotation.Configuration;
33+
import org.springframework.context.annotation.EnableAspectJAutoProxy;
34+
import org.springframework.test.annotation.DirtiesContext;
35+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
36+
37+
import static org.assertj.core.api.Assertions.assertThat;
38+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
39+
40+
/**
41+
* Integration tests for advice invocation order for advice configured via
42+
* AspectJ auto-proxy support.
43+
*
44+
* @author Sam Brannen
45+
* @since 5.0.18
46+
* @see org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests
47+
*/
48+
class AspectJAutoProxyAdviceOrderIntegrationTests {
49+
50+
@Nested
51+
@SpringJUnitConfig(AfterAdviceFirstConfig.class)
52+
@DirtiesContext
53+
class AfterAdviceFirstTests {
54+
55+
@Test
56+
void afterAdviceIsInvokedFirst(@Autowired Echo echo, @Autowired AfterAdviceFirstAspect aspect) throws Exception {
57+
assertThat(aspect.invocations).isEmpty();
58+
assertThat(echo.echo(42)).isEqualTo(42);
59+
assertThat(aspect.invocations).containsExactly("after", "after returning");
60+
61+
aspect.invocations.clear();
62+
assertThatExceptionOfType(Exception.class).isThrownBy(
63+
() -> echo.echo(new Exception()));
64+
assertThat(aspect.invocations).containsExactly("after", "after throwing");
65+
}
66+
}
67+
68+
69+
@Nested
70+
@SpringJUnitConfig(AfterAdviceLastConfig.class)
71+
@DirtiesContext
72+
class AfterAdviceLastTests {
73+
74+
@Test
75+
void afterAdviceIsNotInvokedLast(@Autowired Echo echo, @Autowired AfterAdviceLastAspect aspect) throws Exception {
76+
assertThat(aspect.invocations).isEmpty();
77+
assertThat(echo.echo(42)).isEqualTo(42);
78+
// On Java versions prior to JDK 7, we would expect the @After advice to be invoked last.
79+
assertThat(aspect.invocations).containsExactly("after", "after returning");
80+
81+
aspect.invocations.clear();
82+
assertThatExceptionOfType(Exception.class).isThrownBy(
83+
() -> echo.echo(new Exception()));
84+
// On Java versions prior to JDK 7, we would expect the @After advice to be invoked last.
85+
assertThat(aspect.invocations).containsExactly("after", "after throwing");
86+
}
87+
}
88+
89+
90+
@Configuration
91+
@EnableAspectJAutoProxy(proxyTargetClass = true)
92+
static class AfterAdviceFirstConfig {
93+
94+
@Bean
95+
AfterAdviceFirstAspect echoAspect() {
96+
return new AfterAdviceFirstAspect();
97+
}
98+
99+
@Bean
100+
Echo echo() {
101+
return new Echo();
102+
}
103+
}
104+
105+
@Configuration
106+
@EnableAspectJAutoProxy(proxyTargetClass = true)
107+
static class AfterAdviceLastConfig {
108+
109+
@Bean
110+
AfterAdviceLastAspect echoAspect() {
111+
return new AfterAdviceLastAspect();
112+
}
113+
114+
@Bean
115+
Echo echo() {
116+
return new Echo();
117+
}
118+
}
119+
120+
static class Echo {
121+
122+
Object echo(Object obj) throws Exception {
123+
if (obj instanceof Exception) {
124+
throw (Exception) obj;
125+
}
126+
return obj;
127+
}
128+
}
129+
130+
/**
131+
* {@link After @After} advice declared as first <em>after</em> method in source code.
132+
*/
133+
@Aspect
134+
static class AfterAdviceFirstAspect {
135+
136+
List<String> invocations = new ArrayList<>();
137+
138+
@Pointcut("execution(* echo(*))")
139+
void echo() {
140+
}
141+
142+
@After("echo()")
143+
void after() {
144+
invocations.add("after");
145+
}
146+
147+
@AfterReturning("echo()")
148+
void succeeded() {
149+
invocations.add("after returning");
150+
}
151+
152+
@AfterThrowing("echo()")
153+
void failed() {
154+
invocations.add("after throwing");
155+
}
156+
}
157+
158+
/**
159+
* {@link After @After} advice declared as last <em>after</em> method in source code.
160+
*/
161+
@Aspect
162+
static class AfterAdviceLastAspect {
163+
164+
List<String> invocations = new ArrayList<>();
165+
166+
@Pointcut("execution(* echo(*))")
167+
void echo() {
168+
}
169+
170+
@AfterReturning("echo()")
171+
void succeeded() {
172+
invocations.add("after returning");
173+
}
174+
175+
@AfterThrowing("echo()")
176+
void failed() {
177+
invocations.add("after throwing");
178+
}
179+
180+
@After("echo()")
181+
void after() {
182+
invocations.add("after");
183+
}
184+
}
185+
186+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<beans xmlns="http://www.springframework.org/schema/beans"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:aop="http://www.springframework.org/schema/aop"
5+
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
6+
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
7+
8+
<bean id="echo" class="org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests$Echo"/>
9+
10+
<bean id="echoAspect" class="org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests$EchoAspect" />
11+
12+
<aop:config>
13+
<aop:aspect id="echoAdvice" ref="echoAspect">
14+
<aop:pointcut id="echoMethod" expression="execution(* echo(*))" />
15+
<aop:after method="after" pointcut-ref="echoMethod" />
16+
<aop:after-throwing method="failed" pointcut-ref="echoMethod" />
17+
<aop:after-returning method="succeeded" pointcut-ref="echoMethod" />
18+
</aop:aspect>
19+
</aop:config>
20+
21+
</beans>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<beans xmlns="http://www.springframework.org/schema/beans"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:aop="http://www.springframework.org/schema/aop"
5+
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
6+
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
7+
8+
<bean id="echo" class="org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests$Echo"/>
9+
10+
<bean id="echoAspect" class="org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests$EchoAspect" />
11+
12+
<aop:config>
13+
<aop:aspect id="echoAdvice" ref="echoAspect">
14+
<aop:pointcut id="echoMethod" expression="execution(* echo(*))" />
15+
<aop:after-returning method="succeeded" pointcut-ref="echoMethod" />
16+
<aop:after-throwing method="failed" pointcut-ref="echoMethod" />
17+
<aop:after method="after" pointcut-ref="echoMethod" />
18+
</aop:aspect>
19+
</aop:config>
20+
21+
</beans>

0 commit comments

Comments
 (0)