Add a classpath check for AOP Coroutines/Reactive conversion

Closes gh-32599
This commit is contained in:
Sébastien Deleuze 2024-04-09 14:01:51 +02:00
parent 7b7cfb27a3
commit 23696b7db8
3 changed files with 13 additions and 5 deletions

View File

@ -102,6 +102,9 @@ class CglibAopProxy implements AopProxy, Serializable {
private static final String COROUTINES_FLOW_CLASS_NAME = "kotlinx.coroutines.flow.Flow";
private static final boolean coroutinesReactorPresent = ClassUtils.isPresent("kotlinx.coroutines.reactor.MonoKt",
CglibAopProxy.class.getClassLoader());;
/** The configuration used to configure this proxy. */
protected final AdvisedSupport advised;
@ -421,7 +424,7 @@ class CglibAopProxy implements AopProxy, Serializable {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
if (KotlinDetector.isSuspendingFunction(method)) {
if (coroutinesReactorPresent && KotlinDetector.isSuspendingFunction(method)) {
return COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName()) ?
CoroutinesUtils.asFlow(returnValue) :
CoroutinesUtils.awaitSingleOrNull(returnValue, arguments[arguments.length - 1]);

View File

@ -75,6 +75,9 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
private static final String COROUTINES_FLOW_CLASS_NAME = "kotlinx.coroutines.flow.Flow";
private static final boolean coroutinesReactorPresent = ClassUtils.isPresent("kotlinx.coroutines.reactor.MonoKt",
JdkDynamicAopProxy.class.getClassLoader());;
/** We use a static Log to avoid serialization issues. */
private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
@ -234,7 +237,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
if (KotlinDetector.isSuspendingFunction(method)) {
if (coroutinesReactorPresent && KotlinDetector.isSuspendingFunction(method)) {
return COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName()) ?
CoroutinesUtils.asFlow(retVal) : CoroutinesUtils.awaitSingleOrNull(retVal, args[args.length - 1]);
}

View File

@ -28,7 +28,6 @@ import java.util.Set;
import kotlin.coroutines.Continuation;
import kotlin.coroutines.CoroutineContext;
import kotlinx.coroutines.Job;
import org.reactivestreams.Publisher;
import org.springframework.aop.Advisor;
import org.springframework.aop.AopInvocationException;
@ -65,6 +64,9 @@ import org.springframework.util.ReflectionUtils;
*/
public abstract class AopUtils {
private static final boolean coroutinesReactorPresent = ClassUtils.isPresent("kotlinx.coroutines.reactor.MonoKt",
AopUtils.class.getClassLoader());;
/**
* Check whether the given object is a JDK dynamic proxy or a CGLIB proxy.
* <p>This method additionally checks if the given object is an instance
@ -347,7 +349,7 @@ public abstract class AopUtils {
// Use reflection to invoke the method.
try {
ReflectionUtils.makeAccessible(method);
return KotlinDetector.isSuspendingFunction(method) ?
return coroutinesReactorPresent && KotlinDetector.isSuspendingFunction(method) ?
KotlinDelegate.invokeSuspendingFunction(method, target, args) : method.invoke(target, args);
}
catch (InvocationTargetException ex) {
@ -370,7 +372,7 @@ public abstract class AopUtils {
*/
private static class KotlinDelegate {
public static Publisher<?> invokeSuspendingFunction(Method method, @Nullable Object target, Object... args) {
public static Object invokeSuspendingFunction(Method method, @Nullable Object target, Object... args) {
Continuation<?> continuation = (Continuation<?>) args[args.length -1];
Assert.state(continuation != null, "No Continuation available");
CoroutineContext context = continuation.getContext().minusKey(Job.Key);