Skip to content

Commit 4149d5c

Browse files
committed
Merge branch '6.1.x'
2 parents 89a10d5 + 85a781d commit 4149d5c

File tree

6 files changed

+85
-31
lines changed

6 files changed

+85
-31
lines changed

spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import java.lang.reflect.InvocationTargetException;
2020
import java.lang.reflect.Method;
21-
import java.lang.reflect.Modifier;
2221
import java.util.Map;
2322
import java.util.Objects;
2423

@@ -30,6 +29,7 @@
3029
import kotlin.reflect.KFunction;
3130
import kotlin.reflect.KParameter;
3231
import kotlin.reflect.full.KCallables;
32+
import kotlin.reflect.full.KClasses;
3333
import kotlin.reflect.jvm.KCallablesJvm;
3434
import kotlin.reflect.jvm.ReflectJvmMapping;
3535
import kotlinx.coroutines.BuildersKt;
@@ -46,7 +46,6 @@
4646

4747
import org.springframework.util.Assert;
4848
import org.springframework.util.CollectionUtils;
49-
import org.springframework.util.ReflectionUtils;
5049

5150
/**
5251
* Utilities for working with Kotlin Coroutines.
@@ -57,9 +56,6 @@
5756
*/
5857
public abstract class CoroutinesUtils {
5958

60-
private static final ReflectionUtils.MethodFilter boxImplFilter =
61-
(method -> method.isSynthetic() && Modifier.isStatic(method.getModifiers()) && method.getName().equals("box-impl"));
62-
6359
/**
6460
* Convert a {@link Deferred} instance to a {@link Mono}.
6561
*/
@@ -123,10 +119,7 @@ public static Publisher<?> invokeSuspendingFunction(CoroutineContext context, Me
123119
if (parameter.getType().getClassifier() instanceof KClass<?> kClass) {
124120
Class<?> javaClass = JvmClassMappingKt.getJavaClass(kClass);
125121
if (KotlinDetector.isInlineClass(javaClass)) {
126-
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
127-
Assert.state(methods.length == 1,
128-
"Unable to find a single box-impl synthetic static method in " + javaClass.getName());
129-
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
122+
argMap.put(parameter, KClasses.getPrimaryConstructor(kClass).call(args[index]));
130123
}
131124
else {
132125
argMap.put(parameter, args[index]);

spring-core/src/test/kotlin/org/springframework/core/CoroutinesUtilsTests.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,17 @@ class CoroutinesUtilsTests {
154154
}
155155
}
156156

157+
@Test
158+
fun invokeSuspendingFunctionWithValueClassWithInitParameter() {
159+
val method = CoroutinesUtilsTests::class.java.declaredMethods.first { it.name.startsWith("suspendingFunctionWithValueClassWithInit") }
160+
val mono = CoroutinesUtils.invokeSuspendingFunction(method, this, "", null) as Mono
161+
Assertions.assertThatIllegalArgumentException().isThrownBy {
162+
runBlocking {
163+
mono.awaitSingle()
164+
}
165+
}
166+
}
167+
157168
@Test
158169
fun invokeSuspendingFunctionWithExtension() {
159170
val method = CoroutinesUtilsTests::class.java.getDeclaredMethod("suspendingFunctionWithExtension",
@@ -206,6 +217,11 @@ class CoroutinesUtilsTests {
206217
return value.value
207218
}
208219

220+
suspend fun suspendingFunctionWithValueClassWithInit(value: ValueClassWithInit): String {
221+
delay(1)
222+
return value.value
223+
}
224+
209225
suspend fun CustomException.suspendingFunctionWithExtension(): String {
210226
delay(1)
211227
return "${this.message}"
@@ -219,6 +235,15 @@ class CoroutinesUtilsTests {
219235
@JvmInline
220236
value class ValueClass(val value: String)
221237

238+
@JvmInline
239+
value class ValueClassWithInit(val value: String) {
240+
init {
241+
if (value.isEmpty()) {
242+
throw IllegalArgumentException()
243+
}
244+
}
245+
}
246+
222247
class CustomException(message: String) : Throwable(message)
223248

224249
}

spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import java.lang.reflect.InvocationTargetException;
2020
import java.lang.reflect.Method;
21-
import java.lang.reflect.Modifier;
2221
import java.util.Arrays;
2322
import java.util.Map;
2423

@@ -27,6 +26,7 @@
2726
import kotlin.reflect.KClass;
2827
import kotlin.reflect.KFunction;
2928
import kotlin.reflect.KParameter;
29+
import kotlin.reflect.full.KClasses;
3030
import kotlin.reflect.jvm.KCallablesJvm;
3131
import kotlin.reflect.jvm.ReflectJvmMapping;
3232

@@ -37,10 +37,8 @@
3737
import org.springframework.core.MethodParameter;
3838
import org.springframework.core.ParameterNameDiscoverer;
3939
import org.springframework.lang.Nullable;
40-
import org.springframework.util.Assert;
4140
import org.springframework.util.CollectionUtils;
4241
import org.springframework.util.ObjectUtils;
43-
import org.springframework.util.ReflectionUtils;
4442
import org.springframework.validation.method.MethodValidator;
4543
import org.springframework.web.bind.WebDataBinder;
4644
import org.springframework.web.bind.support.SessionStatus;
@@ -64,9 +62,6 @@ public class InvocableHandlerMethod extends HandlerMethod {
6462

6563
private static final Class<?>[] EMPTY_GROUPS = new Class<?>[0];
6664

67-
private static final ReflectionUtils.MethodFilter boxImplFilter =
68-
(method -> method.isSynthetic() && Modifier.isStatic(method.getModifiers()) && method.getName().equals("box-impl"));
69-
7065

7166
private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
7267

@@ -322,10 +317,7 @@ public static Object invokeFunction(Method method, Object target, Object[] args)
322317
if (parameter.getType().getClassifier() instanceof KClass<?> kClass) {
323318
Class<?> javaClass = JvmClassMappingKt.getJavaClass(kClass);
324319
if (KotlinDetector.isInlineClass(javaClass)) {
325-
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
326-
Assert.state(methods.length == 1,
327-
"Unable to find a single box-impl synthetic static method in " + javaClass.getName());
328-
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
320+
argMap.put(parameter, KClasses.getPrimaryConstructor(kClass).call(args[index]));
329321
}
330322
else {
331323
argMap.put(parameter, args[index]);
@@ -342,6 +334,7 @@ public static Object invokeFunction(Method method, Object target, Object[] args)
342334
Object result = function.callBy(argMap);
343335
return (result == Unit.INSTANCE ? null : result);
344336
}
337+
345338
}
346339

347340
}

spring-web/src/test/kotlin/org/springframework/web/method/support/InvocableHandlerMethodKotlinTests.kt

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,24 @@ class InvocableHandlerMethodKotlinTests {
8787
@Test
8888
fun valueClass() {
8989
composite.addResolver(StubArgumentResolver(Long::class.java, 1L))
90-
val value = getInvocable(Handler::class.java, Long::class.java).invokeForRequest(request, null)
90+
val value = getInvocable(ValueClassHandler::class.java, Long::class.java).invokeForRequest(request, null)
9191
Assertions.assertThat(value).isEqualTo(1L)
9292
}
9393

9494
@Test
9595
fun valueClassDefaultValue() {
9696
composite.addResolver(StubArgumentResolver(Double::class.java))
97-
val value = getInvocable(Handler::class.java, Double::class.java).invokeForRequest(request, null)
97+
val value = getInvocable(ValueClassHandler::class.java, Double::class.java).invokeForRequest(request, null)
9898
Assertions.assertThat(value).isEqualTo(3.1)
9999
}
100100

101+
@Test
102+
fun valueClassWithInit() {
103+
composite.addResolver(StubArgumentResolver(String::class.java, ""))
104+
val invocable = getInvocable(ValueClassHandler::class.java, String::class.java)
105+
Assertions.assertThatIllegalArgumentException().isThrownBy { invocable.invokeForRequest(request, null) }
106+
}
107+
101108
@Test
102109
fun propertyAccessor() {
103110
val value = getInvocable(PropertyAccessorHandler::class.java).invokeForRequest(request, null)
@@ -153,11 +160,19 @@ class InvocableHandlerMethodKotlinTests {
153160
return null
154161
}
155162

163+
}
164+
165+
private class ValueClassHandler {
166+
156167
fun valueClass(limit: LongValueClass) =
157168
limit.value
158169

159170
fun valueClass(limit: DoubleValueClass = DoubleValueClass(3.1)) =
160171
limit.value
172+
173+
fun valueClassWithInit(valueClass: ValueClassWithInit) =
174+
valueClass
175+
161176
}
162177

163178
private class PropertyAccessorHandler {
@@ -183,6 +198,15 @@ class InvocableHandlerMethodKotlinTests {
183198
@JvmInline
184199
value class DoubleValueClass(val value: Double)
185200

201+
@JvmInline
202+
value class ValueClassWithInit(val value: String) {
203+
init {
204+
if (value.isEmpty()) {
205+
throw IllegalArgumentException()
206+
}
207+
}
208+
}
209+
186210
class CustomException(message: String) : Throwable(message)
187211

188212
}

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

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import java.lang.reflect.InvocationTargetException;
2020
import java.lang.reflect.Method;
21-
import java.lang.reflect.Modifier;
2221
import java.lang.reflect.ParameterizedType;
2322
import java.lang.reflect.Type;
2423
import java.util.ArrayList;
@@ -32,6 +31,7 @@
3231
import kotlin.reflect.KClass;
3332
import kotlin.reflect.KFunction;
3433
import kotlin.reflect.KParameter;
34+
import kotlin.reflect.full.KClasses;
3535
import kotlin.reflect.jvm.KCallablesJvm;
3636
import kotlin.reflect.jvm.ReflectJvmMapping;
3737
import reactor.core.publisher.Mono;
@@ -46,10 +46,8 @@
4646
import org.springframework.http.HttpStatusCode;
4747
import org.springframework.http.server.reactive.ServerHttpResponse;
4848
import org.springframework.lang.Nullable;
49-
import org.springframework.util.Assert;
5049
import org.springframework.util.CollectionUtils;
5150
import org.springframework.util.ObjectUtils;
52-
import org.springframework.util.ReflectionUtils;
5351
import org.springframework.validation.method.MethodValidator;
5452
import org.springframework.web.method.HandlerMethod;
5553
import org.springframework.web.reactive.BindingContext;
@@ -74,9 +72,6 @@ public class InvocableHandlerMethod extends HandlerMethod {
7472

7573
private static final Object NO_ARG_VALUE = new Object();
7674

77-
private static final ReflectionUtils.MethodFilter boxImplFilter =
78-
(method -> method.isSynthetic() && Modifier.isStatic(method.getModifiers()) && method.getName().equals("box-impl"));
79-
8075

8176
private final HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
8277

@@ -333,10 +328,7 @@ public static Object invokeFunction(Method method, Object target, Object[] args,
333328
if (parameter.getType().getClassifier() instanceof KClass<?> kClass) {
334329
Class<?> javaClass = JvmClassMappingKt.getJavaClass(kClass);
335330
if (KotlinDetector.isInlineClass(javaClass)) {
336-
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
337-
Assert.state(methods.length == 1,
338-
"Unable to find a single box-impl synthetic static method in " + javaClass.getName());
339-
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
331+
argMap.put(parameter, KClasses.getPrimaryConstructor(kClass).call(args[index]));
340332
}
341333
else {
342334
argMap.put(parameter, args[index]);
@@ -354,6 +346,7 @@ public static Object invokeFunction(Method method, Object target, Object[] args,
354346
return (result == Unit.INSTANCE ? null : result);
355347
}
356348
}
349+
357350
}
358351

359352
}

spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/InvocableHandlerMethodKotlinTests.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package org.springframework.web.reactive.result
1919
import io.mockk.every
2020
import io.mockk.mockk
2121
import kotlinx.coroutines.delay
22+
import org.assertj.core.api.Assertions
2223
import org.assertj.core.api.Assertions.assertThat
2324
import org.junit.jupiter.api.Test
2425
import org.springframework.core.MethodParameter
@@ -41,6 +42,7 @@ import reactor.core.publisher.Mono
4142
import reactor.test.StepVerifier
4243
import java.lang.reflect.Method
4344
import java.time.Duration
45+
import kotlin.reflect.KClass
4446
import kotlin.reflect.jvm.javaMethod
4547

4648
/**
@@ -197,6 +199,14 @@ class InvocableHandlerMethodKotlinTests {
197199
assertHandlerResultValue(result, "3.1")
198200
}
199201

202+
@Test
203+
fun valueClassWithInit() {
204+
this.resolvers.add(stubResolver("", String::class.java))
205+
val method = ValueClassController::valueClassWithInit.javaMethod!!
206+
val result = invoke(ValueClassController(), method)
207+
assertExceptionThrown(result, IllegalArgumentException::class)
208+
}
209+
200210
@Test
201211
fun propertyAccessor() {
202212
this.resolvers.add(stubResolver(null, String::class.java))
@@ -256,6 +266,10 @@ class InvocableHandlerMethodKotlinTests {
256266
}.verifyComplete()
257267
}
258268

269+
private fun assertExceptionThrown(mono: Mono<HandlerResult>, exceptionClass: KClass<out Throwable>) {
270+
StepVerifier.create(mono).verifyError(exceptionClass.java)
271+
}
272+
259273
class CoroutinesController {
260274

261275
suspend fun singleArg(q: String?): String {
@@ -320,6 +334,9 @@ class InvocableHandlerMethodKotlinTests {
320334
fun valueClassWithDefault(limit: DoubleValueClass = DoubleValueClass(3.1)) =
321335
"${limit.value}"
322336

337+
fun valueClassWithInit(valueClass: ValueClassWithInit) =
338+
valueClass
339+
323340
}
324341

325342
class PropertyAccessorController {
@@ -346,5 +363,14 @@ class InvocableHandlerMethodKotlinTests {
346363
@JvmInline
347364
value class DoubleValueClass(val value: Double)
348365

366+
@JvmInline
367+
value class ValueClassWithInit(val value: String) {
368+
init {
369+
if (value.isEmpty()) {
370+
throw IllegalArgumentException()
371+
}
372+
}
373+
}
374+
349375
class CustomException(message: String) : Throwable(message)
350376
}

0 commit comments

Comments
 (0)