This commit is contained in:
Jakob Hofer 2025-10-07 23:10:35 +03:00 committed by GitHub
commit 9d43c6b2dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 75 additions and 2 deletions

View File

@ -127,6 +127,12 @@ jar {
} }
} }
kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xcontext-parameters")
}
}
test { test {
// Make sure the classes dir is used on the test classpath (required by ResourceTests). // 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. // When test fixtures are involved, the JAR is used by default.

View File

@ -125,7 +125,7 @@ public abstract class CoroutinesUtils {
for (KParameter parameter : function.getParameters()) { for (KParameter parameter : function.getParameters()) {
switch (parameter.getKind()) { switch (parameter.getKind()) {
case INSTANCE -> argMap.put(parameter, target); case INSTANCE -> argMap.put(parameter, target);
case VALUE, EXTENSION_RECEIVER -> { case VALUE, EXTENSION_RECEIVER, CONTEXT -> {
Object arg = args[index]; Object arg = args[index];
if (!(parameter.isOptional() && arg == null)) { if (!(parameter.isOptional() && arg == null)) {
KType type = parameter.getType(); KType type = parameter.getType();

View File

@ -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 @Test
fun invokeSuspendingFunctionWithGenericParameter() { fun invokeSuspendingFunctionWithGenericParameter() {
val method = GenericController::class.java.declaredMethods.first { it.name.startsWith("handle") } val method = GenericController::class.java.declaredMethods.first { it.name.startsWith("handle") }
@ -377,6 +397,18 @@ class CoroutinesUtilsTests {
return "${this.message}-$limit" 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 { interface Named {
val name: String val name: String
} }

View File

@ -102,3 +102,9 @@ dependencies {
testRuntimeOnly("org.glassfish:jakarta.el") testRuntimeOnly("org.glassfish:jakarta.el")
testRuntimeOnly("org.hibernate.validator:hibernate-validator") testRuntimeOnly("org.hibernate.validator:hibernate-validator")
} }
kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xcontext-parameters")
}
}

View File

@ -318,7 +318,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
for (KParameter parameter : function.getParameters()) { for (KParameter parameter : function.getParameters()) {
switch (parameter.getKind()) { switch (parameter.getKind()) {
case INSTANCE -> argMap.put(parameter, target); case INSTANCE -> argMap.put(parameter, target);
case VALUE, EXTENSION_RECEIVER -> { case VALUE, EXTENSION_RECEIVER, CONTEXT -> {
Object arg = args[index]; Object arg = args[index];
if (!(parameter.isOptional() && arg == null)) { if (!(parameter.isOptional() && arg == null)) {
KType type = parameter.getType(); KType type = parameter.getType();

View File

@ -238,6 +238,22 @@ class InvocableHandlerMethodKotlinTests {
Assertions.assertThat(value).isEqualTo("foo-20") 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 @Test
fun genericParameter() { fun genericParameter() {
val horse = Animal("horse") 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<T : Named> { private abstract class GenericHandler<T : Named> {
fun handle(named: T) = named.name fun handle(named: T) = named.name