Skip to content

Commit 8eb2445

Browse files
anaconda874snicoll
authored andcommitted
Use proper return type in AsyncExecutionInterceptor
See gh-33957
1 parent cda7e98 commit 8eb2445

File tree

2 files changed

+86
-1
lines changed

2 files changed

+86
-1
lines changed

spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.aop.interceptor;
1818

1919
import java.lang.reflect.Method;
20+
import java.lang.reflect.Modifier;
2021
import java.util.concurrent.Callable;
2122
import java.util.concurrent.ExecutionException;
2223
import java.util.concurrent.Executor;
@@ -60,6 +61,7 @@
6061
* @author Juergen Hoeller
6162
* @author Chris Beams
6263
* @author Stephane Nicoll
64+
* @author Bao Ngo
6365
* @since 3.0
6466
* @see org.springframework.scheduling.annotation.Async
6567
* @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor
@@ -125,7 +127,16 @@ public Object invoke(final MethodInvocation invocation) throws Throwable {
125127
return null;
126128
};
127129

128-
return doSubmit(task, executor, invocation.getMethod().getReturnType());
130+
return doSubmit( task, executor, determineReturnType( invocation, userMethod ) );
131+
}
132+
133+
private static Class<?> determineReturnType(MethodInvocation invocation, Method userMethod) {
134+
Method originalMethod = invocation.getMethod();
135+
if( Modifier.isAbstract( originalMethod.getModifiers() ) ) {
136+
return userMethod.getReturnType();
137+
}
138+
139+
return originalMethod.getReturnType();
129140
}
130141

131142
/**
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2002-2024 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.interceptor;
18+
19+
import java.util.concurrent.Callable;
20+
import java.util.concurrent.CompletableFuture;
21+
import java.util.concurrent.Future;
22+
23+
import org.aopalliance.intercept.MethodInvocation;
24+
import org.junit.jupiter.api.Test;
25+
import org.mockito.ArgumentCaptor;
26+
27+
import org.springframework.core.task.AsyncTaskExecutor;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.mockito.BDDMockito.given;
31+
import static org.mockito.Mockito.any;
32+
import static org.mockito.Mockito.mock;
33+
import static org.mockito.Mockito.spy;
34+
import static org.mockito.Mockito.verify;
35+
36+
37+
/**
38+
* Tests for {@link AsyncExecutionInterceptor}.
39+
*
40+
* @author Bao Ngo
41+
* @since 7.0
42+
*/
43+
class AsyncExecutionInterceptorTests {
44+
45+
@Test
46+
public void testInvokeOnInterface() throws Throwable {
47+
AsyncExecutionInterceptor interceptor = spy( new AsyncExecutionInterceptor( null ) );
48+
Impl impl = new Impl();
49+
ArgumentCaptor<Class<?>> classArgumentCaptor = ArgumentCaptor.forClass( Class.class );
50+
MethodInvocation mi = mock();
51+
given( mi.getThis() ).willReturn( impl );
52+
given( mi.getMethod() ).willReturn( I.class.getMethod( "doSomeThing" ) );
53+
interceptor.invoke( mi );
54+
verify( interceptor ).doSubmit(
55+
any( Callable.class ),
56+
any( AsyncTaskExecutor.class ),
57+
classArgumentCaptor.capture()
58+
);
59+
assertThat( classArgumentCaptor.getValue() ).isEqualTo( Future.class );
60+
}
61+
62+
63+
private interface I<O> {
64+
O doSomeThing();
65+
}
66+
67+
private static final class Impl implements I<Future<Void>> {
68+
@Override
69+
public Future<Void> doSomeThing() {
70+
return CompletableFuture.runAsync( () -> {
71+
} );
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)