47
47
import org .springframework .cglib .proxy .MethodProxy ;
48
48
import org .springframework .cglib .proxy .NoOp ;
49
49
import org .springframework .core .KotlinDetector ;
50
+ import org .springframework .core .MethodParameter ;
50
51
import org .springframework .core .SmartClassLoader ;
51
52
import org .springframework .lang .Nullable ;
52
53
import org .springframework .util .Assert ;
75
76
* @author Ramnivas Laddad
76
77
* @author Chris Beams
77
78
* @author Dave Syer
79
+ * @author Sebastien Deleuze
78
80
* @see org.springframework.cglib.proxy.Enhancer
79
81
* @see AdvisedSupport#setProxyTargetClass
80
82
* @see DefaultAopProxyFactory
@@ -98,6 +100,8 @@ class CglibAopProxy implements AopProxy, Serializable {
98
100
/** Keeps track of the Classes that we have validated for final methods. */
99
101
private static final Map <Class <?>, Boolean > validatedClasses = new WeakHashMap <>();
100
102
103
+ private static final String COROUTINES_FLOW_CLASS_NAME = "kotlinx.coroutines.flow.Flow" ;
104
+
101
105
102
106
/** The configuration used to configure this proxy. */
103
107
protected final AdvisedSupport advised ;
@@ -399,10 +403,11 @@ private static boolean implementsInterface(Method method, Set<Class<?>> ifcs) {
399
403
/**
400
404
* Process a return value. Wraps a return of {@code this} if necessary to be the
401
405
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
406
+ * Also takes care of the conversion from {@code Mono} to Kotlin Coroutines if needed.
402
407
*/
403
408
@ Nullable
404
409
private static Object processReturnType (
405
- Object proxy , @ Nullable Object target , Method method , @ Nullable Object returnValue ) {
410
+ Object proxy , @ Nullable Object target , Method method , Object [] arguments , @ Nullable Object returnValue ) {
406
411
407
412
// Massage return value if necessary
408
413
if (returnValue != null && returnValue == target &&
@@ -416,6 +421,11 @@ private static Object processReturnType(
416
421
throw new AopInvocationException (
417
422
"Null return value from advice does not match primitive return type for: " + method );
418
423
}
424
+ if (KotlinDetector .isSuspendingFunction (method )) {
425
+ return COROUTINES_FLOW_CLASS_NAME .equals (new MethodParameter (method , -1 ).getParameterType ().getName ()) ?
426
+ CoroutinesUtils .asFlow (returnValue ) :
427
+ CoroutinesUtils .awaitSingleOrNull (returnValue , arguments [arguments .length - 1 ]);
428
+ }
419
429
return returnValue ;
420
430
}
421
431
@@ -446,7 +456,7 @@ public StaticUnadvisedInterceptor(@Nullable Object target) {
446
456
@ Nullable
447
457
public Object intercept (Object proxy , Method method , Object [] args , MethodProxy methodProxy ) throws Throwable {
448
458
Object retVal = AopUtils .invokeJoinpointUsingReflection (this .target , method , args );
449
- return processReturnType (proxy , this .target , method , retVal );
459
+ return processReturnType (proxy , this .target , method , args , retVal );
450
460
}
451
461
}
452
462
@@ -471,7 +481,7 @@ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy
471
481
try {
472
482
oldProxy = AopContext .setCurrentProxy (proxy );
473
483
Object retVal = AopUtils .invokeJoinpointUsingReflection (this .target , method , args );
474
- return processReturnType (proxy , this .target , method , retVal );
484
+ return processReturnType (proxy , this .target , method , args , retVal );
475
485
}
476
486
finally {
477
487
AopContext .setCurrentProxy (oldProxy );
@@ -499,7 +509,7 @@ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy
499
509
Object target = this .targetSource .getTarget ();
500
510
try {
501
511
Object retVal = AopUtils .invokeJoinpointUsingReflection (target , method , args );
502
- return processReturnType (proxy , target , method , retVal );
512
+ return processReturnType (proxy , target , method , args , retVal );
503
513
}
504
514
finally {
505
515
if (target != null ) {
@@ -529,7 +539,7 @@ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy
529
539
try {
530
540
oldProxy = AopContext .setCurrentProxy (proxy );
531
541
Object retVal = AopUtils .invokeJoinpointUsingReflection (target , method , args );
532
- return processReturnType (proxy , target , method , retVal );
542
+ return processReturnType (proxy , target , method , args , retVal );
533
543
}
534
544
finally {
535
545
AopContext .setCurrentProxy (oldProxy );
@@ -656,7 +666,7 @@ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy
656
666
proxy , this .target , method , args , this .targetClass , this .adviceChain , methodProxy );
657
667
// If we get here, we need to create a MethodInvocation.
658
668
Object retVal = invocation .proceed ();
659
- retVal = processReturnType (proxy , this .target , method , retVal );
669
+ retVal = processReturnType (proxy , this .target , method , args , retVal );
660
670
return retVal ;
661
671
}
662
672
}
@@ -706,7 +716,7 @@ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy
706
716
// We need to create a method invocation...
707
717
retVal = new CglibMethodInvocation (proxy , target , method , args , targetClass , chain , methodProxy ).proceed ();
708
718
}
709
- return processReturnType (proxy , target , method , retVal );
719
+ return processReturnType (proxy , target , method , args , retVal );
710
720
}
711
721
finally {
712
722
if (target != null && !targetSource .isStatic ()) {
0 commit comments