Skip to content

Commit d6554c6

Browse files
committed
Recursively boxing Kotlin nested value classes
This commit is a follow-up to spring-projects#34592. It introduces recursive boxing of Kotlin nested value classes in CoroutinesUtils. Signed-off-by: Dmitry Sulman <[email protected]>
1 parent 551f6c0 commit d6554c6

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

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

+16-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.lang.reflect.InvocationTargetException;
2020
import java.lang.reflect.Method;
2121
import java.util.Map;
22+
import java.util.Objects;
2223

2324
import kotlin.Unit;
2425
import kotlin.coroutines.CoroutineContext;
@@ -131,11 +132,7 @@ public static Publisher<?> invokeSuspendingFunction(
131132
if (!(type.isMarkedNullable() && arg == null) &&
132133
type.getClassifier() instanceof KClass<?> kClass &&
133134
KotlinDetector.isInlineClass(JvmClassMappingKt.getJavaClass(kClass))) {
134-
KFunction<?> constructor = KClasses.getPrimaryConstructor(kClass);
135-
if (!KCallablesJvm.isAccessible(constructor)) {
136-
KCallablesJvm.setAccessible(constructor, true);
137-
}
138-
arg = constructor.call(arg);
135+
arg = box(kClass, arg);
139136
}
140137
argMap.put(parameter, arg);
141138
}
@@ -161,6 +158,20 @@ public static Publisher<?> invokeSuspendingFunction(
161158
return mono;
162159
}
163160

161+
private static Object box(KClass<?> kClass, @Nullable Object arg) {
162+
KFunction<?> constructor = Objects.requireNonNull(KClasses.getPrimaryConstructor(kClass));
163+
KType type = constructor.getParameters().get(0).getType();
164+
if (!(type.isMarkedNullable() && arg == null) &&
165+
type.getClassifier() instanceof KClass<?> parameterClass &&
166+
KotlinDetector.isInlineClass(JvmClassMappingKt.getJavaClass(parameterClass))) {
167+
arg = box(parameterClass, arg);
168+
}
169+
if (!KCallablesJvm.isAccessible(constructor)) {
170+
KCallablesJvm.setAccessible(constructor, true);
171+
}
172+
return constructor.call(arg);
173+
}
174+
164175
private static Flux<?> asFlux(Object flow) {
165176
return ReactorFlowKt.asFlux(((Flow<?>) flow));
166177
}

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

+17
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ class CoroutinesUtilsTests {
199199
}
200200
}
201201

202+
@Test
203+
fun invokeSuspendingFunctionWithNestedValueClassParameter() {
204+
val method = CoroutinesUtilsTests::class.java.declaredMethods.first { it.name.startsWith("suspendingFunctionWithNestedValueClassParameter") }
205+
val mono = CoroutinesUtils.invokeSuspendingFunction(method, this, "foo", null) as Mono
206+
runBlocking {
207+
Assertions.assertThat(mono.awaitSingle()).isEqualTo("foo")
208+
}
209+
}
210+
202211
@Test
203212
fun invokeSuspendingFunctionWithValueClassReturnValue() {
204213
val method = CoroutinesUtilsTests::class.java.declaredMethods.first { it.name.startsWith("suspendingFunctionWithValueClassReturnValue") }
@@ -328,6 +337,11 @@ class CoroutinesUtilsTests {
328337
return value.value
329338
}
330339

340+
suspend fun suspendingFunctionWithNestedValueClassParameter(value: NestedValueClass): String {
341+
delay(1)
342+
return value.value.value
343+
}
344+
331345
suspend fun suspendingFunctionWithValueClassReturnValue(): ValueClass {
332346
delay(1)
333347
return ValueClass("foo")
@@ -382,6 +396,9 @@ class CoroutinesUtilsTests {
382396
@JvmInline
383397
value class ValueClass(val value: String)
384398

399+
@JvmInline
400+
value class NestedValueClass(val value: ValueClass)
401+
385402
@JvmInline
386403
value class ValueClassWithInit(val value: String) {
387404
init {

0 commit comments

Comments
 (0)