Kotlin with Gradle

Table of Contents

Why Kotlin and Gradle

Compared with clojure and scala, kotlin is much lighter, as I'm going to write some android apps, it does matter. I've also tried mirah, but kotlin seems more promising.

Comming from the groovy world, Gradle has now become the de facto build tool for android development. I have very little experience with ant and maven, but gradle is more succinct and declarative.

Get Started

Gradle does have some project templates included, but very limited compared to lein. A list of templates can be get with gradle help --task :init, groovy and scala are included, but not kotlin. Just use the java-library template:

gradle init --type java-library

this will generate a bunch of files:

.
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── main
    │   └── java
    │       └── Library.java
    └── test
        └── java
            └── LibraryTest.java

7 directories, 8 files

run git init, add a simple .gitignore

.gradle
/build

It is said that the gradle stuff(gradlew, gradle/wrapper) should be included, so that the project can be build with the exact version of gradle in the future.

Building with Gradle

Modify build.gradle, add dependencies for kotlin:

apply plugin: 'kotlin'

buildscript {
  ext.kotlin_version = '0.10.195'
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
  }
}
dependencies {
    compile 'org.slf4j:slf4j-api:1.7.7'
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    testCompile 'junit:junit:4.12'
}

Build

Create the directory to put kotlin source:

mkdir -p src/main/kotlin
touch src/main/kotlin/Main.kt

add a simple Main.kt:

fun main(args: Array<String>) {
    println("kotlin!")
}

now build

gradle build

Gradle Run

It would be sweet to run the program directly, and there is a application plugin for that purpose. Add two more lines to build.gradle, to apply the plugin and specify the entry class:

apply plugin: 'application'

mainClassName = "_DefaultPackage"

Now the project can be build and launched with one single command

gradle run

Passing Arguments

It turns out to be a little tricky, but here is what I end up with:

gradle run -Dexec.args="placeholder arg1 arg2"

A run block is needed in build.gradle:

run {
  args System.getProperty("exec.args").split() 
}

Update Main.kt to use the args:

fun fib(n: Int):Int {
    return when (n) {
           0,1 -> 1
           else -> fib(n - 1) + fib(n - 2)
    }
}

fun main(args: Array<String>) {
    if (args.size() > 1) {
        println(fib(args[1].toInt()))
    } else {
        println("i need a number")
    }
}

Using External Libraries

Declear your dependencies in build.gradle:

dependencies {
    ...
    compile 'com.github.kevinsawicki:http-request:6.0'
    ...
}

Import, nothing fancy:

import com.github.kevinsawicki.http.HttpRequest

fun main(args: Array<String>) {
    val url:String = "https://hacker-news.firebaseio.com/v0/topstories.json"
    val response:String = HttpRequest.get(url).body()
    println(response)
}

JSON

dependencies {
    ...
    compile 'com.fasterxml.jackson.module:jackson-module-kotlin:2.5.1'
    ...
}
import com.github.kevinsawicki.http.HttpRequest
import com.fasterxml.jackson.module.kotlin.*

fun main(args: Array<String>) {
    val url:String = "https://hacker-news.firebaseio.com/v0/topstories.json"
    val response:String = HttpRequest.get(url).body()
    val mapper = jacksonObjectMapper()
    val ids:Array<Int> = mapper.readValue(response)
    for (id in ids) {
        println(id)
    }
}