Support suspending handler methods in Spring MVC

This commit adds support for Kotlin Coroutines suspending functions to
Spring MVC, by converting those to a Mono that can then be handled by
the asynchronous request processing feature.

It also optimizes Coroutines detection with the introduction of an
optimized KotlinDetector.isSuspendingFunction() method that does not
require kotlin-reflect.

Closes gh-23611
This commit is contained in:
Sébastien Deleuze
2020-10-09 12:22:15 +02:00
parent fad7243733
commit 94a42a3086
13 changed files with 110 additions and 29 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,9 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.springframework.core.CoroutinesUtils;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.KotlinDetector;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.lang.Nullable;
@@ -39,6 +41,7 @@ import org.springframework.web.method.HandlerMethod;
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @author Sebastien Deleuze
* @since 3.1
*/
public class InvocableHandlerMethod extends HandlerMethod {
@@ -185,12 +188,16 @@ public class InvocableHandlerMethod extends HandlerMethod {
*/
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
Method method = getBridgedMethod();
ReflectionUtils.makeAccessible(method);
try {
return getBridgedMethod().invoke(getBean(), args);
if (KotlinDetector.isSuspendingFunction(method)) {
return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);
}
return method.invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
assertTargetBean(method, getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, args), ex);
}