I have a Kotlin library that I'm attempting to call from Java. I haven't worked with Kotlin before.
The Kotlin library function is as follows:
suspend fun decode(jwt: String): UsefulThing {
// does a bunch of stuff, removed for brevity.
return otherthing.getUsefulThing(jwt)
}
How can I call this from Java? So far I've tried:
Continuation<UsefulThing> continuation = new Continuation<>() {
#NotNull
#Override
public CoroutineContext getContext() {
return EmptyCoroutineContext.INSTANCE;
}
#Override
public void resumeWith(#NotNull Object o) {
System.out.println("Result of decode is " + o);
}
};
// Call decode with the parameter and continuation.
Object result = UsefulThingKt.decode(JWT, continuation);
// result is COROUTINE_SUSPENDED
I never see any console output. Looks like the continuation is never called, or it's run in another context. I've pored over other answers and coroutines seem to have gone through a number of iterations - I can't find an explanation that really makes sense to me.
I should note that I'm running on Java 11.
How can I simply call the kotlin function?
I suggest to not even try. Suspend functions were never meant for Java interop.
Instead, convert it on the Kotlin side to something that Java understands - to CompletableFuture:
fun decodeAsync(jwt: String): CompletableFuture<UsefulThing> = GlobalScope.future { decode(jwt) }
We can freely mix Java and Kotlin code in a single module, so you can create such wrapper inside your project.
Depending on your case you could use GlobalScope (in Java we don't have structured concurrency) or you could create a custom CoroutineScope and handle its lifecycle manually.
Related
TL;DR:
Is there a simple syntax in java to access kotlins backticked functions such as fun `if`(){...}
Long Version:
In Kotlin, one may write the following class.
class ShapeShifter {
fun speak() { println("Hello fellow hooman") }
fun `speakLikeA🐱`() { println("Meow") }
fun `speakLikeA🐶`() { println("Bwoof !") }
fun `speakLikeA🐧`() { println("NOOT NOOT ! (you would'nt have so much problems with linux ...)") }
}
And this would work just fine ... All your fellow kotlin-ers would be able to speak to you in all your forms like so :
ShapeShifter().`speakLikeA🐶`() // would work like a charm
but when interracting with java-ist muggles your secret identity would be safe because I am pretty sure java-ists can only interract with you like so :
new ShapeShifter().speak()
My question is :
Is there a way for java commoners to reach to your backticked kotlin functions WITHOUT resorting to using black magics such as introspection/reflection like so :
var tomJedusor = new ShapeShifter();
ShapeShifter.class.getDeclaredMethod("speakLikeA🐍").invoke(tomJedusor); //the forbidden arcane spell banned from Konoha ...
#JvmName annotation lets you define jvm name for that method.
#JvmName("speakLikeACat")
fun `speakLikeA🐱`() { println("Meow") }
#JvmName("speakLikeADog")
fun `speak like a 🐶`() { println("Bwoof") }
Now, you can access that method from java code.
// .java
shapeShifter.speakLikeACat();
shapeShifter.speakLikeADog();
Accesing backticked kotlin methods, fields from java is only possible with some jvm annotations. Kotlin compiler must obey java language specifications to generate the byte code. Actually java language specification does not allow this feature.
I decided to write this question as there are no best practices yet available on this topic.
We are providing an Android SDK that implements asynchronous calls with Coroutines.
I want our clients to consume suspending functions and Flow from Java or standard Kotlin.
I am aware that there is kotlinx-coroutines-jdk8 but this can only be used from Android Api level 24 and our SDK supports Android down to Api level 21. So this is not an option at the moment.
My idea was to bridge the worlds of Java (or standard Kotlin) and Coroutines by providing a simply callback API.
I would like to know if my following approach is a good solution. Are there any downsides or dangers? What alternative would I have to make clients call Coroutines functions without forcing them to use Coroutines themself?
Now let's get started. First I show you some interfaces and helper function I can use later to map suspend functions and Flow.
Cancellation
I need to ensure that Coroutine can be cancelled from Java. So I created a Cancelable interface.
interface Cancelable {
fun cancel()
}
This interface gets implemented by CancelableJob that contains and hides the Job to be canceled.
class CancelableJob(private val job: Job) : Cancelable {
override fun cancel() {
job.cancel()
}
}
Launch a new Coroutine
Every time a clients calls a function I will launch a new Coroutine. For this I create a top level function launchCancelableJob. This function gets a suspending block and returns a Cancelable.
The Coroutine will be launched on Dispatchers.Main, so all results can be observed on UI Thread, together with a SupervisedJob.
fun launchCancelableJob(block: suspend () -> Unit): Cancelable {
val job: Job = CoroutineScope(Dispatchers.Main + SupervisorJob()).launch {
block.invoke()
}
return CancelableJob(job)
}
Bridge Suspend Function and Flow to World of Java
Now it's time to provide a bridge function that is not a suspend function itself, but launches a Coroutine and returns a Cancelable. From a given callback the result will be delivered to the caller.
// normal coroutine api
suspend fun generateQrCode(): QrCode
// bridge function - to be called from Java
fun generateQrCode(callback: (QrCode) -> Unit): Cancelable {
return launchCancelableJob {
val qrCode: QrCode = generateQrCode()
callback(qrcode)
}
}
The same I could do with Flow.
// normal coroutine api
fun generateQrCodes(): Flow<QrCode>
// bridge function - to be called from Java
fun generateQrCodes(callback: (QrCode) -> Unit): Cancelable {
return launchCancelableJob {
generateQrCodes().collect { qrCode: QrCode ->
callback(qrcode)
}
}
}
Usage
The above function could be called from Java like:
Cancelable cancelable = generateQrCode(new Function1<QrCode, Unit>() {
#Override
public Unit invoke(QrCode qrCode) {
// show the qrCode
return Unit.INSTANCE;
}
});
And if no longer needed it could be canceled like:
cancelable.cancel();
This is my approach. I'm really looking forward to your opinions or perhaps better solutions. Thank you for reading, I know this was a very long question.
I am using this library which is a CalendarView. https://github.com/kizitonwose/CalendarView
In the sample code there is the following code which attaches a Scroll Listener to the CalendarView
calendarView.monthScrollListener = { // etc}
I am unsure how to translate this to Java, I try the following but the "MonthScrollListener" class is nowhere to be found, its like it want some other type but I cannot find the type. Everything else has worked so far when translating the Kotlin to Java but I cannot see how this might work
mBinding.calendarView.setMonthScrollListener(new MonthScrollListener(){ // etc});
What should I pass into the setMonthScrollListener() method?
Edit: when I "ctrl click" on the setMonthScrollListener() it takes me into the CalendarView class and there is the following line:
public final var monthScrollListener: com.kizitonwose.calendarview.ui.MonthScrollListener? /* = ((com.kizitonwose.calendarview.model.CalendarMonth) -> kotlin.Unit)? */ /* compiled code */
So I try explicitly referencing the MonthScrollListener but everything is resolved up to the MonthScrollListener, which isnt available...
typealias is not visible in Java, but given the example you're talking about is:
typealias MonthScrollListener = (CalendarMonth) -> Unit
Then in Java world it should be similar to single method interface like (more about it below):
import kotlin.Unit;
interface MonthScrollListener {
Unit whatever(CalendarMonth cm);
}
It could be void because this is what Unit means in Kotlin but you know - life.
So passing Lambda in that method which expects listener should look like:
whatever.setMonthScrollListener((CalendarMonth cm) -> {
// w00t
return kotlin.Unit.INSTANCE;
});
I've basically ended up writing the same approach as suggested by #MishaAkopov
Edit (after reading about it):
But what type is it actually? It appears that Kotlin standard library has a bunch of interfaces like Function0<R> and Function2<P1,P2,R> that have one method invoke. So if you'd need to use above Kotlin code in previous Java versions it would instead look like:
Function1<CalendarMonth, Unit> listener = new Function1<CalendarMonth, Unit>() {
#Override
public Unit invoke(CalendarMonth cm) {
// Do something with calendar month
return kotlin.Unit.INSTANCE;
}
}
whatever.setMonthScrollListener(listener);
I have a bunch of tasks that need to be performed before and after a method call.
My approach is to use annotation processing, and a custom annotation to do this.
#BeforeSomething(task = 'something')
#AfterSomething(task = 'something else')
fun something(blah: Something) {
Log.d("Something", "Something $blah")
}
So that the end output from just running this method could be like:
Before task, options 'something'
Something blahblahblah
After task, options 'somethign else'
Whats the best way to do this? I've looked into AspectJ but thats not working with Kotlin. I've also looked into Lombok, but I can't use that library.
You could provide the tasks via a higher order function - a wrapper function:
inline fun <T> wrapFunction(before: Task? = null, after: Task? = null, body: () -> T): T =
try {
before?.run()
body()
} finally {
after?.run()
}
fun something(blah: String) = wrapFunction(before = BeforeTask, after = AfterTask) {
println("Something")
}
This requires no extra tools and is refactoring safe.
If you not provide a before or after parameter the Kotlin compiler will not even generate the null-check, due to dead code elimination (abstractions without costs).
Introduction:
I'm developing a Java library called awaitility which also has a Groovy extension. Prior to Java 8 you could use the library like this:
// Syntax example with the Groovy extension
await().atMost(500, MILLISECONDS).until { asynch.getValue() == 2 }
The Groovy extension makes use of a class called ConditionFactory defined in the Java API. But this API doesn't define an until method that takes an instance of a Groovy Closure. So instead the method is added with a meta class like this:
ConditionFactory.metaClass.until { Closure closure ->
delegate.until(new Callable<Boolean>() {
Boolean call() {
return closure.call();
}
});
}
As you can see it simply delegates to the until method in the Java API that takes an instance of Callable<Boolean>.
The Problem:
The Java API also contains an overloaded method of until that takes a Runnable as its parameter. When the Groovy extension is used with Java 8 the Runnable version of the until method is called instead of the until method taking Closure as an argument (the method defined using metaClass). It seems like the metaClass is no longer kicking in. Why is this? Is there a work-around?
Actually I don't think this has anything to do with Java 8 (sorry for the confusion). A work-around to my problem looked like this:
def originalMethod = ConditionFactory.metaClass.getMetaMethod("until", Runnable.class)
ConditionFactory.metaClass.until { Runnable runnable ->
if (runnable instanceof Closure) {
delegate.until(new Callable<Boolean>() {
Boolean call() {
return (runnable as Closure).call();
}
});
} else {
originalMethod.invoke(delegate, runnable)
}
}