This guide demonstrates how to create a Kotlin library targeted for the JVM. We’ll build a simple API with documentation, write and run tests, and package it all up into a something we can distribute.

It makes sense to use Gradle’s Kotlin DSL for build scripts since our library and tests are also in Kotlin.

What you’ll build

You’ll create a Kotlin library with the conventional layout, add a test to verify behavior, generate documentation, and publish the library with docs and sources.

If you get stuck at any point, you can check out the completed example.

What you’ll need

Step 1: Bootstrap Kotlin project

Let’s develop the simplest of libraries with just one API class and method.

Create project directory

This is the conventional layout for a Kotlin project. Luckily, Gradle is flexible and would allow us to easily change it by adjusting the sourceSets {}. We won’t worry about that today, though.

Kotlin project structure
my-kotlin-library
├── build.gradle.kts
└── src
    ├── main
    │   └── kotlin
    │       └── org
    │           └── example
    │               └── MyLibrary.kt
    └── test
        └── kotlin
            └── org
                └── example
                    └── MyLibraryTest.kt

The first step is to create a folder for the new project and change directory into it. In a *nix shell this would be:

$ mkdir -p my-kotlin-library/src/main/kotlin/org/example
$ cd my-kotlin-library

In our new directory we add our library class called MyLibrary that returns a value object Language.

src/main/kotlin/org/example/MyLibrary.kt
package org.example

/**
 * The `Language` type defines a programming language with a name and hotness score.
 *
 * @property name The name of the language.
 * @property hotness A score from 1 to 10 of user enthusiasm. 10 = so hot right now
 */
data class Language(val name: String, val hotness: Int)

class MyLibrary {
    /**
     * @return data relating to the Kotlin {@code Lanugage}.
     */
    fun kotlinLanguage() = Language("Kotlin", 10)
}

With the following simple build script we can compile our new Kotlin library.

build.gradle.kts
plugins {
    kotlin("jvm") version "1.2.10" (1)
}

repositories {
    jcenter() (2)
}

dependencies {
    implementation(kotlin("stdlib", "1.2.10")) (3)
}
1 Apply the Kotlin plugin, targeting the Java VM
2 Declare a dependency repository on Bintray jcenter
3 Declare a dependency on the Kotlin standard library

We use the implementation dependency configuration so that we don’t expose any of the Kotlin standard library through our API. This has architectural and performance benefits.

We’re nearly ready to start testing and packaging our software.

Digging deeper with a build scan

This is not strictly required to complete this guide, but using the build scan plugin will be very helpful with understanding what is happening with our builds.

build.gradle.kts
plugins {
+    `build-scan` (1)
     kotlin("jvm") version "1.2.10"
}
1 Apply the build scan plugin in the plugins {} block at the top.

Add the following build scan configuration below.

build.gradle.kts
buildScan {
    setLicenseAgreementUrl("https://gradle.com/terms-of-service") (1)
    setLicenseAgree("yes")

    publishAlways() (2)
}
1 We will never share your build information, but it’s important to read and agree to build scan terms of service.
2 Configure build scan plugin to create a build scan after all builds.

Now we can compile our project.

Compile Kotlin sources
$ gradle compileKotlin

> Task :compileKotlin
Using kotlin incremental compilation


BUILD SUCCESSFUL in 16s
1 actionable task: 1 executed

Publishing build scan...
https://gradle.com/s/vah36msduhfiu

For example, it is important to know that the Kotlin plugin applies Gradle’s Java plugin under the covers (we can see this in the "Plugins" section of the build scan). If we look at the docs for the Java plugin, we learn about all of the conventions it applies for things like Javadocs and packaging we’ll do later in this guide.

build scan plugins

Think of a build scan like a web-based, detailed build report. Super handy for digging into build failures or dependency issues. Let’s move on.

Step 2: Add testing with JUnit

JUnit 4 is the simplest of testing libraries to add to our project. If you happen to prefer the Spek framework for Kotlin-based specifications, check out the Spek docs.

build.gradle.kts
dependencies {
     implementation(kotlin("stdlib", "1.2.10"))
+    testImplementation("junit:junit:4.12") (1)
}
1 Add test implementation dependency on JUnit

Now we are ready to add tests for our library. We will follow the Kotlin plugin conventions and put them under src/test/kotlin.

src/test/kotlin/org/example/MyLibraryTest.kt
package org.example

import org.junit.Assert.assertEquals
import org.junit.Test

class MyLibraryTest {
    @Test fun testMyLanguage() {
        assertEquals("Kotlin", MyLibrary().kotlinLanguage().name)
        assertEquals(10, MyLibrary().kotlinLanguage().hotness)
    }
}

Nothing unexpected here. Now let’s run them.

Execute tests
$ gradle test

> Task :compileKotlin
Using kotlin incremental compilation

> Task :compileTestKotlin
Using kotlin incremental compilation


BUILD SUCCESSFUL in 5s
3 actionable tasks: 3 executed

Publishing build scan...
https://gradle.com/s/hxz67nlm3lejk

Boom. Tests.

Step 3: Add docs with Dokka

A library isn’t done until it’s documented. Dokka is a popular documentation engine for Kotlin projects. Let’s use it.

Apply the Dokka plugin

The Dokka Gradle plugin cannot be resolved from the Gradle Plugin Portal as of v0.9.15, so we will use a buildscript {} block to apply the plugin to the build script classpath, and then apply it.

