How to call Kotlin standard library function from Java? - java

Motivation:
In our Android project we have many verifications like str != null && !str.isEmpty(), so I decided to refactor them to a helper method.
For a moment I use following class as a helper:
public class StringUtil {
public static boolean isNullOrEmpty(#Nullable String str) {
return str == null || str.isEmpty();
}
}
Problem:
We already have a string's helper class, written in Kotlin (say, String.kt).
So, this is not clear to have two helpers (one in Java and one in Kotlin).
What I tried:
Naive approach to copy-past isNullOrEmpty() inside String.kt do not successed, because $reciever is null, so it crashed.
Secondly, I tried to used Kotlin native isNullOrEmpty() from kotlin.text (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/is-null-or-empty.html):
public inline fun CharSequence?.isNullOrEmpty(): Boolean
but I cannot figure out how to call it from Java. This page (https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html) do not provide any suggestions.
The problem is not about Accessing Kotlin extension functions from Java. My extension is perfectly visibly, but it crash because of null-receivier. As I mentioned below, question is more about accessing native library code, not my own extension.
Any help please ?

Some standard library functions, including this one, are marked with the #InlineOnly annotation, which makes them inaccessible from Java. For most other functions, you can access them exactly as described in the question linked as a duplicate.

After suggestion from #yole, I finally manage to convert code correctly to extension:
fun String?.isNullOrEmpty(): Boolean = (this == null || this.isEmpty())
So, problem was in defining extension as String, not as String? which leads to crash on $receiver. (Kotlin generates hidden not-null verifications when translating to Java, see https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#null-safety)
Alternatively, standard library functions marked with #InlineOnly can be accessed from Java via custom extension.
fun String?.isVoid(): Boolean = this.isNullOrEmpty()
My problem here was in misunderstanding of ?. I tried this first:
fun String?.isVoid(): Boolean? = this?.isNullOrEmpty()
As #Moria mentioned, please note behaviour of ? - b?.method will return b.method if b is not null, and null otherwise (https://kotlinlang.org/docs/reference/null-safety.html#safe-calls)

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.

How do you access Kotlin Library Sealed Classes as Error Handling in Java?

I've imported a library into my code that uses Sealed Classes as Error Handling. The Library is written in Kotlin, and my code is in Java. Other than this line, things have gone okay.
Code Example of what I've tried to even hold the Resource:
String dogID = "1234";
DogClient dogClient = new dogClient(); //params not important.
Resource<DogDto> dogDtoResource = dogClient.fetchDog(dogID); //Problem Statement
The dogClient.fetchDog(String id) method uses a sealed class called Resource where it uses data classes to handle errors. When I try to do the above, it says it cannot access Kotlin.coroutines.Continuation.
Resource in T code:
sealed class Resource<in T> {
data class Success<T>(val data: T) : Resource<T>()
data class Error(val exception: Throwable, val statusCode: Int?) : Resource<Any>()
}
I need to access the data on Success, and know when it throws an Error. The code in Kotlin would work something like this:
when(dogClient.fetchDog(dogId)) {
is Resource.Success -> result.data;
is Resource.Error -> throw new Exception();
I am completely lost on how to translate this to Java and haven't found any articles/documentation to help me.
it says it cannot access Kotlin.coroutines.Continuation
The problem is probably not the Resource sealed class then, but rather the fetchDog function you're trying to call is most likely a suspend function in Kotlin (using Kotlin coroutines).
You can check this other answer for this specific problem. It basically boils down to providing a non-suspend function from the Kotlin code, which you will be able to call from Java.
If you cannot modify the library, you can add a simple Kotlin file to your project to write this "bridge" function (but this means you'll need to setup Kotlin compilation in your project).

Python equivalence to org.apache.commons.configuration?

I want to port this Configuration.class object (from http://pastebin.com/dZeV27XB) into python and it seems hard to port the org.apache.commons.configuration object
In the java class, there were multiple functions that returns a Configuration.getString or Configuration.getInt e.g.
public int getDumpEndDir()
{
return this.config.getInt("wiki.dump.endDir");
}
public String getDocDir()
{
return this.config.getString("wiki.dump.docDir");
}
Any clue to what such function return?
Is there a python library similar to org.apache.commons?
Especially if there is one with the org.apache.commons.configuration library.
Is there a reason why this is in Java but not python?
You can use python's inbuild ConfigParser module which is very similar to Java's properties file loader. But here, the configuration parameters will be split section-wise.
check this,
https://docs.python.org/2/library/configparser.html
If it is an inmemory config structure, then you can simply use a dictionary object...

POI for XPages - using xwpfdocument

To help solve another problem I have, I'm testing the following code in the postGenerationProcess event of the POI Word widget:
var jce:writeXWPFDocument = new writeXWPFDocument();
var newString3 = jce.doSomething3(xwpfdocument);
print("newString3 = " + newString3);
doSomething3 is defined in a Java class contained in the .nsf.
public class writeXWPFDocument {
public String doSomething3(XWPFDocument xwpfdocument) {
return "DO SOMETHING - xwpfdocument";
}}
When I run this code, I get the error:
Java method 'doSomething3(org.apache.poi.xwpf.usermodel.XWPFDocument)'
on java class 'AZGPackage.writeXWPFDocument' not found
What could be causing this error?
#Knut Hermann - this is a test which relates to the other problem you have been helping me with.
Edit to make the correct answer easier to find:
I have used poi in a few applications. I've encountered similar problems twice: First, usually when I accidentally import a class with the same name from the wrong package (like lotus.local.domino.Database instead of lotus.domino.Database). The other time I encountered this (and the only time the package name was identical) was when I had poi in a plug-in that I had added to the build path and also had it installed by a poi extension library I had built. If you can't cast an object as itself, there is an issue with the ClassLoader, and I don't know what would cause that other than a class being listed twice.
SSJS seems to pass a different object type to the function. Try to change the class of the parameter to Object and for testing return the class name.
In a production code you could check with instanceof if the parameter has the right data type.
In General: consider using a facade pattern, so you keep your complex Java classes away from SSJS

Categories

Resources