Merge branch '6.2.x'

This commit is contained in:
Sébastien Deleuze
2024-11-27 16:40:05 +01:00
6 changed files with 320 additions and 62 deletions

View File

@@ -16,14 +16,18 @@
package org.springframework.web.method.support
import kotlinx.coroutines.delay
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.core.MethodParameter
import org.springframework.util.ReflectionUtils
import org.springframework.web.bind.support.WebDataBinderFactory
import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.context.request.ServletWebRequest
import org.springframework.web.testfixture.method.ResolvableMethod
import org.springframework.web.testfixture.servlet.MockHttpServletRequest
import org.springframework.web.testfixture.servlet.MockHttpServletResponse
import reactor.core.publisher.Mono
import reactor.test.StepVerifier
import java.lang.reflect.Method
import kotlin.reflect.jvm.javaGetter
import kotlin.reflect.jvm.javaMethod
@@ -33,6 +37,7 @@ import kotlin.reflect.jvm.javaMethod
*
* @author Sebastien Deleuze
*/
@Suppress("UNCHECKED_CAST")
class InvocableHandlerMethodKotlinTests {
private val request: NativeWebRequest = ServletWebRequest(MockHttpServletRequest(), MockHttpServletResponse())
@@ -110,6 +115,12 @@ class InvocableHandlerMethodKotlinTests {
Assertions.assertThat(value).isEqualTo("foo")
}
@Test
fun resultOfUnitReturnValue() {
val value = getInvocable(ValueClassHandler::resultOfUnitReturnValue.javaMethod!!).invokeForRequest(request, null)
Assertions.assertThat(value).isNull()
}
@Test
fun valueClassDefaultValue() {
composite.addResolver(StubArgumentResolver(Double::class.java))
@@ -138,6 +149,60 @@ class InvocableHandlerMethodKotlinTests {
Assertions.assertThat(value).isEqualTo('a')
}
@Test
fun suspendingValueClass() {
composite.addResolver(ContinuationHandlerMethodArgumentResolver())
composite.addResolver(StubArgumentResolver(Long::class.java, 1L))
val value = getInvocable(SuspendingValueClassHandler::longValueClass.javaMethod!!).invokeForRequest(request, null)
StepVerifier.create(value as Mono<Long>).expectNext(1L).verifyComplete()
}
@Test
fun suspendingValueClassReturnValue() {
composite.addResolver(ContinuationHandlerMethodArgumentResolver())
val value = getInvocable(SuspendingValueClassHandler::valueClassReturnValue.javaMethod!!).invokeForRequest(request, null)
StepVerifier.create(value as Mono<String>).expectNext("foo").verifyComplete()
}
@Test
fun suspendingResultOfUnitReturnValue() {
composite.addResolver(ContinuationHandlerMethodArgumentResolver())
val value = getInvocable(SuspendingValueClassHandler::resultOfUnitReturnValue.javaMethod!!).invokeForRequest(request, null)
StepVerifier.create(value as Mono<Unit>).verifyComplete()
}
@Test
fun suspendingValueClassDefaultValue() {
composite.addResolver(ContinuationHandlerMethodArgumentResolver())
composite.addResolver(StubArgumentResolver(Double::class.java))
val value = getInvocable(SuspendingValueClassHandler::doubleValueClass.javaMethod!!).invokeForRequest(request, null)
StepVerifier.create(value as Mono<Double>).expectNext(3.1).verifyComplete()
}
@Test
fun suspendingValueClassWithInit() {
composite.addResolver(ContinuationHandlerMethodArgumentResolver())
composite.addResolver(StubArgumentResolver(String::class.java, ""))
val value = getInvocable(SuspendingValueClassHandler::valueClassWithInit.javaMethod!!).invokeForRequest(request, null)
StepVerifier.create(value as Mono<String>).verifyError(IllegalArgumentException::class.java)
}
@Test
fun suspendingValueClassWithNullable() {
composite.addResolver(ContinuationHandlerMethodArgumentResolver())
composite.addResolver(StubArgumentResolver(LongValueClass::class.java, null))
val value = getInvocable(SuspendingValueClassHandler::valueClassWithNullable.javaMethod!!).invokeForRequest(request, null)
StepVerifier.create(value as Mono<Long>).verifyComplete()
}
@Test
fun suspendingValueClassWithPrivateConstructor() {
composite.addResolver(ContinuationHandlerMethodArgumentResolver())
composite.addResolver(StubArgumentResolver(Char::class.java, 'a'))
val value = getInvocable(SuspendingValueClassHandler::valueClassWithPrivateConstructor.javaMethod!!).invokeForRequest(request, null)
StepVerifier.create(value as Mono<Char>).expectNext('a').verifyComplete()
}
@Test
fun propertyAccessor() {
val value = getInvocable(PropertyAccessorHandler::prop.javaGetter!!).invokeForRequest(request, null)
@@ -206,23 +271,58 @@ class InvocableHandlerMethodKotlinTests {
private class ValueClassHandler {
fun valueClassReturnValue() =
StringValueClass("foo")
fun valueClassReturnValue() = StringValueClass("foo")
fun longValueClass(limit: LongValueClass) =
limit.value
fun resultOfUnitReturnValue() = Result.success(Unit)
fun doubleValueClass(limit: DoubleValueClass = DoubleValueClass(3.1)) =
limit.value
fun longValueClass(limit: LongValueClass) = limit.value
fun valueClassWithInit(valueClass: ValueClassWithInit) =
valueClass
fun doubleValueClass(limit: DoubleValueClass = DoubleValueClass(3.1)) = limit.value
fun valueClassWithNullable(limit: LongValueClass?) =
limit?.value
fun valueClassWithInit(valueClass: ValueClassWithInit) = valueClass
fun valueClassWithPrivateConstructor(limit: ValueClassWithPrivateConstructor) =
limit.value
fun valueClassWithNullable(limit: LongValueClass?) = limit?.value
fun valueClassWithPrivateConstructor(limit: ValueClassWithPrivateConstructor) = limit.value
}
private class SuspendingValueClassHandler {
suspend fun valueClassReturnValue(): StringValueClass {
delay(1)
return StringValueClass("foo")
}
suspend fun resultOfUnitReturnValue(): Result<Unit> {
delay(1)
return Result.success(Unit)
}
suspend fun longValueClass(limit: LongValueClass): Long {
delay(1)
return limit.value
}
suspend fun doubleValueClass(limit: DoubleValueClass = DoubleValueClass(3.1)): Double {
delay(1)
return limit.value
}
suspend fun valueClassWithInit(valueClass: ValueClassWithInit): ValueClassWithInit {
delay(1)
return valueClass
}
suspend fun valueClassWithNullable(limit: LongValueClass?): Long? {
delay(1)
return limit?.value
}
suspend fun valueClassWithPrivateConstructor(limit: ValueClassWithPrivateConstructor): Char {
delay(1)
return limit.value
}
}
private class PropertyAccessorHandler {
@@ -282,4 +382,19 @@ class InvocableHandlerMethodKotlinTests {
class CustomException(message: String) : Throwable(message)
// Avoid adding a spring-webmvc dependency
class ContinuationHandlerMethodArgumentResolver : HandlerMethodArgumentResolver {
override fun supportsParameter(parameter: MethodParameter) =
"kotlin.coroutines.Continuation" == parameter.getParameterType().getName()
override fun resolveArgument(
parameter: MethodParameter,
mavContainer: ModelAndViewContainer?,
webRequest: NativeWebRequest,
binderFactory: WebDataBinderFactory?
) = null
}
}