Support Kotlin extensions in web handlers

This commit restores support for Kotlin extensions in
web handlers, and adds support for invoking reflectively
suspending extension functions, as well as the other
features supported as of Spring Framework 6.1 like
value classes and default value for parameters.

Closes gh-31876
This commit is contained in:
Sébastien Deleuze
2023-12-21 12:15:26 +01:00
parent 5f8a031c22
commit 85cb6cc5fb
6 changed files with 130 additions and 25 deletions

View File

@@ -117,8 +117,11 @@ public abstract class CoroutinesUtils {
int index = 0;
for (KParameter parameter : function.getParameters()) {
switch (parameter.getKind()) {
case INSTANCE -> argMap.put(parameter, target);
case VALUE -> {
case INSTANCE:
argMap.put(parameter, target);
break;
case VALUE:
case EXTENSION_RECEIVER:
if (!parameter.isOptional() || args[index] != null) {
if (parameter.getType().getClassifier() instanceof KClass<?> kClass && kClass.isValue()) {
Class<?> javaClass = JvmClassMappingKt.getJavaClass(kClass);
@@ -131,7 +134,8 @@ public abstract class CoroutinesUtils {
}
}
index++;
}
break;
}
}
return KCallables.callSuspendBy(function, argMap, continuation);

View File

@@ -154,6 +154,26 @@ class CoroutinesUtilsTests {
}
}
@Test
fun invokeSuspendingFunctionWithExtension() {
val method = CoroutinesUtilsTests::class.java.getDeclaredMethod("suspendingFunctionWithExtension",
CustomException::class.java, Continuation::class.java)
val mono = CoroutinesUtils.invokeSuspendingFunction(method, this, CustomException("foo")) as Mono
runBlocking {
Assertions.assertThat(mono.awaitSingleOrNull()).isEqualTo("foo")
}
}
@Test
fun invokeSuspendingFunctionWithExtensionAndParameter() {
val method = CoroutinesUtilsTests::class.java.getDeclaredMethod("suspendingFunctionWithExtensionAndParameter",
CustomException::class.java, Int::class.java, Continuation::class.java)
val mono = CoroutinesUtils.invokeSuspendingFunction(method, this, CustomException("foo"), 20) as Mono
runBlocking {
Assertions.assertThat(mono.awaitSingleOrNull()).isEqualTo("foo-20")
}
}
suspend fun suspendingFunction(value: String): String {
delay(1)
return value
@@ -186,7 +206,19 @@ class CoroutinesUtilsTests {
return value.value
}
suspend fun CustomException.suspendingFunctionWithExtension(): String {
delay(1)
return "${this.message}"
}
suspend fun CustomException.suspendingFunctionWithExtensionAndParameter(limit: Int): String {
delay(1)
return "${this.message}-$limit"
}
@JvmInline
value class ValueClass(val value: String)
class CustomException(message: String) : Throwable(message)
}