Annotation Processing with Kapt and Gradle
KOTLIN!! …is what all of Google was collectively shouting at Android developers at this year’s I/O conference. And that’s great — Kotlin is a full featured language with great IDE support that makes writing Android apps a heck of a lot easier and faster. Kotlin is, however, still very new, with version 1.0 released in just February of last year. And as with anything that new, not everything quite works.
One thing that has been painful for a while, but is starting to become easier, is using Kotlin with annotation processors. But even with a lot of the functional issues worked out, there isn’t a ton of documentation about how all the pieces go together, so let’s walk through it.
We’re going to assume that you’re already conversant on the subject of Java annotation processors. With that in mind, there are really only a few differences.
kapt
Kapt is the Kotlin Annotation Processing Tool, and it’s in pretty good shape these days. If you want to be able to reference generated code from Kotlin, you need to use kapt. To do that, simply include the plugin in your build.gradle file with the line:
apply plugin: 'kotlin-kapt'
And where you would normally use the annotationProcessor keyword to specify your processor dependency, instead use the kapt keyword.
That’s it. You’re done.
Not Quite
Ok, you’re almost done. The next, and most interesting question is, how do you debug an annotation processor that’s compiled with kapt?
If you’re coming from java, you might be familiar with debugging an annotation processor by running javac from the command line and then attaching the debugger to it. But kapt isn’t using javac to compile, it’s using kotlinc. So the instructions for debugging an annotation processor the normal way need to be very slightly modified for kapt, in two ways:
- The command we want to run is now:
./gradlew :app:clean :app:compileDebugKotlin --no-daemon -Dorg.gradle.debug=true -Dkotlin.compiler.execution.strategy="in-process" -Dkotlin.daemon.jvm.options="-Xdebug,-Xrunjdwp:transport=dt_socket\,address=5005\,server=y\,suspend=n"
Note: The above command has been edited from the original story because of a comment on this stackoverflow. The new command allows you to attach the debugger at any time, rather than waiting for the kapt step to begin and forcing you to try and “catch” it. Summary — use this new command, it’s way better.
2.W̶e̶ ̶n̶e̶e̶d̶ ̶t̶o̶ ̶w̶a̶i̶t̶ ̶f̶o̶r̶ ̶t̶h̶e̶ ̶K̶o̶t̶l̶i̶n̶ ̶c̶o̶m̶p̶i̶l̶a̶t̶i̶o̶n̶ ̶t̶a̶s̶k̶ ̶t̶o̶ ̶b̶e̶g̶i̶n̶ ̶b̶e̶f̶o̶r̶e̶ ̶w̶e̶ ̶a̶t̶t̶a̶c̶h̶ ̶t̶h̶e̶ ̶d̶e̶b̶u̶g̶g̶e̶r̶.̶ ̶S̶o̶ ̶y̶o̶u̶ ̶w̶a̶n̶t̶ ̶t̶o̶ ̶m̶o̶n̶i̶t̶o̶r̶ ̶y̶o̶u̶r̶ ̶b̶u̶i̶l̶d̶ ̶a̶n̶d̶ ̶l̶o̶o̶k̶ ̶f̶o̶r̶ ̶t̶h̶e̶ ̶t̶a̶s̶k̶:̶
:app:kaptDebugKotlin
A̶n̶d̶ ̶w̶h̶e̶n̶ ̶y̶o̶u̶ ̶s̶e̶e̶ ̶i̶t̶,̶ ̶h̶e̶a̶d̶ ̶i̶m̶m̶e̶d̶i̶a̶t̶e̶l̶y̶ ̶o̶v̶e̶r̶ ̶t̶o̶ ̶y̶o̶u̶r̶ ̶I̶D̶E̶ ̶a̶n̶d̶ ̶h̶i̶t̶ ̶d̶e̶b̶u̶g̶ ̶o̶n̶ ̶y̶o̶u̶r̶ ̶R̶e̶m̶o̶t̶e̶ ̶c̶o̶n̶f̶i̶g̶u̶r̶a̶t̶i̶o̶n̶.̶ ̶I̶n̶ ̶m̶y̶ ̶e̶x̶p̶e̶r̶i̶e̶n̶c̶e̶,̶ ̶i̶f̶ ̶y̶o̶u̶ ̶d̶o̶n̶’̶t̶ ̶a̶t̶t̶a̶c̶h̶ ̶i̶n̶ ̶t̶i̶m̶e̶,̶ ̶t̶h̶e̶ ̶t̶a̶s̶k̶ ̶w̶i̶l̶l̶ ̶j̶u̶s̶t̶ ̶m̶o̶v̶e̶ ̶o̶n̶.̶ ̶Y̶o̶u̶ ̶h̶a̶v̶e̶ ̶a̶ ̶f̶e̶w̶ ̶s̶e̶c̶o̶n̶d̶s̶ ̶t̶o̶ ̶f̶i̶g̶u̶r̶e̶ ̶i̶t̶ ̶o̶u̶t̶,̶ ̶b̶u̶t̶ ̶i̶t̶’̶s̶ ̶a̶ ̶b̶i̶t̶ ̶o̶f̶ ̶a̶ ̶r̶a̶c̶e̶ ̶t̶o̶ ̶g̶e̶t̶ ̶i̶t̶ ̶a̶l̶l̶ ̶w̶o̶r̶k̶i̶n̶g̶.̶
EDIT: The above ^ is no longer the case! With the new gradle command, you can attach the debugger at any time, and it should hit breakpoints in your processor class. Yay! The only caveat is that sometimes the debugger will hang at other points in the build, just restart or reattach debugging, and you’ll be good to go.
So THAT’s really it. Now you can build, run, and debug your annotation processor with kapt. Happy Kotlin-ing.