Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Test-Driving Kotlin in ZK

DZone's Guide to

Test-Driving Kotlin in ZK

Let's see what kinds of benefits Kotlin offers over Java when working with ZK as your frontend framework in a Java EE application.

· Java Zone ·
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

Every now and then it's time to learn something new — especially for a software developer. Be it just to keep in touch with recent developments, to challenge yourself by getting out of your comfort zone, or to widen your perspective and get fresh ideas on something you already know.

Very often, this means trying out the latest framework or a new platform. Sometimes, you work on an existing project and several decisions are already set in stone.

Assume you work on a JEE application using ZK as the frontend framework running on the JVM. In this case, you might not have all the degrees of freedom you might like. Still, you can be cheeky and keep up to date by using an alternative programming language running on the JVM. Obviously, a major feature of this language should be the interoperability with existing Java code and libraries.

Kotlin claims to be compatible. So, I decided to put this to the test just to see how far I could get and what surprises it has to offer. (Mild spoiler: It works!) Other important features of Kotlin are shorter and more expressive syntax as well as a safer and more flexible type system, avoiding common mistakes.

As a positive side effect, learning Kotlin adds to your own skill set — for example, when it comes to coding for the Android Platform in a future project (you never know!).

So why not combine the pleasant with the useful and just...

Enable Kotlin

Adding the Kotlin compiler to an existing Maven/Gradle project is well-documented and offers no surprises (in this example I chose Gradle just because of its shorter syntax):

build.gradle

buildscript {
    repositories { mavenCentral() }
    dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" }
}
apply plugin: "kotlin"
...
dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib"
    ...


After that, .kt (Kotlin) files are compiled automatically and produce bytecode executable by the JVM. Existing Java code continues to compile as well.

The usual Gradle commands just work as before:

  • ./gradlew compileKotlin  (just compile Kotlin)

  • ./gradlew test (run all tests)

  • ./gradlew build (e.g. build the WAR file)

That's all we need for now to move on.

Start Coding

Assume we have the following ZUL-Page, implemented using the MVVM pattern:

myIndex.zul

<zk>
    <div viewModel="@id('vm') @init('zk.kotlin.vm.MyViewModel')">
        Your Name:
        <textbox id="name" 
                 value="@bind(vm.name)"
                 onOK="@command('submit')"/>
        <button id="submit" label="submit"
                onClick="@command('submit')"/>
        <separator/>
        <label id="response" value="@load(vm.response)"/>
    </div>
</zk>


It will display a <textbox> widget to enter your name. When pressing ENTER ("onOK") or clicking the button, it will trigger the "submit" command and display a response:
 "Hello [yourname]!" in the  <label> below. What we need to implement is a View Model class with 2 properties: name and response.

In Java, this implementation could look like this:

public class MyViewModel {
    private String name = "";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getResponse() {
        return String.format("Hello %s!", name);
    }

    @Command("submit")
    @NotifyChange("response")
    public void submit() {
    }
}


Nothing remarkable here... just a POJO with a command handler - for the submit command.

Shorter Code

As a first surprise, the same class in Kotlin becomes:

MyViewModel.kt

class MyViewModel() {
    var name = ""
    val response get() = "Hello $name!"

    @Command("submit")
    @NotifyChange("response")
    fun submit() {
    }
}


