theapache64
theapache64

Reputation: 11754

How can I implement a Kotlin suspend method in a Java class?

I have a Kotlin interface

interface MyKotlinInterface {
    suspend fun mySuspendableMethod(): List<String>
}

then I created a Java class, and implemented MyKotlinInterface

public class MyJavaImpl implements MyKotlinInterface {

    @Nullable
    @Override
    public Object mySuspendableMethod(@NotNull Continuation<? super List<? extends String>> completion) {
        return null;
    }
}

the IDE shows no error, but when I compile am getting below error

error: MyJavaImpl is not abstract and does not override abstract method mySuspendableMethod(Continuation<? super List>) in MyKotlinInterface public class MyJavaImpl implements MyKotlinInterface {

So my questions are

  1. Is it possible to do this?
  2. If it's not possible, why IDE doesn't show any error? and why IDE converts the suspend method to Continuation param.

enter image description here

  1. If it's possible, why am I getting this error? and How can I fix it?

UPDATE:

I've changed

@NotNull Continuation<? super List<? extends String>> completion

to

@NotNull Continuation completion

and the compile-time error has gone.

Upvotes: 4

Views: 1044

Answers (1)

Alexey Soshin
Alexey Soshin

Reputation: 17721

Probably the best material on how suspend methods work in Kotlin behind the scenes is this file in the Kotlin repo: https://github.com/JetBrains/kotlin/pull/3709/files

As you've correctly noted, suspend keyword informs Kotlin compiler to transform the function into a statemachine, or, in maybe a bit more familiar terms, into a chain of callbacks.

To pass information between callbacks we need something to hold the result of the previous computation. This is the Continuation you see. The generic type, in your case List, is what the last call in the chain of callbacks should produce.

Since generics in JVM are a compile-time concept, by erasing them altogether you circumvented the issue, but not really solved it.

Why IDE doesn't alert regarding compilation issues?
AFAIK IntelliJ IDEA uses its own version of compiler in order to recognize the issues as they occur. This compiler is optimised for performance, and doesn't handle some edge cases.

How to solve the issue
Put a type on your interface:

interface MyKotlinInterface<T> {
    suspend fun mySuspendableMethod(): List<T>
}

Your Java class will have to change slightly:

public class MyJavaImpl<T> implements MyKotlinInterface<T> {

    @Nullable
    @Override
    public Object mySuspendableMethod(@NotNull Continuation<? super List<? extends T>> $completion) {
        return List.of("A", "B");
    }
}

But it will run and compile fine:

fun main() = runBlocking {
    val impl = MyJavaImpl<String>()

    println(impl.mySuspendableMethod())
}

Upvotes: 7

Related Questions