Skip to content

Commit bdcd10e

Browse files
committed
Merge branch '6.1.x'
2 parents 861ef88 + 227e75d commit bdcd10e

File tree

4 files changed

+78
-16
lines changed

4 files changed

+78
-16
lines changed

spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import kotlin.reflect.KParameter;
2727
import kotlin.reflect.jvm.ReflectJvmMapping;
2828

29+
import org.springframework.beans.BeanUtils;
2930
import org.springframework.beans.ConversionNotSupportedException;
3031
import org.springframework.beans.TypeMismatchException;
3132
import org.springframework.beans.factory.config.BeanExpressionContext;
@@ -281,8 +282,12 @@ private static Object convertIfNecessary(
281282
NamedValueInfo namedValueInfo, @Nullable Object arg) throws Exception {
282283

283284
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
285+
Class<?> parameterType = parameter.getParameterType();
286+
if (KotlinDetector.isKotlinPresent() && KotlinDetector.isInlineClass(parameterType)) {
287+
parameterType = BeanUtils.findPrimaryConstructor(parameterType).getParameterTypes()[0];
288+
}
284289
try {
285-
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
290+
arg = binder.convertIfNecessary(arg, parameterType, parameter);
286291
}
287292
catch (ConversionNotSupportedException ex) {
288293
throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),

spring-web/src/test/kotlin/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverKotlinTests.kt

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@ import org.springframework.core.annotation.SynthesizingMethodParameter
2525
import org.springframework.core.convert.support.DefaultConversionService
2626
import org.springframework.http.HttpMethod
2727
import org.springframework.http.MediaType
28-
import org.springframework.util.ReflectionUtils
2928
import org.springframework.web.bind.MissingServletRequestParameterException
3029
import org.springframework.web.bind.annotation.RequestParam
3130
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer
@@ -39,6 +38,7 @@ import org.springframework.web.testfixture.servlet.MockHttpServletRequest
3938
import org.springframework.web.testfixture.servlet.MockHttpServletResponse
4039
import org.springframework.web.testfixture.servlet.MockMultipartFile
4140
import org.springframework.web.testfixture.servlet.MockMultipartHttpServletRequest
41+
import kotlin.reflect.jvm.javaMethod
4242

4343
/**
4444
* Kotlin test fixture for [RequestParamMethodArgumentResolver].
@@ -70,6 +70,9 @@ class RequestParamMethodArgumentResolverKotlinTests {
7070
lateinit var nonNullableMultipartParamRequired: MethodParameter
7171
lateinit var nonNullableMultipartParamNotRequired: MethodParameter
7272

73+
lateinit var nonNullableValueClassParam: MethodParameter
74+
lateinit var nullableValueClassParam: MethodParameter
75+
7376

7477
@BeforeEach
7578
fun setup() {
@@ -80,10 +83,8 @@ class RequestParamMethodArgumentResolverKotlinTests {
8083
binderFactory = DefaultDataBinderFactory(initializer)
8184
webRequest = ServletWebRequest(request, MockHttpServletResponse())
8285

83-
val method = ReflectionUtils.findMethod(javaClass, "handle",
84-
String::class.java, String::class.java, String::class.java, String::class.java,
85-
Boolean::class.java, Boolean::class.java, Int::class.java, Int::class.java, String::class.java, String::class.java,
86-
MultipartFile::class.java, MultipartFile::class.java, MultipartFile::class.java, MultipartFile::class.java)!!
86+
val method = RequestParamMethodArgumentResolverKotlinTests::handle.javaMethod!!
87+
val valueClassMethod = RequestParamMethodArgumentResolverKotlinTests::handleValueClass.javaMethod!!
8788

8889
nullableParamRequired = SynthesizingMethodParameter(method, 0)
8990
nullableParamNotRequired = SynthesizingMethodParameter(method, 1)
@@ -101,6 +102,9 @@ class RequestParamMethodArgumentResolverKotlinTests {
101102
nullableMultipartParamNotRequired = SynthesizingMethodParameter(method, 11)
102103
nonNullableMultipartParamRequired = SynthesizingMethodParameter(method, 12)
103104
nonNullableMultipartParamNotRequired = SynthesizingMethodParameter(method, 13)
105+
106+
nonNullableValueClassParam = SynthesizingMethodParameter(valueClassMethod, 0)
107+
nullableValueClassParam = SynthesizingMethodParameter(valueClassMethod, 1)
104108
}
105109

106110
@Test
@@ -317,6 +321,20 @@ class RequestParamMethodArgumentResolverKotlinTests {
317321
}
318322
}
319323

324+
@Test
325+
fun resolveNonNullableValueClass() {
326+
request.addParameter("value", "123")
327+
var result = resolver.resolveArgument(nonNullableValueClassParam, null, webRequest, binderFactory)
328+
assertThat(result).isEqualTo(123)
329+
}
330+
331+
@Test
332+
fun resolveNullableValueClass() {
333+
request.addParameter("value", "123")
334+
var result = resolver.resolveArgument(nullableValueClassParam, null, webRequest, binderFactory)
335+
assertThat(result).isEqualTo(123)
336+
}
337+
320338

321339
@Suppress("unused_parameter")
322340
fun handle(
@@ -338,5 +356,13 @@ class RequestParamMethodArgumentResolverKotlinTests {
338356
@RequestParam("mfile", required = false) nonNullableMultipartParamNotRequired: MultipartFile) {
339357
}
340358

359+
@Suppress("unused_parameter")
360+
fun handleValueClass(
361+
@RequestParam("value") nonNullable: ValueClass,
362+
@RequestParam("value") nullable: ValueClass?) {
363+
}
364+
365+
@JvmInline value class ValueClass(val value: Int)
366+
341367
}
342368

spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import kotlin.reflect.jvm.ReflectJvmMapping;
2727
import reactor.core.publisher.Mono;
2828

29+
import org.springframework.beans.BeanUtils;
2930
import org.springframework.beans.ConversionNotSupportedException;
3031
import org.springframework.beans.TypeMismatchException;
3132
import org.springframework.beans.factory.config.BeanExpressionContext;
@@ -197,8 +198,12 @@ private Object applyConversion(@Nullable Object value, NamedValueInfo namedValue
197198
BindingContext bindingContext, ServerWebExchange exchange) {
198199

199200
WebDataBinder binder = bindingContext.createDataBinder(exchange, namedValueInfo.name);
201+
Class<?> parameterType = parameter.getParameterType();
202+
if (KotlinDetector.isKotlinPresent() && KotlinDetector.isInlineClass(parameterType)) {
203+
parameterType = BeanUtils.findPrimaryConstructor(parameterType).getParameterTypes()[0];
204+
}
200205
try {
201-
value = binder.convertIfNecessary(value, parameter.getParameterType(), parameter);
206+
value = binder.convertIfNecessary(value, parameterType, parameter);
202207
}
203208
catch (ConversionNotSupportedException ex) {
204209
throw new ServerErrorException("Conversion not supported.", parameter, ex);

spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverKotlinTests.kt

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,14 +22,14 @@ import org.springframework.core.MethodParameter
2222
import org.springframework.core.ReactiveAdapterRegistry
2323
import org.springframework.core.annotation.SynthesizingMethodParameter
2424
import org.springframework.format.support.DefaultFormattingConversionService
25-
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest
26-
import org.springframework.web.testfixture.server.MockServerWebExchange
27-
import org.springframework.util.ReflectionUtils
2825
import org.springframework.web.bind.annotation.RequestParam
2926
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer
3027
import org.springframework.web.reactive.BindingContext
3128
import org.springframework.web.server.ServerWebInputException
29+
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest
30+
import org.springframework.web.testfixture.server.MockServerWebExchange
3231
import reactor.test.StepVerifier
32+
import kotlin.reflect.jvm.javaMethod
3333

3434
/**
3535
* Kotlin test fixture for [RequestParamMethodArgumentResolver].
@@ -53,6 +53,9 @@ class RequestParamMethodArgumentResolverKotlinTests {
5353
lateinit var defaultValueStringParamRequired: MethodParameter
5454
lateinit var defaultValueStringParamNotRequired: MethodParameter
5555

56+
lateinit var nonNullableValueClassParam: MethodParameter
57+
lateinit var nullableValueClassParam: MethodParameter
58+
5659

5760
@BeforeEach
5861
fun setup() {
@@ -61,10 +64,8 @@ class RequestParamMethodArgumentResolverKotlinTests {
6164
initializer.conversionService = DefaultFormattingConversionService()
6265
bindingContext = BindingContext(initializer)
6366

64-
val method = ReflectionUtils.findMethod(javaClass, "handle",
65-
String::class.java, String::class.java, String::class.java, String::class.java,
66-
Boolean::class.java, Boolean::class.java, Int::class.java, Int::class.java,
67-
String::class.java, String::class.java)!!
67+
val method = RequestParamMethodArgumentResolverKotlinTests::handle.javaMethod!!
68+
val valueClassMethod = RequestParamMethodArgumentResolverKotlinTests::handleValueClass.javaMethod!!
6869

6970
nullableParamRequired = SynthesizingMethodParameter(method, 0)
7071
nullableParamNotRequired = SynthesizingMethodParameter(method, 1)
@@ -77,6 +78,9 @@ class RequestParamMethodArgumentResolverKotlinTests {
7778
defaultValueIntParamNotRequired = SynthesizingMethodParameter(method, 7)
7879
defaultValueStringParamRequired = SynthesizingMethodParameter(method, 8)
7980
defaultValueStringParamNotRequired = SynthesizingMethodParameter(method, 9)
81+
82+
nonNullableValueClassParam = SynthesizingMethodParameter(valueClassMethod, 0)
83+
nullableValueClassParam = SynthesizingMethodParameter(valueClassMethod, 1)
8084
}
8185

8286
@Test
@@ -219,6 +223,20 @@ class RequestParamMethodArgumentResolverKotlinTests {
219223
StepVerifier.create(result).expectComplete().verify()
220224
}
221225

226+
@Test
227+
fun resolveNonNullableValueClass() {
228+
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/path?value=123"))
229+
var result = resolver.resolveArgument(nonNullableValueClassParam, bindingContext, exchange)
230+
StepVerifier.create(result).expectNext(123).expectComplete().verify()
231+
}
232+
233+
@Test
234+
fun resolveNullableValueClass() {
235+
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/path?value=123"))
236+
var result = resolver.resolveArgument(nullableValueClassParam, bindingContext, exchange)
237+
StepVerifier.create(result).expectNext(123).expectComplete().verify()
238+
}
239+
222240

223241
@Suppress("unused_parameter")
224242
fun handle(
@@ -235,5 +253,13 @@ class RequestParamMethodArgumentResolverKotlinTests {
235253
@RequestParam("value", required = false) withDefaultValueStringParamNotRequired: String = "default") {
236254
}
237255

256+
@Suppress("unused_parameter")
257+
fun handleValueClass(
258+
@RequestParam("value") nonNullable: ValueClass,
259+
@RequestParam("value") nullable: ValueClass?) {
260+
}
261+
262+
@JvmInline value class ValueClass(val value: Int)
263+
238264
}
239265

0 commit comments

Comments
 (0)