One initially obvious benefit (from a Java developer's point of view) is the more compact/expressive syntax avoiding the (often brainlessly IDE-generated) getters and setters. Even in this embarrassingly trivial ViewModel class, we save about half the lines of code.

Astonishingly (not for a Kotlin developer) the compiled class still works in a ZK application when used as an MVVM ViewModel (without having to change the ZUL code or data- or command-binding expressions). Designed for interoperability with Java, the Kotlin compiler conveniently adds the getters/setters automatically, allowing existing frameworks to work as before, leveraging their functionality.

  • var (line 2) stands for variable, hence it has an implicit getter and setter 

  • val (line 3) is a read-only value, which needs just a getter

Where needed, we can implement a custom getter as for the calculated property response (which, as a bonus, uses the string interpolation feature to insert $name into the response string).

So far, we have simply achieved the same thing with less code (bad luck if you're paid by lines of code — which I think is just an urban legend anyway. Less typing for everyone else).

Safer Code

Other language features help to create code that is more compile/refactoring safe (without writing more code). Especially in a ZK+MVVM application, this can help to avoid runtime errors — often occurring due to a failed reflective method or field invocations.

In particular, I am referring those 2 annotations using magic strings that are resolved via reflection during runtime. As we can see in the code below, the command name and the notifyChange property name are such unwanted hard-coded String values:

    val response get() = "Hello $name!"

    @Command("submit")
    @NotifyChange("response")
    fun submit() { }


The @Command method is used in the ZUL-File in a @command-binding:

<button id="submit" label="submit"
        onClick="@command('submit')"/>


To avoid repetition, the command name is optional in the @Command annotation and, if missing, matches the method name (this also works in Java but doesn't solve our problem entirely).

    @Command
    @NotifyChange("response")
    fun submit() { }


Still, if the method name changes due to refactoring, the UI will break at runtime — no compiler will help there. In order to be more flexible with refactoring changes, we can use Kotlin's nice reflection API to introduce a property value, which will always match the method name.

In a similar way, we can use the reflection API to avoid hard-coding the response-property name (I'll get to that in a second). Here is the safer version of our View Model Class:

MySafeViewModel.kt

class MySafeViewModel() {
    val SUBMIT = ::submit.name;
    var name = ""
    val response get() = "Hello $name!"

    @Command fun submit() {
        notifyChange(::response.name)
    }
}


... and the updated usage in the .zul file (mySafeIndex.zul):

    <button id="submit" label="submit"
            onClick="@command(vm.SUBMIT)"/>


The syntax might look a bit alien at first — but hey, that's part of the learning experience. (Just try something similar in Java and you'll quickly learn to love this feature.)

As we can see, we traded the hard-coded Strings for compile- and refactoring-safe values, and we can use them in the ZUL file to never break the ZUL file due to command method name changes in the View Model.

Now, what happened to @NotifyChange("response")? Unfortunately, we can't just say @NotifyChange(::response.name) — that would have been nice, but annotation values require compile-time constants, while reflection is still a runtime API (both in Java and Kotlin).

Luckily, ZK has an (arguably ugly) utility method to trigger @NotifyChange programmatically ... We just have to call:

BindUtils.postNotifyChange(null, null, this, "response")
//the same compile-/refactoring-safe using Kotlin's reflection API
BindUtils.postNotifyChange(null, null, this, ::response.name)


Still too much to write? Kotlin's Extensions help to reduce repetitive typing. On top, I'd argue that the first 2 parameters are null 99% of the time, so we can implement the following 2 extension functions, both doing the same thing:

bindUtilsExt.kt

fun Any.notifyChange(propName: String) = 
        BindUtils.postNotifyChange(null, null, this, propName)

fun Any.notifyChange(prop: KProperty<*>) =
        notifyChange(prop.name) /*calls the method above*/


The notifyChange extension functions are defined on the Any type, so they can be called on every object. I can only recommend reading/understanding the documentation about this feature. Excessive use of this feature might make your code harder to reason about.

Here, it achieves a shorter syntax; fitting the existing ZK API to our needs. The following 4 lines have the same effect (you can choose which you like most):

//using ZK's API
BindUtils.postNotifyChange(null, null, this, "response")
//using ZK's API + Kotlin reflection
BindUtils.postNotifyChange(null, null, this, ::response.name)
//using our extension function, passing the property name as string
notifyChange(::response.name)
//overloaded version using the property reference directly
notifyChange(::response)


You can also notify nested properties, e.g. the street-property of an Address object: 

//using ZK's API
BindUtils.postNotifyChange(null, null, someAddress, "street"); 
//shorter & compile safe using our extension
someAddress.notifyChange(Address::street)


Before I forget to mention it: In order to use Kotlin's reflection API, you have to add the kotlin-reflect dependency.

build.gradle

    compile "org.jetbrains.kotlin:kotlin-reflect"


Taking a Break

Since the article is already getting quite long, I'll cover a slightly more interesting CRUD example using ZK's Form-Binding in combination with Kotlin's data-classes and Kotlin+JUnit+ZATS in separate articles.

Special thanks go to Carsten Lenz (Germany)
who patiently helped out during a "quick" 20-30-minute call
(which actually took 2 hours)

Example Code

The full code is available on GitHub and can be run using the following commands:

git clone https://github.com/zkoss-demo/zk-kotlin.git
cd zk-kotlin
./gradlew startJettyRunner


Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:
java ,zk framework ,kotlin ,front end development ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}