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 2df6a875fe7..ce8e761e401 100644 --- a/spring-core/src/test/kotlin/org/springframework/core/CoroutinesUtilsTests.kt +++ b/spring-core/src/test/kotlin/org/springframework/core/CoroutinesUtilsTests.kt @@ -238,7 +238,7 @@ class CoroutinesUtilsTests { } @Test - suspend fun invokeSuspendingFunctionWithNullableValueClassParameterWithNonnullObject() { + suspend fun invokeSuspendingFunctionWithNullableValueClassParameterAndNonNullParameter() { val method = CoroutinesUtilsTests::class.java.declaredMethods.first { it.name.startsWith("suspendingFunctionWithNullableValueClass") } val mono = CoroutinesUtils.invokeSuspendingFunction(method, this, ValueClass("foo"), null) as Mono Assertions.assertThat(mono.awaitSingleOrNull()).isEqualTo("foo") 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 f5c78bf597f..a0ce18884a9 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 @@ -321,7 +321,7 @@ public class InvocableHandlerMethod extends HandlerMethod { Object arg = args[index]; if (!(parameter.isOptional() && arg == null)) { KType type = parameter.getType(); - if (!(type.isMarkedNullable() && arg == null) && + if (!type.isMarkedNullable() && type.getClassifier() instanceof KClass kClass && KotlinDetector.isInlineClass(JvmClassMappingKt.getJavaClass(kClass))) { arg = box(kClass, arg); @@ -342,7 +342,7 @@ public class InvocableHandlerMethod extends HandlerMethod { private static Object box(KClass kClass, @Nullable Object arg) { KFunction constructor = Objects.requireNonNull(KClasses.getPrimaryConstructor(kClass)); KType type = constructor.getParameters().get(0).getType(); - if (!(type.isMarkedNullable() && arg == null) && + if (!type.isMarkedNullable() && type.getClassifier() instanceof KClass parameterClass && KotlinDetector.isInlineClass(JvmClassMappingKt.getJavaClass(parameterClass))) { arg = box(parameterClass, arg); 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 4b15b492193..b7da2b669f2 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 @@ -148,6 +148,13 @@ class InvocableHandlerMethodKotlinTests { Assertions.assertThatIllegalArgumentException().isThrownBy { invocable.invokeForRequest(request, null) } } + @Test + fun valueClassWithNullableAndNonNullParameter() { + composite.addResolver(StubArgumentResolver(LongValueClass::class.java, LongValueClass(1))) + val value = getInvocable(ValueClassHandler::valueClassWithNullable.javaMethod!!).invokeForRequest(request, null) + Assertions.assertThat(value).isEqualTo(1L) + } + @Test fun valueClassWithNullable() { composite.addResolver(StubArgumentResolver(LongValueClass::class.java, null)) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java index 3107bc0e384..f66c4b63870 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java @@ -360,7 +360,7 @@ public class InvocableHandlerMethod extends HandlerMethod { Object arg = args[index]; if (!(parameter.isOptional() && arg == null)) { KType type = parameter.getType(); - if (!(type.isMarkedNullable() && arg == null) && + if (!type.isMarkedNullable() && type.getClassifier() instanceof KClass kClass && KotlinDetector.isInlineClass(JvmClassMappingKt.getJavaClass(kClass))) { arg = box(kClass, arg); @@ -382,7 +382,7 @@ public class InvocableHandlerMethod extends HandlerMethod { private static Object box(KClass kClass, @Nullable Object arg) { KFunction constructor = Objects.requireNonNull(KClasses.getPrimaryConstructor(kClass)); KType type = constructor.getParameters().get(0).getType(); - if (!(type.isMarkedNullable() && arg == null) && + if (!type.isMarkedNullable() && type.getClassifier() instanceof KClass parameterClass && KotlinDetector.isInlineClass(JvmClassMappingKt.getJavaClass(parameterClass))) { arg = box(parameterClass, arg); diff --git a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/InvocableHandlerMethodKotlinTests.kt b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/InvocableHandlerMethodKotlinTests.kt index 2556e7b196b..338f06faec4 100644 --- a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/InvocableHandlerMethodKotlinTests.kt +++ b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/InvocableHandlerMethodKotlinTests.kt @@ -250,6 +250,14 @@ class InvocableHandlerMethodKotlinTests { assertExceptionThrown(result, IllegalArgumentException::class) } + @Test + fun valueClassWithNullableAndNonNullParameter() { + this.resolvers.add(stubResolver(LongValueClass(1), LongValueClass::class.java)) + val method = ValueClassController::valueClassWithNullable.javaMethod!! + val result = invoke(ValueClassController(), method) + assertHandlerResultValue(result, "1") + } + @Test fun valueClassWithNullable() { this.resolvers.add(stubResolver(null, LongValueClass::class.java))