Java Calling — Kotlin

Call Kotlin Code from Java

Nino Handler
ProAndroidDev

--

This blog post is all about calling Kotlin — from Java code. Java, even for Kotlin enthusiasts, will live longer than expected in a dark place somewhere deep in our source control. We will have to deal with it and probably continue working with a legacy Java codebase.

photo taken by Axl Jansen — More images and contact: www.axljansen.com — altered by the author, license

The good thing, you might already know it: You can use Kotlin and Java side-by-side as they both are Java Virtual Machine (JVM) languages and compile to the same byte code. You can always validate this by going toTools -> Kotlin -> Show Kotlin Bytecode in Intellij. So if you would like to enhance your legacy project with some Kotlin code, if you would like to bring some color to this old grey Java world, if you want to let a rainbow rise above the old stinking boilerplate dungheap - it is super easily done by just integrating Kotlin into your existing java project — YEAY! Do it!

BUT: When calling your “concise”, “safe”, “interoperable”, “tool-friendly” code from a Java class you will soon realize some drawbacks.

Interoperability Problems and Solutions

I. @file:JvmName / @file:JvmMultifileClass

Let’s assume you created an extension function for a class named TrafficLight. You don’t always want to check if you have to stop at the traffic light or if you can drive. So you wrote this:

Problem: When calling it from Java you would have to type TrafficLightExtensionsKt.isDrive(trafficLight) .

This works but it is not what you as a (Java) developer would expect — you would probably look for a utility class instead.

Solution: If you make use of the annotation @file:JvmName the problem is solved:

With this annotation you can specify the name of the generated Java class. Now it is accessible from Java like an utility class: TrafficLightUtils.isDrive(trafficLight) . If the name already existed in the same package the code would not compile. You can use another annotation @file:JvmMultifileClass to make this work.

Note, that in any case you call an extension function from Java as if it was a static function. In Kotlin you could simply call it on the object instance, which still looks the best: trafficLight.isDrive(). Lovin’ it.

II. @JvmField

You also want to create a class Ticket for those who cross the traffic light on red. In Java you would probably have written something like the code below. You can directly access your immutable field from another class by ticket.text :

When writing this in Kotlin you use a data class

Problem: Now Kotlin generates the accessor methods (getter and setter) for your property and it won’t be accessible as a field any more. You would need to access the property by ticket.getText() and update the code in the whole project. We don’t want that, do we?

Solution: To change this and access the property as a field again add the @JvmField annotation to the property. It “instructs the Kotlin compiler not to generate getters/setters for this property and expose it as a field”.

Access it by ticket.text again. Now you are well prepared to refactor an existing Java class with public final properties to Kotlin. “Hit it!”

III. @JvmOverloads

Let’s step to a more technical example. In your Android application you handle errors in one place and need to pass error information to this place. So you create a class which contains all the information to handle an error:

You made use of default values for two of your class’ properties.

Problem: Unfortunately, when creating such an object from a Java class, you still have to pass all values to the constructor — so not cool.

ErrorInfo("backendIssue", "this is totally related to the backend", null, false);

Solution: Another annotation comes in handy @JvmOverloads :

Now it’s also possible to create the ErrorInfo object as if you had overloaded the ErrorInfo constructor

ErrorInfo("backend issue", "this is totally related to the backend");

Boom! Long live interoperability! Inter-, inter-, interoperability!

IV. @JvmStatic

Let’s assume, you got really excited about all this and wrote your next Activity in Kotlin. As usual in this project, you create a static createIntent(context:Context) method. To achieve this you have to use a companion object inside your Activity:

You did this, because you wanted to achieve something like this: MainActivity.createIntent(this);
Like in the old Java days…

Problem: Without any further additions this looks different now: MainActivity.Companion.createIntent(this);
Yuck!

Solution: Use the@JvmStatic annotation, which specifies that an additional static method needs to be generated from this element.

Let’s call it — Kotlin

With these annotations

@file:JvmName*
@file:JvmMultifileClass*
@JvmField*
@JvmStatic*
@get:JvmName
@set:JvmName
@JvmOverloads*
@Throws
@JvmWildcard
@JvmSuppresWildcards
* See example above

you can now start developing with Kotlin in your Java legacy project, you can migrate old Java classes to Kotlin without any changes in the rest of the code base - e.g. next time you fix a NullPointerException. So hit it, hit Shift + Alt + Command + K in your Java classes and become a happy developer!

“Hello, Kotlin Calling.
Two, one, zero — der Alarm ist rot
Java ist tot — cha, cha, cha”
(post inspired by Falco)

I hope you liked it. Thanks a lot for reading this and spread the word.

--

--