Pushing the limits of Kotlin annotation processing

Is annotation processing really supported in Kotlin? ☐ Yes ☐ No ☑ It’s complicated

There are times when writing code “by hand” is not enough, because the code you’re writing is mechanically derived from other code, and the result is pure boilerplate: a nightmare of copy/paste.

That’s when metaprogramming becomes a necessity, and in Java there are two ways to achieve such capabilities: reflection and annotation processing.

Reflection is perhaps the easiest solution, but has a few downsides:

it might cause performance problems if misused (especially on constrained platforms like Android)

it’s less “safe”, as code that compiles fine might crash at runtime

and most importantly: it can only inspect and access existing constructs, like methods and classes, but not create new ones

Kotlin is a much richer language than Java, and as such it stores all this extra metadata in special annotations. If you use the standard reflection API in Kotlin, you’ll only be able to inspect things from the JVM perspective; that’s why Kotlin comes with an external reflection library that allows to access the extra information. One thing to note is that at the moment it’s rather large, which is another downside when used on Android.

Annotation processing is much more powerful because not only it allows developers to inspect pretty much everything about the structure of code before running it, but offers the ability to generate extra classes.

Lately I’ve been involved in a few Kotlin projects, both personally and at work, which require the use of annotation processing, and they do so in a way that requires to either/or:

inspect Kotlin types, because as said before they carry extra information compared to their JVM equivalent

generate Kotlin code, as that’s the only way to access some of the advanced features that Kotlin offers

The whole issue revolves around one question:

“Is annotation processing supported in Kotlin, and how well does it work?”

To answer that, let’s start with a bit of history, necessary to understand everything that follows…