Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Exploiting Kotlin Metadata + Annotation Processing

Exploiting Kotlin Metadata + Annotation Processing

When compiling Kotlin code for the JVM, the resulting bytecode doesn't understand the advanced features of the language – like the difference between List and MutableList, or List<String> and List<String?>.

A year ago a prototype was developed to use these "metadata" during annotation processing; today, a few popular libraries (even from Google!) employ it under the hood to take their Kotlin integration to the next level.

Join us to explore what's possible, and have fun digging into some practical examples.

[ sequel to last year's presentation at Kotlin Night Berlin: "Unleash the secret power of Kotlin Metadata" ]

Eugenio Marletti

June 15, 2018
Tweet

More Decks by Eugenio Marletti

Other Decks in Technology

Transcript

  1. class object data class sealed class !" !" !" !"

    class class class abstract class
  2. public final class Sample { private final int counter; public

    final int getCounter() { return this.counter; } public Sample(int counter) { this.counter = counter; } public final int component1() { return this.counter; } @NotNull public final Sample copy(int counter) { return new Sample(counter); } // $FF: synthetic method // $FF: bridge method @NotNull public static Sample copy$default(Sample var0, int var1, int var2, Object var3) { if((var2 & 1) != 0) { var1 = var0.counter; } return var0.copy(var1); } public String toString() { return "Sample(counter=" + this.counter + ")"; } public int hashCode() { return this.counter; } public boolean equals(Object var1) { if(this != var1) { if(var1 instanceof Sample) { Sample var2 = (Sample)var1; if(this.counter == var2.counter) { return true; } } return false; } else { return true; } } } @Metadata( k = 1, mv = {1, 1, 10}, bv = {1, 0, 2}, d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\b\n\u0002\b\u0006\n\u0002\u0010\u000b\n\u0002\b\u0003\n\u0002\u0010\u000e\n\u0000\b\u0086\b\u0018\u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0010\ d2 = {"LSample;", "", "counter", "", "(I)V", "getCounter", "()I", "component1", "copy", "equals", "", "other", "hashCode", "toString", "", "production sources for module app"} ))
  3. @Metadata( k = 1, mv = {1, 1, 10}, bv

    = {1, 0, 2}, d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0 d2 = {"LSample;", "", "counter", "", "(I)V", "getCounter", "()I", "compon ))
  4. @Metadata 1. kind 2. metadata version 3. bytecode version 4.

    data1 5. data2 6. extra string 7. extra int 8. package name
  5. 8. package name fully qualified package (if != from Java)

    (ie. @JvmPackageName) (no classes!)
  6. 7. extra int 0 -> multi-file class facade or part

    1 -> compiled by a pre-release version 2 -> Kotlin script source file (.kts)
  7. 1. kind 1 -> Class 2 -> File 3 ->

    Synthetic class 4 -> Multi-file class facade 5 -> Multi-file class part
  8. * nullability (also nested) * secondary constructors * companion object

    name * properties list * delegated types * internal visibility * sealed class hierarchy * type aliases (declaration and usage) * generic types (also in/out /*, reified) * classes (data/sealed/object/companion) * property (var/getter/setter/const/lateinit) * value parameter (default/crossinline/noinline) * function (operator/infix/inline/tailrec/external)
  9. ( )

  10. kotlin-metadata roadmap - use jetbrains/kotlinx-metadata-jvm (shadowed) - wrap Types/Elements in

    idiomatic Kotlin API - expose type mapping Java <-> Kotlin - KotlinPoet integration - documentation–HAHAHA JUST KIDDING
  11. goo.gl/nEcGmR -> JetBrains/kotlinx-metadata-jvm goo.gl/V26u5C -> Takhion/kotlin-metadata goo.gl/yWgvor -> Exploring Moshi’s

    Kotlin Code Gen goo.gl/mZdccu -> Moshi Kotlin Code Gen: An Open Source Story goo.gl/FPKqZ7 -> Λrrow annotation processors goo.gl/UDNmvh -> Moshi annotation processor goo.gl/GBHMqs -> Room annotation processor