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

Using Kotlin Extensions in Groovy

DZone's Guide to

Using Kotlin Extensions in Groovy

Dive into two different ways of using extension methods with Kotlin and Groovy, which is particularly useful if you want to use Spock for testing.

· 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.

Kotlin and Groovy have mechanisms for extending existing classes without using inheritance or decorators. In both languages, the mechanisms are called extension methods. Their source code looks different, but generated bytecode is quite similar. Thanks to that, Groovy is able to use Kotlin extensions just like its own.

Why would I want to use such extensions in Groovy? The main reason is that I want to test my extensions using the best testing framework available for the JVM — Spock Framework.

The code is available here.

Extensions in Kotlin

There are many types of extensions in Kotlin. I decided to focus only on extension functions and properties.

As an example, I extend the java.lang.String class. First, I create an extension function, skipFirst, which skips the first N characters:

fun String.skipFirst(n: Int) = if (length > n) this.substring(n) else ""


Next, I create an extension property answer, which is the Answer to the Ultimate Question of Life, the Universe, and Everything:

val String.answer
    get() = 42


Both extensions are declared in the package com.github.alien11689.extensions, in the file StringExtensions. However, the generated class in the target directory is named StringExtensionsKt , and this is the name that must be used when accessing it from other languages. Specific class names can be forced by the annotation @file:JvmName.

Using Kotlin Extensions in Groovy

There are two ways to use extensions in Groovy (that are supported by good IDEs). First, you can declare the scope where the extensions are available by the use method:

def "should use extension method"() {
    expect:
        use(StringExtensionsKt) {
            input.skipFirst(n) == expected
        }
    where:
        input  | n | expected
        "abcd" | 3 | "d"
        "abcd" | 6 | ""
        ""     | 3 | ""
}

def "should use extension property"() {
    expect:
        use(StringExtensionsKt) {
            "abcd".answer == 42
        }
}


This is acceptable, but it is not very convenient. The second and much better way is to use an extension module definition. The extension module is defined in the file org.codehaus.groovy.runtime.ExtensionModule in the directory src/main/resources/META-INF/services/. The same directory is monitored by ServiceLoader, but the file format is completely different:

moduleName=string-extension-module
moduleVersion=1.0.0
extensionClasses=com.github.alien11689.extensions.StringExtensionsKt


The tests look much better now:

def "should use extension method"() {
    expect:
        input.skipFirst(n) == expected
    where:
        input  | n | expected
        "abcd" | 3 | "d"
        "abcd" | 6 | ""
        ""     | 3 | ""
}

def "should use extension property"() {
    expect:
        "abcd".answer == 42
}

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

Topics:
kotlin ,groovy ,extensions ,java

Published at DZone with permission of Dominik Przybysz. See the original article here.

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}