diff --git a/spring-core/spring-core.gradle b/spring-core/spring-core.gradle index cd88a0ee6d..ad8f0d9ece 100644 --- a/spring-core/spring-core.gradle +++ b/spring-core/spring-core.gradle @@ -127,6 +127,12 @@ jar { } } +kotlin { + compilerOptions { + freeCompilerArgs.addAll("-Xcontext-parameters") + } +} + test { // Make sure the classes dir is used on the test classpath (required by ResourceTests). // When test fixtures are involved, the JAR is used by default. diff --git a/spring-core/src/test/kotlin/org/springframework/core/CoroutinesUtilsTests.kt b/spring-core/src/test/kotlin/org/springframework/core/CoroutinesUtilsTests.kt index 8547e553c4..f3f45309f8 100644 --- a/spring-core/src/test/kotlin/org/springframework/core/CoroutinesUtilsTests.kt +++ b/spring-core/src/test/kotlin/org/springframework/core/CoroutinesUtilsTests.kt @@ -275,6 +275,26 @@ class CoroutinesUtilsTests { } } + @Test + fun invokeSuspendingFunctionWithContextParameter() { + val method = CoroutinesUtilsTests::class.java.getDeclaredMethod("suspendingFunctionWithContextParameter", + 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 invokeSuspendingFunctionWithContextParameterAndParameter() { + val method = CoroutinesUtilsTests::class.java.getDeclaredMethod("suspendingFunctionWithContextParameterAndParameter", + 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") + } + } + @Test fun invokeSuspendingFunctionWithGenericParameter() { val method = GenericController::class.java.declaredMethods.first { it.name.startsWith("handle") } @@ -377,6 +397,18 @@ class CoroutinesUtilsTests { return "${this.message}-$limit" } + context(value: CustomException) + suspend fun suspendingFunctionWithContextParameter(): String { + delay(1) + return "${value.message}" + } + + context(value: CustomException) + suspend fun suspendingFunctionWithContextParameterAndParameter(limit: Int): String { + delay(1) + return "${value.message}-$limit" + } + interface Named { val name: String } diff --git a/spring-web/spring-web.gradle b/spring-web/spring-web.gradle index 62a50956d6..089a9e5a9b 100644 --- a/spring-web/spring-web.gradle +++ b/spring-web/spring-web.gradle @@ -102,3 +102,9 @@ dependencies { testRuntimeOnly("org.glassfish:jakarta.el") testRuntimeOnly("org.hibernate.validator:hibernate-validator") } + +kotlin { + compilerOptions { + freeCompilerArgs.addAll("-Xcontext-parameters") + } +} \ No newline at end of file diff --git a/spring-web/src/test/kotlin/org/springframework/web/method/support/InvocableHandlerMethodKotlinTests.kt b/spring-web/src/test/kotlin/org/springframework/web/method/support/InvocableHandlerMethodKotlinTests.kt index 4b15b49219..408ea2840c 100644 --- a/spring-web/src/test/kotlin/org/springframework/web/method/support/InvocableHandlerMethodKotlinTests.kt +++ b/spring-web/src/test/kotlin/org/springframework/web/method/support/InvocableHandlerMethodKotlinTests.kt @@ -238,6 +238,22 @@ class InvocableHandlerMethodKotlinTests { Assertions.assertThat(value).isEqualTo("foo-20") } + @Test + fun contextParameter() { + composite.addResolver(StubArgumentResolver(CustomException::class.java, CustomException("foo"))) + val value = getInvocable(ReflectionUtils.findMethod(ContextParameterHandler::class.java, "handle", CustomException::class.java)!!).invokeForRequest(request, null) + Assertions.assertThat(value).isEqualTo("foo") + } + + @Test + fun contextParameterWithParameter() { + composite.addResolver(StubArgumentResolver(CustomException::class.java, CustomException("foo"))) + composite.addResolver(StubArgumentResolver(Int::class.java, 20)) + val value = getInvocable(ReflectionUtils.findMethod(ContextParameterHandler::class.java, "handleWithParameter", CustomException::class.java, Int::class.java)!!) + .invokeForRequest(request, null) + Assertions.assertThat(value).isEqualTo("foo-20") + } + @Test fun genericParameter() { val horse = Animal("horse") @@ -359,6 +375,19 @@ class InvocableHandlerMethodKotlinTests { } } + private class ContextParameterHandler { + + context(exception: CustomException) + fun handle(): String { + return "${exception.message}" + } + + context(exception: CustomException) + fun handleWithParameter(limit: Int): String { + return "${exception.message}-$limit" + } + } + private abstract class GenericHandler { fun handle(named: T) = named.name