How to Make Gradle Kotlin Projects Work Properly With Annotation Processor in IntelliJ

Eric Lin
Atlas
Published in
4 min readSep 28, 2017

A week ago I was thinking of writing a small Kotlin command line tool to read some local JSON files. I opened IntelliJ and started a Kotlin project with Gradle. Everything worked just fine. I could compile and run the output jar file until I imported autovalue. Autovalue uses an annotation processor to generate model objects, but IntelliJ just would not invoke annotation processing properly, so the compilation failed. I did some research and finally made it work, and I think these tricks are worth sharing.

A side note:

Not long ago I wrote a post about why I am still using autovalue in Kotlin projects (Why converting Autovalue class to Kotlin data class may not be “pragmatic” for JSON models at this moment).

JetBrains is really good at listening to the community. They released two experimental features to address the two issues I mentioned in the post:

Start a new Kotlin project

Let’s start a new project with Kotlin and Gradle supports:

Import the library that uses annotation processing, and enable the Kotlin kapt plugin. I use Autovalue as the example:

apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'

repositories {
mavenCentral()
}

dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"

compileOnly "com.google.auto.value:auto-value:1.5"
kapt "com.google.auto.value:auto-value:1.5"
}

// make sure you add these configuration for jar task
jar {
manifest {
attributes 'Main-Class': 'AnnotationProcessorKt'
}

from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}

jar task reference: Kotlin Basics: Create Executable Kotlin JARs, using Gradle

Lastly, we need a simple main method and an Autovalue class:

import com.google.auto.value.AutoValue

@AutoValue
abstract class Person {

abstract fun firstName(): String

abstract fun lastName(): String
}

fun main(args: Array<String>) {

// This won't work in IntelliJ out of box
val p: Person = AutoValue_Person("Eric", "Lin")
println("Hi, I am $p")
}

Of course, like I said earlier, the line val p: Person = AutoValue_Person("Eric", "Lin") just won't work! But if you run the jar task via Gradle in a command line directly, you can get a working jar file:

jar in gradle

Delegate IDE build/run actions to gradle

The problem here is when you “build” the project, IntelliJ does NOT use the same settings you configure in build.gradle. You must to configure the annotation processor manually, which can be awkward to set up, and I could not get it to work properly.

Instead there’s a much simpler trick you can do: Just tell IntellJ to use gradle for your build process!

In Build Tools -> Gradle -> Runner, you can tick the setting Delegate IDE build/run actions to gradle so that IntelliJ will use gradle for your project.

runner

Expose generated files to IntelliJ

Now you can verify that the build/generated directory contains the generated files:

generated

However, the file we need AutoValue_Person.java is still not recognized as the source file by the IDE.

There are two ways to mark the kapt directory as a source directory:

1. Manually mark the directory

Right click on the kapt directory -> Mark Directory as -> Sources Root

mark as source manually

2. Use IDEA gradle plugin to mark sources

Add the following snippet to your build.gradle

idea {
module {
sourceDirs += files('build/generated/source/kapt/main', 'build/generated/source/kaptKotlin/main')
generatedSourceDirs += files('build/generated/source/kapt/main', 'build/generated/source/kaptKotlin/main')
}
}

By doing so, the IDEA plugin will configure IntelliJ to treat those two directories as normal source directories.

reference: JetBrains/kotlin-examples

Run and Debug the jar file inside IntelliJ

Now you should be able to compile the project in IntelliJ without any compilation errors. However, wouldn’t it be nice if we can run and debug the output jar file in the IDE as well?

Here’s the trick I use:

  1. Go to run configuration
  2. Create a Jar Application
  3. Type in the path to the expected output jar file
  4. In Before Launch settings, add a gradle task jar
run configuration

Once the run configuration is set, you should be able to click on run or debug for your compiled jar file inside the IDE!

run the jar file
debug the jar file

Whoa! Long live Kotlin!

--

--

Eric Lin
Atlas
Writer for

Honest Android developer. Loves Kotlin and new technologies.