From 23ecb501371a2e95c7c1e0ba6e4d5476766a10a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Fri, 23 Jun 2023 14:01:08 +0200 Subject: [PATCH 1/3] Optimize KotlinReflectionParameterNameDiscoverer This commit removes the intermediate list allocation. Closes gh-30725 --- ...otlinReflectionParameterNameDiscoverer.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/KotlinReflectionParameterNameDiscoverer.java b/spring-core/src/main/java/org/springframework/core/KotlinReflectionParameterNameDiscoverer.java index 610cf5d1cb..53629a40c6 100644 --- a/spring-core/src/main/java/org/springframework/core/KotlinReflectionParameterNameDiscoverer.java +++ b/spring-core/src/main/java/org/springframework/core/KotlinReflectionParameterNameDiscoverer.java @@ -74,21 +74,17 @@ public class KotlinReflectionParameterNameDiscoverer implements ParameterNameDis @Nullable private String[] getParameterNames(List parameters) { - List filteredParameters = parameters - .stream() + String[] parameterNames = parameters.stream() // Extension receivers of extension methods must be included as they appear as normal method parameters in Java .filter(p -> KParameter.Kind.VALUE.equals(p.getKind()) || KParameter.Kind.EXTENSION_RECEIVER.equals(p.getKind())) - .toList(); - String[] parameterNames = new String[filteredParameters.size()]; - for (int i = 0; i < filteredParameters.size(); i++) { - KParameter parameter = filteredParameters.get(i); - // extension receivers are not explicitly named, but require a name for Java interoperability - // $receiver is not a valid Kotlin identifier, but valid in Java, so it can be used here - String name = KParameter.Kind.EXTENSION_RECEIVER.equals(parameter.getKind()) ? "$receiver" : parameter.getName(); - if (name == null) { + // extension receivers are not explicitly named, but require a name for Java interoperability + // $receiver is not a valid Kotlin identifier, but valid in Java, so it can be used here + .map(p -> KParameter.Kind.EXTENSION_RECEIVER.equals(p.getKind()) ? "$receiver" : p.getName()) + .toArray(String[]::new); + for (String parameterName : parameterNames) { + if (parameterName == null) { return null; } - parameterNames[i] = name; } return parameterNames; } From 81f1edbaf2e169c4b50c2923db1b6b2a4f435e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Fri, 23 Jun 2023 14:07:14 +0200 Subject: [PATCH 2/3] Change InvocableHandlerMethod#invokeSuspendingFunction return type This commits changes the return type from Publisher to Object in order to avoid potential compatibility issues when the Reactive Streams dependency is not in the classpath. Closes gh-30716 --- .../web/method/support/InvocableHandlerMethod.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java b/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java index 99e7ea079c..b2e2755a18 100644 --- a/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java +++ b/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java @@ -20,8 +20,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; -import org.reactivestreams.Publisher; - import org.springframework.context.MessageSource; import org.springframework.core.CoroutinesUtils; import org.springframework.core.DefaultParameterNameDiscoverer; @@ -240,7 +238,7 @@ public class InvocableHandlerMethod extends HandlerMethod { * instead. * @since 6.0 */ - protected Publisher invokeSuspendingFunction(Method method, Object target, Object[] args) { + protected Object invokeSuspendingFunction(Method method, Object target, Object[] args) { return CoroutinesUtils.invokeSuspendingFunction(method, target, args); } From d3a249e34dea676647bb59f91344ef7f32bb175c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Fri, 23 Jun 2023 14:17:38 +0200 Subject: [PATCH 3/3] Reduce the delay used for Coroutines in tests Closes gh-30731 --- .../core/KotlinCoroutinesUtilsTests.kt | 8 +++---- ...lientToServerCoroutinesIntegrationTests.kt | 22 +++++++++---------- ...esAnnotationTransactionInterceptorTests.kt | 18 +++++++-------- ...bstractCoroutinesTransactionAspectTests.kt | 6 ++--- .../KotlinInvocableHandlerMethodTests.kt | 12 +++++----- .../annotation/CoroutinesIntegrationTests.kt | 4 ++-- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/spring-core/src/test/kotlin/org/springframework/core/KotlinCoroutinesUtilsTests.kt b/spring-core/src/test/kotlin/org/springframework/core/KotlinCoroutinesUtilsTests.kt index 55d1cee25e..e43285f9b1 100644 --- a/spring-core/src/test/kotlin/org/springframework/core/KotlinCoroutinesUtilsTests.kt +++ b/spring-core/src/test/kotlin/org/springframework/core/KotlinCoroutinesUtilsTests.kt @@ -34,7 +34,7 @@ class KotlinCoroutinesUtilsTests { fun deferredToMono() { runBlocking { val deferred: Deferred = async(Dispatchers.IO) { - delay(10) + delay(1) "foo" } val mono = CoroutinesUtils.deferredToMono(deferred) @@ -122,12 +122,12 @@ class KotlinCoroutinesUtilsTests { } suspend fun suspendingFunction(value: String): String { - delay(10) + delay(1) return value } suspend fun suspendingFunctionWithFlow(): Flow { - delay(10) + delay(1) return flowOf("foo", "bar") } @@ -136,7 +136,7 @@ class KotlinCoroutinesUtilsTests { } suspend fun suspendingFunctionWithContext(value: String): String { - delay(10) + delay(1) Assertions.assertThat(coroutineContext[CoroutineName]?.name).isEqualTo("name") return value } diff --git a/spring-messaging/src/test/kotlin/org/springframework/messaging/rsocket/RSocketClientToServerCoroutinesIntegrationTests.kt b/spring-messaging/src/test/kotlin/org/springframework/messaging/rsocket/RSocketClientToServerCoroutinesIntegrationTests.kt index 4f47e7b9a8..1694d0a905 100644 --- a/spring-messaging/src/test/kotlin/org/springframework/messaging/rsocket/RSocketClientToServerCoroutinesIntegrationTests.kt +++ b/spring-messaging/src/test/kotlin/org/springframework/messaging/rsocket/RSocketClientToServerCoroutinesIntegrationTests.kt @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 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. @@ -154,13 +154,13 @@ class RSocketClientToServerCoroutinesIntegrationTests { @MessageMapping("receive-async") suspend fun receiveAsync(payload: String) { - delay(10) + delay(1) fireForgetPayloads.tryEmitNext(payload) } @MessageMapping("echo-async") suspend fun echoAsync(payload: String): String { - delay(10) + delay(1) return "$payload async" } @@ -169,7 +169,7 @@ class RSocketClientToServerCoroutinesIntegrationTests { var i = 0 return flow { while(true) { - delay(10) + delay(1) emit("$payload ${i++}") } } @@ -177,11 +177,11 @@ class RSocketClientToServerCoroutinesIntegrationTests { @MessageMapping("echo-stream-async") suspend fun echoStreamAsync(payload: String): Flow { - delay(10) + delay(1) var i = 0 return flow { while(true) { - delay(10) + delay(1) emit("$payload ${i++}") } } @@ -189,31 +189,31 @@ class RSocketClientToServerCoroutinesIntegrationTests { @MessageMapping("echo-channel") fun echoChannel(payloads: Flow) = payloads.map { - delay(10) + delay(1) "$it async" } @Suppress("UNUSED_PARAMETER") @MessageMapping("thrown-exception") suspend fun handleAndThrow(payload: String): String { - delay(10) + delay(1) throw IllegalArgumentException("Invalid input error") } @MessageMapping("unit-return-value") suspend fun unitReturnValue(payload: String) = - if (payload != "bad") delay(10) else throw IllegalStateException("bad") + if (payload != "bad") delay(1) else throw IllegalStateException("bad") @MessageExceptionHandler suspend fun handleException(ex: IllegalArgumentException): String { - delay(10) + delay(1) return "${ex.message} handled" } @Suppress("UNUSED_PARAMETER") @MessageExceptionHandler suspend fun handleExceptionWithVoidReturnValue(ex: IllegalStateException) { - delay(10) + delay(1) } } diff --git a/spring-tx/src/test/kotlin/org/springframework/transaction/annotation/CoroutinesAnnotationTransactionInterceptorTests.kt b/spring-tx/src/test/kotlin/org/springframework/transaction/annotation/CoroutinesAnnotationTransactionInterceptorTests.kt index 4ec5b21d6d..4f2437f1be 100644 --- a/spring-tx/src/test/kotlin/org/springframework/transaction/annotation/CoroutinesAnnotationTransactionInterceptorTests.kt +++ b/spring-tx/src/test/kotlin/org/springframework/transaction/annotation/CoroutinesAnnotationTransactionInterceptorTests.kt @@ -160,48 +160,48 @@ class CoroutinesAnnotationTransactionInterceptorTests { open class TestWithCoroutines { open suspend fun suspendingNoValueSuccess() { - delay(10) + delay(1) } open suspend fun suspendingNoValueFailure() { - delay(10) + delay(1) throw IllegalStateException() } open suspend fun suspendingValueSuccess(): String { - delay(10) + delay(1) return "foo" } open suspend fun suspendingValueFailure(): String { - delay(10) + delay(1) throw IllegalStateException() } open fun flowSuccess(): Flow { return flow { emit("foo") - delay(10) + delay(1) emit("foo") } } open suspend fun suspendingFlowSuccess(): Flow { - delay(10) + delay(1) return flow { emit("foo") - delay(10) + delay(1) emit("foo") } } open suspend fun suspendingValueSuccessWithContext(): String { - delay(10) + delay(1) return coroutineContext[ExampleContext.Key].toString() } open suspend fun suspendingValueFailureWithContext(): String { - delay(10) + delay(1) throw IllegalStateException(coroutineContext[ExampleContext.Key].toString()) } } diff --git a/spring-tx/src/test/kotlin/org/springframework/transaction/interceptor/AbstractCoroutinesTransactionAspectTests.kt b/spring-tx/src/test/kotlin/org/springframework/transaction/interceptor/AbstractCoroutinesTransactionAspectTests.kt index e141188f5b..6843f2e796 100644 --- a/spring-tx/src/test/kotlin/org/springframework/transaction/interceptor/AbstractCoroutinesTransactionAspectTests.kt +++ b/spring-tx/src/test/kotlin/org/springframework/transaction/interceptor/AbstractCoroutinesTransactionAspectTests.kt @@ -337,17 +337,17 @@ abstract class AbstractCoroutinesTransactionAspectTests { private var name: String? = null override suspend fun getName(): String? { - delay(10) + delay(1) return name } override suspend fun setName(name: String?) { - delay(10) + delay(1) this.name = name } override suspend fun exceptional(t: Throwable?) { - delay(10) + delay(1) if (t != null) { throw t } diff --git a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/KotlinInvocableHandlerMethodTests.kt b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/KotlinInvocableHandlerMethodTests.kt index 7975a7dd85..1608a90895 100644 --- a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/KotlinInvocableHandlerMethodTests.kt +++ b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/KotlinInvocableHandlerMethodTests.kt @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -134,12 +134,12 @@ class KotlinInvocableHandlerMethodTests { class CoroutinesController { suspend fun singleArg(q: String?): String { - delay(10) + delay(1) return "success:$q" } suspend fun noArgs(): String { - delay(10) + delay(1) return "success" } @@ -149,12 +149,12 @@ class KotlinInvocableHandlerMethodTests { @ResponseStatus(HttpStatus.CREATED) suspend fun created(): String { - delay(10) + delay(1) return "created" } suspend fun response(response: ServerHttpResponse) { - delay(10) + delay(1) response.headers.add("foo", "bar") } } @@ -162,7 +162,7 @@ class KotlinInvocableHandlerMethodTests { private class PrivateCoroutinesController { suspend fun singleArg(q: String?): String { - delay(10) + delay(1) return "success:$q" } } diff --git a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/method/annotation/CoroutinesIntegrationTests.kt b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/method/annotation/CoroutinesIntegrationTests.kt index 3af6b1b886..4252423c51 100644 --- a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/method/annotation/CoroutinesIntegrationTests.kt +++ b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/method/annotation/CoroutinesIntegrationTests.kt @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -172,7 +172,7 @@ class CoroutinesIntegrationTests : AbstractRequestMappingIntegrationTests() { @GetMapping("/suspending-flow") suspend fun suspendingFlowEndpoint(): Flow { - delay(10) + delay(1) return flow { emit("foo") delay(1)