Unwrap Kotlin inline value classes return values
The result returned by Kotlin reflective invocation of a function returning an inline value class is wrapped, which makes sense from Kotlin POV but from a JVM perspective the associated value and type should be unwrapped to be consistent with what would happen with a reflective invocation done by Java. This commit unwraps such result. Closes gh-33026
This commit is contained in:
@@ -44,6 +44,7 @@ import kotlinx.coroutines.reactor.ReactorFlowKt;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.SynchronousSink;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -145,7 +146,7 @@ public abstract class CoroutinesUtils {
|
||||
}
|
||||
return KCallables.callSuspendBy(function, argMap, continuation);
|
||||
})
|
||||
.filter(result -> result != Unit.INSTANCE)
|
||||
.handle(CoroutinesUtils::handleResult)
|
||||
.onErrorMap(InvocationTargetException.class, InvocationTargetException::getTargetException);
|
||||
|
||||
KType returnType = function.getReturnType();
|
||||
@@ -165,4 +166,22 @@ public abstract class CoroutinesUtils {
|
||||
return ReactorFlowKt.asFlux(((Flow<?>) flow));
|
||||
}
|
||||
|
||||
private static void handleResult(Object result, SynchronousSink<Object> sink) {
|
||||
if (result == Unit.INSTANCE) {
|
||||
sink.complete();
|
||||
}
|
||||
else if (KotlinDetector.isInlineClass(result.getClass())) {
|
||||
try {
|
||||
sink.next(result.getClass().getDeclaredMethod("unbox-impl").invoke(result));
|
||||
sink.complete();
|
||||
}
|
||||
catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
|
||||
sink.error(ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sink.next(result);
|
||||
sink.complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +199,15 @@ class CoroutinesUtilsTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun invokeSuspendingFunctionWithValueClassReturnValue() {
|
||||
val method = CoroutinesUtilsTests::class.java.declaredMethods.first { it.name.startsWith("suspendingFunctionWithValueClassReturnValue") }
|
||||
val mono = CoroutinesUtils.invokeSuspendingFunction(method, this, null) as Mono
|
||||
runBlocking {
|
||||
Assertions.assertThat(mono.awaitSingle()).isEqualTo("foo")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun invokeSuspendingFunctionWithValueClassWithInitParameter() {
|
||||
val method = CoroutinesUtilsTests::class.java.declaredMethods.first { it.name.startsWith("suspendingFunctionWithValueClassWithInit") }
|
||||
@@ -310,6 +319,11 @@ class CoroutinesUtilsTests {
|
||||
return value.value
|
||||
}
|
||||
|
||||
suspend fun suspendingFunctionWithValueClassReturnValue(): ValueClass {
|
||||
delay(1)
|
||||
return ValueClass("foo")
|
||||
}
|
||||
|
||||
suspend fun suspendingFunctionWithValueClassWithInit(value: ValueClassWithInit): String {
|
||||
delay(1)
|
||||
return value.value
|
||||
|
||||
Reference in New Issue
Block a user