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 6e0a13342f6..4cc2fdeefdb 100644 --- a/spring-core/src/test/kotlin/org/springframework/core/CoroutinesUtilsTests.kt +++ b/spring-core/src/test/kotlin/org/springframework/core/CoroutinesUtilsTests.kt @@ -230,7 +230,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 07a4b78790d..6dca729698e 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 @@ -316,7 +316,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); @@ -337,7 +337,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 920e29b5ef8..c06ea62a2aa 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 @@ -329,7 +329,7 @@ public class InvocableHandlerMethod extends HandlerMethod { private static final String COROUTINE_CONTEXT_ATTRIBUTE = "org.springframework.web.server.CoWebFilter.context"; @SuppressWarnings("DataFlowIssue") - public static @Nullable Object invokeFunction(Method method, Object target, Object[] args, boolean isSuspendingFunction, + public static @Nullable Object invokeFunction(Method method, Object target, @Nullable Object[] args, boolean isSuspendingFunction, ServerWebExchange exchange) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { if (isSuspendingFunction) { @@ -356,7 +356,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); @@ -378,7 +378,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 95a5df9cbbc..9e41a222399 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))