build.gradle.kts
// Using buildscript {} instead of plugins {} due to https://github.com/Kotlin/dokka/issues/146
buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath("org.jetbrains.dokka:dokka-gradle-plugin:0.9.15")
    }
}
apply {
    plugin("org.jetbrains.dokka")
}

Configure Dokka plugin

Now we can add configuration down below in our build script.

build.gradle.kts
val dokka by tasks.getting(org.jetbrains.dokka.gradle.DokkaTask::class) {    (1)
    outputFormat = "html"
    outputDirectory = "$buildDir/javadoc"
}
1 Configure existing Dokka task to output HTML to typical Javadoc directory

There are many more configuration options available for Dokka, documented here, but this gets the job done for us right now. Let’s run it.

Generate docs with Dokka
$ gradle dokka

> Task :dokka
No documentation for org.example.MyLibrary (MyLibrary.kt:11)
No documentation for org.example.MyLibrary$<init>() (MyLibrary.kt:11)


BUILD SUCCESSFUL in 8s
1 actionable task: 1 executed

Publishing build scan...
https://gradle.com/s/buf6pl5vrjqt4

Dokka complains that we didn’t document absolutely everything, but there’s enough to get this if we open up $PROJECT_DIR/build/javadoc/my-kotlin-library/index.html. Click on the Language type and you should see our nice documentation.

dokka

Generate javadoc JAR

build.gradle.kts
import org.gradle.jvm.tasks.Jar

val dokkaJar by tasks.creating(Jar::class) { (1)
    group = JavaBasePlugin.DOCUMENTATION_GROUP
    description = "Assembles Kotlin docs with Dokka"
    classifier = "javadoc"
    from(dokka) (2)
}
1 Create dokka Jar task from dokka task output
2 dependsOn(dokka) not needed; dependency automatically inferred by from(dokka)

Try running gradle dokkaJar and see if you can find the javadoc JAR based on what you know so far.

We could optionally also generate a "sources" JAR using the same pattern from java.sourceSets["main"].allSource.

Step 4: Publish to local repo

Now our library is ready to share with the world. We’re going to publish it locally with the maven-publish plugin just to keep things simple, but another popular choice is the Gradle Bintray Plugin. Their documentation has several samples you can use if you’re interested.

Apply the maven-publish plugin

build.gradle.kts
plugins {
     `build-scan`
+    `maven-publish`
     kotlin("jvm") version "1.2.10"
}

Set project coordinates

Let us specify our project coordinates as org.example:my-kotlin-library:0.0.1 in our build script for publishing.

build.gradle.kts
group = "org.example"
version = "0.0.1"

The project name is set by the root project directory name by default, but it is best practice to make it explicit. This is done in a settings.gradle file at the project root.

settings.gradle
rootProject.name = "my-kotlin-library"

Configure Maven publication

For the maven-publish plugin to have any effect, a MavenPublication must be added to the set of publications. This publication determines which artifacts are actually published as well as the details included in the associated POM file.

build.gradle.kts
publishing {
    publications {
        create("default", MavenPublication::class.java) { (1)
            from(components["java"])
            artifact(dokkaJar) (2)
        }
    }
    repositories {
        maven {
            url = uri("$buildDir/repository") (3)
        }
    }
}
1 Create a Maven publication called "default" from the "java" component
2 Declare the javadoc JAR from Dokka as an artifact
3 Declare a local Maven repository under the build/ directory

Now we are ready to publish!

Publish to local repository
$ gradle publish

> Task :dokka
No documentation for org.example.MyLibrary (MyLibrary.kt:11)
No documentation for org.example.MyLibrary$<init>() (MyLibrary.kt:11)

> Task :compileKotlin
Using kotlin incremental compilation

Could not find metadata org.example:my-kotlin-library/maven-metadata.xml in remote (file:$PROJECT_DIR/build/repository)

BUILD SUCCESSFUL in 4s
7 actionable tasks: 7 executed

Publishing build scan...
https://gradle.com/s/ideifb3epyoz6

Your Maven repository should now have the published artifacts.

Local Maven repository
build/repository
└── org
    └── example
        └── my-kotlin-library
            ├── 0.0.1
            │   ├── my-kotlin-library-0.0.1-javadoc.jar
            │   ├── my-kotlin-library-0.0.1-javadoc.jar.md5
            │   ├── my-kotlin-library-0.0.1-javadoc.jar.sha1
            │   ├── my-kotlin-library-0.0.1.jar
            │   ├── my-kotlin-library-0.0.1.jar.md5
            │   ├── my-kotlin-library-0.0.1.jar.sha1
            │   ├── my-kotlin-library-0.0.1.pom
            │   ├── my-kotlin-library-0.0.1.pom.md5
            │   └── my-kotlin-library-0.0.1.pom.sha1
            ├── maven-metadata.xml
            ├── maven-metadata.xml.md5
            └── maven-metadata.xml.sha1

Congratulations! You’ve successfully built a Kotlin library, tested it, documented it, and packaged it as a JAR with docs and sources. The complete sample project is on GitHub.

Next Steps

We hope you found this fun and enlightening. Let us know what you thought of this guide via @gradle on Twitter.

Help improve this guide

Have feedback or a question? Found a typo? Like all Gradle guides, help is just a GitHub issue away. Please add an issue or pull request to gradle-guides/building-kotlin-jvm-libraries and we’ll get back to you.