I recently migrated my Gradle Plugin from Groovy to Kotlin. It was essentially a four step process:
- Update the build.gradle file
- Modify the Project Structure
- Convert Groovy code to Kotlin
- Migrate the JUnit tests
Let’s walk through each step…
build.gradle File
The first thing we need to do is update our plugin’s build.gradle file. We’re going to remove the Groovy dependencies and add those needed for Kotlin:
buildscript {
ext.kotlin_version = '1.1.1'
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
dependencies {
compile gradleApi()
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
Project Structure
The next step in the process is to update the project’s folder structure. For this, we just rename the main folder under src from groovy to kotlin. Then we can rename each file’s extension from .groovy to .kt. If you’re working inside IntelliJ IDEA, this renaming changes the icon that is displayed beside each file as well.
Groovy to Kotlin
With the folder structure updated, we need to start migrating our Groovy code over to Kotlin. Let’s start with a simple class, our Extension class. It was a plain Groovy class that held a few strings. These strings had default values.
Here’s the Kotlin version of the class:
The main difference is that we now declare the fields the Kotlin way, using:
var fieldName: String = "default value"
We’ve also added some constants to the QualityChecksPlugin class and imported them here to be used in the default strings’ values. The constants are stored inside a Companion object. This allows us to use them all over the code like public static variables from Java.
Let’s move over to a slightly more complex class: the CheckstyleTask class. Here are the changes we need to make:
//groovy class CheckstyleTask extends Checkstyle {
//kotlin open class CheckstyleTask : Checkstyle() {
We start out by modifying the way the class is declared. We add the open keyword and replace extends with : (colon) and the name of our base class with its empty constructor. Next we need to change how we initialize the fields of the Checkstyle class. Previously we created our own constructor and then initialized them all there. Kotlin does not allow you to have code in your primary constructor. Instead, we will use an init block to achieve the same goal.
init { project.plugins.apply(CheckstylePlugin::class.java) description = "Run Checkstyle" group = VERIFICATION_GROUP configFile = getCheckstyleConfigFile() classpath = project.files() ignoreFailures = false includes.add("**/*.java") excludes.add("**/gen/**") source.add("src") }
Inside of the init block there are minimal changes; instead of applying the CheckStylePlugin the Groovy way:
project.plugins.apply CheckstylePlugin
we use the Kotlin version and supply the CheckStylePlugin Class type:
project.plugins.apply(CheckstylePlugin::class.java)
The next most noticeable difference is the way we gain access to the QualityChecksExtension class. In Groovy we did this:
project?.qualityChecks
However with Kotlin, we would use this:
val extension = project?.extensions?.findByType(QualityChecksExtension::class.java)
It took me a while to figure out what was going on here. Apparently through “Groovy-fu”, Gradle was able to figure out that we wanted the extension which was added with the name “qualityChecks”. With Kotlin we have to be more specific.
JUnit Tests
Moving on to our tests. Kotlin has its own Specification Framework called Spek. However, I haven’t investigated it yet; therefore I went with migrating the existing JUnit tests from Groovy to Kotlin. Here’s an example test.
A few things to point out. First, there’s no public void for the method declarations only fun is needed. Second, we can have a String for the test name. This allows us to be more descriptive and really spell out what each test is all about. Third, we can take advantage of Kotlin’s with function to execute multiple methods on the same object. In fact, there are several idioms that come in handy when working with Kotlin. I noticed the benefits of using the apply and use functions as well during my migration.
The complete source code for the migrated plugin can be found here. I’d love to see more examples of Gradle Plugins written in Kotlin. If you know of any, please leave a link in the comments section. Thanks!