Pass suspend lambda through java class

Is there a way to represent suspend function in java to pass it by Java to another Kotlin class?

My scenario is as follows - I have lambda with type defined as suspend () -> T in Kotlin function parameter. I need to call this function from Java function. The Java function have to receive the lambda itself. So first i create the Kotlin function like that:

class TestClass {
    fun <T : Any?> endKotlinFunction(lambda: suspend () -> T) {
        // do something
    }
}

Then i can create this Java function:

    public <T> void testJavaFunction(
            @NotNull Function1<? super Continuation<? super T>, ?> suspendFunction
    ) {
        TestClass testClass = new TestClass();
        testClass.endKotlinFunction(suspendFunction);
    }

And that’s fine for the compiler. So i can pass such type into the kotlin function. But i then try to call this java function from another kotlin code like that:

// i CAN do that:
testJavaFunction<Int> { 3 }

// i CANNOT do that:
val suspendLambda: suspend () -> Int = {
    2
}
testJavaFunction(suspendLambda)

Can you tell me why that last invocation does not work?

1 Like

Hi There,

I don’t have a precise answer for that, but my guess is that, because coroutine are basically a compiler trick, it needs some metadata that it cannot find on the Java class so it doesn’t recognize your Java class as being able to handle suspending functions, even though you have the correct signature.

I would not try to interop coroutine between kotlin and Java, it’s quite risky and you expose yourself to API changes introduced by the compiler if it decides to compile coroutine in another way.

I’m trying to hack my way through calling super function when overriding a member extension based on the response from: When overriding a member extension function, how to call superclass' implementation - #3 by norswap

I don’t have access to base class and i’m trying to override function what extends suspend lambda. It’s not critical for my operation in any means, but a puzzle to solve. If it’s too “hacky” then i won’t use it in production code. Still - i’m curious if that’s even possible

Casting is an option:

testJavaFunction(suspendLambda as Function1<Continuation<Int>, Any?>)

Passing around a wrapper instead of the lambda itself is another option:

data class EndKotlinFunctionLambda<T>(val delegate: suspend () -> T)

Kotlin and Java would have no trouble passing EndKotlinFunctionLambda back and forth.

2 Likes

Thanks. Wrapper around lambda is pretty “non-hacky” way to do this. And it works great