diff --git a/spring-core/src/main/java/org/springframework/core/MethodParameter.java b/spring-core/src/main/java/org/springframework/core/MethodParameter.java index b730f042d5b..2ea648b2d5e 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodParameter.java +++ b/spring-core/src/main/java/org/springframework/core/MethodParameter.java @@ -972,14 +972,16 @@ public class MethodParameter { * functions via Kotlin reflection. */ private static Type getGenericReturnType(Method method) { - try { - KFunction function = ReflectJvmMapping.getKotlinFunction(method); - if (function != null && function.isSuspend()) { - return ReflectJvmMapping.getJavaType(function.getReturnType()); + if (KotlinDetector.isSuspendingFunction(method)) { + try { + KFunction function = ReflectJvmMapping.getKotlinFunction(method); + if (function != null && function.isSuspend()) { + return ReflectJvmMapping.getJavaType(function.getReturnType()); + } + } + catch (UnsupportedOperationException ex) { + // probably a synthetic class - let's use java reflection instead } - } - catch (UnsupportedOperationException ex) { - // probably a synthetic class - let's use java reflection instead } return method.getGenericReturnType(); } @@ -989,18 +991,20 @@ public class MethodParameter { * functions via Kotlin reflection. */ private static Class getReturnType(Method method) { - try { - KFunction function = ReflectJvmMapping.getKotlinFunction(method); - if (function != null && function.isSuspend()) { - Type paramType = ReflectJvmMapping.getJavaType(function.getReturnType()); - if (paramType == Unit.class) { - paramType = void.class; + if (KotlinDetector.isSuspendingFunction(method)) { + try { + KFunction function = ReflectJvmMapping.getKotlinFunction(method); + if (function != null && function.isSuspend()) { + Type paramType = ReflectJvmMapping.getJavaType(function.getReturnType()); + if (paramType == Unit.class) { + paramType = void.class; + } + return ResolvableType.forType(paramType).resolve(method.getReturnType()); } - return ResolvableType.forType(paramType).resolve(method.getReturnType()); } - } - catch (UnsupportedOperationException ex) { - // probably a synthetic class - let's use java reflection instead + catch (UnsupportedOperationException ex) { + // probably a synthetic class - let's use java reflection instead + } } return method.getReturnType(); } diff --git a/spring-core/src/test/kotlin/org/springframework/core/MethodParameterKotlinTests.kt b/spring-core/src/test/kotlin/org/springframework/core/MethodParameterKotlinTests.kt index d63dae5ae5d..c6f580cab2d 100644 --- a/spring-core/src/test/kotlin/org/springframework/core/MethodParameterKotlinTests.kt +++ b/spring-core/src/test/kotlin/org/springframework/core/MethodParameterKotlinTests.kt @@ -18,6 +18,8 @@ package org.springframework.core import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test +import org.mockito.Mockito.mockStatic +import org.mockito.stubbing.Answer import java.lang.reflect.Method import java.lang.reflect.TypeVariable import kotlin.coroutines.Continuation @@ -114,6 +116,30 @@ class MethodParameterKotlinTests { assertThat(returnGenericParameterType("suspendFun8")).isEqualTo(Any::class.java) } + @Test + fun `Regular function return type`() { + assertThat(returnParameterType("regularFun")).isEqualTo(Producer::class.java) + assertThat(returnGenericParameterTypeName("regularFun")).isEqualTo("org.springframework.core.Producer") + } + + @Test + fun `Regular function return type does not use Kotlin reflection`() { + val methodParameter = returnMethodParameter("regularFun") + mockStatic(Class.forName("kotlin.reflect.jvm.ReflectJvmMapping"), Answer { + throw AssertionError("Kotlin reflection should not be used for regular functions") + }).use { + assertThat(methodParameter.parameterType).isEqualTo(Producer::class.java) + assertThat(methodParameter.genericParameterType.typeName) + .isEqualTo("org.springframework.core.Producer") + } + } + + @Test + fun `Regular function with Continuation parameter return type`() { + assertThat(returnParameterType("regularFunWithContinuation")).isEqualTo(Producer::class.java) + assertThat(returnGenericParameterTypeName("regularFunWithContinuation")).isEqualTo("org.springframework.core.Producer") + } + @Test fun `Parameter name for regular function`() { val methodParameter = returnMethodParameter("nullable", 0) @@ -186,6 +212,12 @@ class MethodParameterKotlinTests { @Suppress("unused", "unused_parameter") suspend fun suspendFun8(p1: String): Any? = TODO() + + @Suppress("unused", "unused_parameter") + fun regularFun(p1: String): Producer = TODO() + + @Suppress("unused", "unused_parameter") + fun regularFunWithContinuation(p1: String, continuation: Continuation): Producer = TODO() } interface Producer