paul
paul

Reputation: 13481

implement onComplete Scala Future in Kotlin

I´m invoking from Kotlin a Scala class that return a Future, I can make an Await of that future

private fun scalaFutureInKotlin() {
    val future: Future<String> = Future.successful("Hello world from Scala")
    val result: String? = Await.result(future, Duration.apply(10, TimeUnit.SECONDS))
    println(result)
}

But what I really want is to being able to implement the onComplete callback and pass the value into a Kotlin Channel or Flow to being used in another coroutine, so then I dont block any thread.

Any idea how to implement a onComplete function of a Scala Future in Kotlin?

Upvotes: 2

Views: 460

Answers (1)

Animesh Sahu
Animesh Sahu

Reputation: 8106

From the answer:

Starting Scala 2.13, the standard library includes scala.jdk.FutureConverters which provides Scala to Java Future conversions (and vice versa):

import scala.jdk.javaapi.FutureConverters
import java.util.concurrent.CompletionStage

val javaFuture: CompletionStage<Int> = FutureConverters.asJava(scalaFuture)

Once you get CompletionStage, you can interop with it in Kotlin with following options:

  1. As kotlinx.coroutines offers CompletionStage.await function defined on that so you can asynchronously wait for the completion of the future:
// Dependencies:
// implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
// implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.3.9"
import kotlinx.coroutines.future.*
import java.util.concurrent.*
import scala.jdk.javaapi.FutureConverters

private suspend fun scalaFutureInKotlin() {
    val future: Future<String> = Future.successful("Hello world from Scala")
    val javaFuture: CompletionStage<Int> = FutureConverters.asJava(future)
    val result: String? = javaFuture.await()  // asynchronous await, function resumes when result is available, callable by suspend function only
    println(result)
}

// Examples:
suspend fun main() {
    scalaFutureInKotlin()
}

// or for calling from coroutine when not inside suspendable block
fun main() {
    val scope = CoroutineScope(Dispatchers.Default)
    scope.launch { scalaFutureInKotlin() }  // call from inside coroutine
}
  1. Directly add listeners to CompletionStage:
import java.util.concurrent.*
import scala.jdk.javaapi.FutureConverters

private fun scalaFutureInKotlin() {
    val future: Future<String> = Future.successful("Hello world from Scala")
    val javaFuture: CompletionStage<Int> = FutureConverters.asJava(future)
    javaFuture.thenAccept { result ->  // use thenApply if you want to return sth and chain the calls
        println(result)
    }
}

Upvotes: 3

Related Questions