Groovy meta class interoperability with Java 8 - java

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)
}
}

Related

How can one access Kotlin's `backtickedFunctions` from Java?

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.

Call a Kotlin suspend function from Java

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.

Translate Kotlin interface to Java

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);

groovy / Java: Intercept method call from outside library

I have a simple groovy script in which I call a method named cron(String cronExpression) from ItemTriggerContext, like:
job('george') {
triggers {
cron('5 4 4 4 4')
}
}
I want to allow the cron method to be called only if some of my validations of the input String pass.
if(myValidationsOfCronExpr are ok) {
call the cron method with said parameter
}
else {
return null
}
This is why I need to intercept all calls to the cron() method from my project.
Already tried http://mrhaki.blogspot.com/2009/11/groovy-goodness-intercept-methods-with.html and https://www.webucator.com/how-to/how-use-the-intercept-cache-invoke-design-pattern-groovy.cfm but they seem applicable only on your own classes.
Any help is much appreciated!

Eclipse - `open call hierarchy` stop searching in lambda chain

Here is my sample java code:
public class Test {
public static void main(String[] args) {
methodDepth0(
()->
methodDepth1(
()->
methodDepth2()
)
);
}
static Object methodDepth2() {
return null;
}
interface MyIF {
void call();
}
static void methodDepth0(MyIF myIf){
myIf.call();
}
interface MyIF2 {
void call();
}
static void methodDepth1(MyIF2 myIf2){
myIf2.call();
}
}
When I open call hierarchy of method methodDepth2() from Eclipse(4.4),
open call hierarchy stop searching next caller:
What I expect is like opening call hierarchy of method methodDepth1() which show until the main method.
From what I can tell the lack of call hierarchy depth is due to (re)evaluation of code at runtime. It is explained in 15.27.4 Run-Time Evaluation of Lambda Expressions in the Java Language Specification.
At run time, evaluation of a lambda expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a lambda expression is distinct from execution of the lambda body.
As the second picture clearly shows, Eclipse is able to trace the call hierarchy through the method call myIf.call() inside methodDepth0. This is correct, because the (outer) lambda implements method MyIF.call().
The fact that the same pattern does not work in the next nesting level looks like a bug. Please consider filing a bug for JDT/UI. TIA.
Just note, that for lambdas implementing library types like Consumer<T>, the number of callers into accept(T) in a workspace may easily become unmanageable, similar to any call hierarchy through, e.g, Runnable.run() - but that doesn't question the general usefulness of call hierarchies through lambdas.

Categories

Resources