There is an coroutine block that can runs suspend functions.
But I call the function by invoke
via reflection. This is java style invocation, apparently a simple call will not work.
Are there ways to run reflected method asynchronously? How to await this method?
import kotlin.coroutines.experimental.*
class TestClass(val InString: String) {
suspend fun printString() {
println(InString)
}
}
fun launch(context: CoroutineContext, block: suspend () -> Unit) =
block.startCoroutine(StandaloneCoroutine(context))
private class StandaloneCoroutine(override val context: CoroutineContext): Continuation<Unit> {
override fun resume(value: Unit) {}
override fun resumeWithException(exception: Throwable) {
val currentThread = Thread.currentThread()
currentThread.uncaughtExceptionHandler.uncaughtException(currentThread, exception)
}
}
fun main(args: Array<String>) {
launch(EmptyCoroutineContext) {
val a = TestClass("TestString");
for (method in a.javaClass.methods) {
if (method.name == "printString")
method.invoke(a) // Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
}
}
}
Update
Since Kotlin 1.3 reflection natively supports calling suspending functions via
KFunction.callSuspend
andKFunction.callSuspendBy
, so the above workaround is no longer needed.Original Answer
Every
suspend
method in Kotlin is represented on JVM via CPS transformation that is explained in the coroutines design document. Java reflection is not aware about it and Kotlin reflection does not currently provide convenient means to perform invocation of suspending function either.You'll have to do invocation with CPS transformation yourself via helper function. I'd suggest to implement the following helper for this purpose:
Now if you replace
invoke
withinvokeSuspend
in your code, then it is going to work just like expected.