diff --git a/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java b/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java index c2f4cccf3db..ee1c342318d 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java @@ -353,9 +353,10 @@ public abstract class AopUtils { // Use reflection to invoke the method. try { - ReflectionUtils.makeAccessible(method); - return (coroutinesReactorPresent && KotlinDetector.isSuspendingFunction(method) ? - KotlinDelegate.invokeSuspendingFunction(method, target, args) : method.invoke(target, args)); + Method originalMethod = BridgeMethodResolver.findBridgedMethod(method); + ReflectionUtils.makeAccessible(originalMethod); + return (coroutinesReactorPresent && KotlinDetector.isSuspendingFunction(originalMethod) ? + KotlinDelegate.invokeSuspendingFunction(originalMethod, target, args) : originalMethod.invoke(target, args)); } catch (InvocationTargetException ex) { // Invoked method threw a checked exception. diff --git a/spring-aop/src/test/kotlin/org/springframework/aop/support/AopUtilsKotlinTests.kt b/spring-aop/src/test/kotlin/org/springframework/aop/support/AopUtilsKotlinTests.kt index a3c54130560..9d28fca0f7d 100644 --- a/spring-aop/src/test/kotlin/org/springframework/aop/support/AopUtilsKotlinTests.kt +++ b/spring-aop/src/test/kotlin/org/springframework/aop/support/AopUtilsKotlinTests.kt @@ -34,19 +34,48 @@ class AopUtilsKotlinTests { @Test fun `Invoking suspending function should return Mono`() { val value = "foo" - val method = ReflectionUtils.findMethod(AopUtilsKotlinTests::class.java, "suspendingFunction", - String::class.java, Continuation::class.java)!! + val method = ReflectionUtils.findMethod(WithoutInterface::class.java, "handle", + String::class. java, Continuation::class.java)!! val continuation = Continuation(CoroutineName("test")) { } - val result = AopUtils.invokeJoinpointUsingReflection(this, method, arrayOf(value, continuation)) + val result = AopUtils.invokeJoinpointUsingReflection(WithoutInterface(), method, arrayOf(value, continuation)) assertThat(result).isInstanceOfSatisfying(Mono::class.java) { assertThat(it.block()).isEqualTo(value) } } + @Test + fun `Invoking suspending function on bridged method should return Mono`() { + val value = "foo" + val bridgedMethod = ReflectionUtils.findMethod(WithInterface::class.java, "handle", Object::class.java, Continuation::class.java)!! + val continuation = Continuation(CoroutineName("test")) { } + val result = AopUtils.invokeJoinpointUsingReflection(WithInterface(), bridgedMethod, arrayOf(value, continuation)) + assertThat(result).isInstanceOfSatisfying(Mono::class.java) { + assertThat(it.block()).isEqualTo(value) + } + } + @Suppress("unused") suspend fun suspendingFunction(value: String): String { delay(1) return value } + class WithoutInterface { + suspend fun handle(value: String): String { + delay(1) + return value + } + } + + interface ProxyInterface { + suspend fun handle(value: T): T + } + + class WithInterface : ProxyInterface { + override suspend fun handle(value: String): String { + delay(1) + return value + } + } + }