Slide 1

Slide 1 text

Annotation Processing in a Kotlin World Zac Sweers @pandanomic

Slide 2

Slide 2 text

Annotation Processing in a Kotlin World

Slide 3

Slide 3 text

https://goo.gl/rSHTn4

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Annotation Processing in a Kotlin World

Slide 6

Slide 6 text

Annotation Processing in a Kotlin World

Slide 7

Slide 7 text

Annotation Processing in a Kotlin World

Slide 8

Slide 8 text

Dagger @Inject @Qualifier

Slide 9

Slide 9 text

@Provides fun provideList(): List { return emptyList() }a

Slide 10

Slide 10 text

@Provides fun provideList(): List { return emptyList() }a @Inject lateinit var tacoList: List

Slide 11

Slide 11 text

@Provides fun provideList(): List { return emptyList() }a @Inject lateinit var tacoList: List<@SuppressJvmWildcard Taco>

Slide 12

Slide 12 text

@Provides fun provideList(): List { return emptyList() }a @Inject lateinit var tacoList: List<@SuppressJvmWildcard Taco>

Slide 13

Slide 13 text

@Provides fun provideTaco(): Taco { return BreakfastTaco() }a @Inject lateinit var taco: Taco

Slide 14

Slide 14 text

@Breakfast @Provides fun provideTaco(): Taco { return BreakfastTaco() }a @Breakfast @Inject lateinit var taco: Taco

Slide 15

Slide 15 text

@Breakfast @Provides fun provideTaco(): Taco { return BreakfastTaco() }a @field:Breakfast @Inject lateinit var taco: Taco

Slide 16

Slide 16 text

@Breakfast @Provides fun provideTaco(): Taco { return BreakfastTaco() }a @field:Breakfast @Inject lateinit var taco: Taco

Slide 17

Slide 17 text

@Module class NetworkModule { @Provides static HttpClient provideHttpClient() { return HttpClient.create(); }a }b

Slide 18

Slide 18 text

@Module class NetworkModule { @Provides static HttpClient provideHttpClient() { return HttpClient.create(); }a companion object { }c }b

Slide 19

Slide 19 text

@Module class NetworkModule { companion object { @Provides fun provideHttpClient(): HttpClient { return HttpClient.create() }a }c }b

Slide 20

Slide 20 text

@Module class NetworkModule { companion object { @JvmStatic @Provides fun provideHttpClient(): HttpClient { return HttpClient.create() }a }c }b

Slide 21

Slide 21 text

@Module class NetworkModule { @Module companion object { @JvmStatic @Provides fun provideHttpClient(): HttpClient { return HttpClient.create() }a }c }b

Slide 22

Slide 22 text

@Module class NetworkModule { @Module companion object { @JvmStatic @Provides fun provideHttpClient(): HttpClient { return HttpClient.create() }a }c }b

Slide 23

Slide 23 text

@Module class NetworkModule { @Module companion object { @JvmStatic @Provides fun provideHttpClient(): HttpClient { return HttpClient.create() }a }c }b

Slide 24

Slide 24 text

Quick refresher

Slide 25

Slide 25 text

Quick refresher • Compile time

Slide 26

Slide 26 text

Quick refresher • Compile time • Since Java 5ish (APIs in Java 6)

Slide 27

Slide 27 text

Quick refresher • Compile time • Since Java 5ish (APIs in Java 6) • Reads Java (byte) code in intermediate format

Slide 28

Slide 28 text

Quick refresher • Compile time • Since Java 5ish (APIs in Java 6) • Reads Java (byte) code in intermediate format • Elements, Types, Filer, etc APIs

Slide 29

Slide 29 text

Quick refresher • Compile time • Since Java 5ish (APIs in Java 6) • Reads Java (byte) code in intermediate format • Elements, Types, Filer, etc APIs • Cannot modify code, only generate more

Slide 30

Slide 30 text

Quick refresher • Compile time • Since Java 5ish (APIs in Java 6) • Reads Java (byte) code in intermediate format • Elements, Types, Filer, etc APIs • Cannot modify code, only generate more • Multiple rounds

Slide 31

Slide 31 text

Quick refresher • Compile time • Since Java 5ish (APIs in Java 6) • Reads Java (byte) code in intermediate format • Elements, Types, Filer, etc APIs • Cannot modify code, only generate more • Multiple rounds

Slide 32

Slide 32 text

Quick refresher • Compile time • Since Java 5ish (APIs in Java 6) • Reads Java (byte) code in intermediate format • Elements, Types, Filer, etc APIs • Cannot modify code, only generate more • Multiple rounds

Slide 33

Slide 33 text

class Person(val name: String)

Slide 34

Slide 34 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004\b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/String;)V", "getName", "()Ljava/lang/String;", "test- project"} ) public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; } public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); } }

Slide 35

Slide 35 text

public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; } public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); } }

Slide 36

Slide 36 text

class Person(val name: String)

Slide 37

Slide 37 text

public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; }c public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); }a }b

Slide 38

Slide 38 text

public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; }c public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); }a }b

Slide 39

Slide 39 text

public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; }c public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); }a }b

Slide 40

Slide 40 text

class Person(val name: String = "Joe")

Slide 41

Slide 41 text

public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; }c public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); }a }b

Slide 42

Slide 42 text

public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; }c public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); }a public Person() { super(); }d }b

Slide 43

Slide 43 text

public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; }c public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); }a public Person() { super(); }d }b

Slide 44

Slide 44 text

class Person(val names: List)

Slide 45

Slide 45 text

class Person(val names: List) public Person(@NotNull List names)

Slide 46

Slide 46 text

class Person(val names: MutableList) public Person(@NotNull List names)

Slide 47

Slide 47 text

public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; } public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); } }

Slide 48

Slide 48 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004\b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; } public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); } }

Slide 49

Slide 49 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004\b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; } public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); } }

Slide 50

Slide 50 text

annotation class Metadata( )a

Slide 51

Slide 51 text

annotation class Metadata( val k: Int = 1 )a

Slide 52

Slide 52 text

annotation class Metadata( val k: Int = 1, val mv: IntArray = [] )a

Slide 53

Slide 53 text

annotation class Metadata( val k: Int = 1, val mv: IntArray = [], val bv: IntArray = [] )a

Slide 54

Slide 54 text

annotation class Metadata( val k: Int = 1, val mv: IntArray = [], val bv: IntArray = [], val d1: Array = [] )a

Slide 55

Slide 55 text

annotation class Metadata( val k: Int = 1, val mv: IntArray = [], val bv: IntArray = [], val d1: Array = [], val d2: Array = [] )a

Slide 56

Slide 56 text

internal annotation class Metadata( val k: Int = 1, val mv: IntArray = [], val bv: IntArray = [], val d1: Array = [], val d2: Array = [] )a

Slide 57

Slide 57 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004\b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a public final class Person { @org.jetbrains.annotations.NotNull() private final java.lang.String name = null; @org.jetbrains.annotations.NotNull() public final java.lang.String getName() { return null; } public Person(@org.jetbrains.annotations.NotNull() java.lang.String name) { super(); } }

Slide 58

Slide 58 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 59

Slide 59 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 60

Slide 60 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 61

Slide 61 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 62

Slide 62 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 63

Slide 63 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 64

Slide 64 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 65

Slide 65 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 66

Slide 66 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 67

Slide 67 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 68

Slide 68 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

No content

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

val metadata = typeElement.getAnnotation(Metadata::class.java)

Slide 74

Slide 74 text

"Reading information from an annotation, you say?"

Slide 75

Slide 75 text

Compiler Plugins

Slide 76

Slide 76 text

Compiler Plugins • Faster/incremental

Slide 77

Slide 77 text

Compiler Plugins • Faster/incremental • No stubs generation

Slide 78

Slide 78 text

Compiler Plugins • Faster/incremental • No stubs generation • No kapt

Slide 79

Slide 79 text

Compiler Plugins • Faster/incremental • No stubs generation • No kapt

Slide 80

Slide 80 text

BUT!

Slide 81

Slide 81 text

BUT!

Slide 82

Slide 82 text

BUT! • Undocumented and not stable

Slide 83

Slide 83 text

BUT! • Undocumented and not stable • Only applies to Kotlin sources

Slide 84

Slide 84 text

BUT! • Undocumented and not stable • Only applies to Kotlin sources • Tooling can be painful

Slide 85

Slide 85 text

BUT! • Undocumented and not stable • Only applies to Kotlin sources • Tooling can be painful • github.com/hzsweers/redacted-compiler- plugin

Slide 86

Slide 86 text

BUT! • Undocumented and not stable • Only applies to Kotlin sources • Tooling can be painful • github.com/hzsweers/redacted-compiler- plugin • The talk title was Annotation Processing in a Kotlin

Slide 87

Slide 87 text

BUT!* • Undocumented and not stable • Only applies to Kotlin sources • Tooling can be painful • github.com/hzsweers/redacted-compiler- plugin • The talk title was Annotation Processing in a Kotlin

Slide 88

Slide 88 text

"Reading information from an annotation, you say?"

Slide 89

Slide 89 text

kotlin-metadata https://github.com/takhion/kotlin-metadata

Slide 90

Slide 90 text

val metadata = typeElement.getAnnotation(Metadata::class.java)

Slide 91

Slide 91 text

val Element.kotlinMetadata: KotlinMetadata? val metadata = typeElement.getAnnotation(Metadata::class.java)

Slide 92

Slide 92 text

val Element.kotlinMetadata: KotlinMetadata? val metadata = typeElement.kotlinMetadata

Slide 93

Slide 93 text

when (typeElement.kotlinMetadata) { is KotlinPackageMetadata -> is KotlinClassMetadata -> is KotlinFileMetadata -> is KotlinMultiFileClassPartMetadata -> is KotlinMultiFileClassFacadeMetadata -> is KotlinSyntheticClassMetadata -> is KotlinUnknownMetadata -> }a

Slide 94

Slide 94 text

when (typeElement.kotlinMetadata) { is KotlinClassMetadata -> }a

Slide 95

Slide 95 text

when (metadata) { is KotlinClassMetadata -> { val classData: ClassData = metadata.data }a }b

Slide 96

Slide 96 text

when (metadata) { is KotlinClassMetadata -> { val classData: ClassData = metadata.data val proto: ProtoBuf.Class = classData.classProto }a }b

Slide 97

Slide 97 text

No content

Slide 98

Slide 98 text

when (metadata) { is KotlinClassMetadata -> { val classData: ClassData = metadata.data val proto: ProtoBuf.Class = classData.classProto }a }b

Slide 99

Slide 99 text

when (metadata) { is KotlinClassMetadata -> { val classData: ClassData = metadata.data val proto: ProtoBuf.Class = classData.classProto val nameResolver = classData.nameResolver }a }b

Slide 100

Slide 100 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 101

Slide 101 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 102

Slide 102 text

@kotlin.Metadata( mv = {1, 1, 11}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n \u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\b\u0007\u0018 \u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u0 0020\u0003\u00a2\u0006\u0002\u0010\u0004R\u0011\u0010\u0 002\u001a\u00020\u0003\u00a2\u0006\b\n\u0000\u001a\u0004 \b\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2 = {"Ltest/Person;", "", "name", "", "(Ljava/lang/ String;)V", "getName", "()Ljava/lang/String;", "test- project"} )a

Slide 103

Slide 103 text

when (metadata) { is KotlinClassMetadata -> { val classData: ClassData = metadata.data val proto: ProtoBuf.Class = classData.classProto val nameResolver = classData.nameResolver }a }b

Slide 104

Slide 104 text

val proto: ProtoBuf.Class = classData.classProto val constructors: List = proto.constructorList val properties: List = proto.propertyList val functions: List = proto.functionList

Slide 105

Slide 105 text

class Person(val name: String = "Joe")

Slide 106

Slide 106 text

class Person(val name: String = "Joe") val name = TODO()

Slide 107

Slide 107 text

class Person(val name: String = "Joe") val name = TODO() val mutable = TODO()

Slide 108

Slide 108 text

class Person(val name: String = "Joe") val name = TODO() val mutable = TODO() val nullable = TODO()

Slide 109

Slide 109 text

class Person(val name: String = "Joe") val name = TODO() val mutable = TODO() val nullable = TODO() val hasDefault = TODO()

Slide 110

Slide 110 text

class Person(val name: String = "Joe") val name = TODO() val mutable = TODO() val nullable = TODO() val hasDefault = TODO()

Slide 111

Slide 111 text

class Person(val name: String = "Joe") val proto = classData.classProto val constr = proto.constructorList.find { it.isPrimary } val name = TODO() val mutable = TODO() val nullable = TODO() val hasDefault = TODO()

Slide 112

Slide 112 text

it.isPrimary

Slide 113

Slide 113 text

val Constructor.isPrimary: Boolean get() { return !Flags.IS_SECONDARY[flags] }

Slide 114

Slide 114 text

class Person(val name: String = "Joe") val proto = classData.classProto val constr = proto.constructorList.find { it.isPrimary } val name = TODO() val mutable = TODO() val nullable = TODO() val hasDefault = TODO()

Slide 115

Slide 115 text

class Person(val name: String = "Joe") val proto = classData.classProto val constr = proto.constructorList.find { it.isPrimary } val nameParam = constr.valueParameterList[0] val name = TODO() val mutable = TODO() val nullable = TODO() val hasDefault = TODO()

Slide 116

Slide 116 text

class Person(val name: String = "Joe") val proto = classData.classProto val constr = proto.constructorList.find { it.isPrimary } val nameParam = constr.valueParameterList[0] val name = nameResolver.getString(nameParam.name) val mutable = TODO() val nullable = TODO() val hasDefault = TODO()

Slide 117

Slide 117 text

class Person(val name: String = "Joe") val proto = classData.classProto val constr = proto.constructorList.find { it.isPrimary } val nameParam = constr.valueParameterList[0] val name = nameResolver.getString(nameParam.name) val mutable = TODO() val nullable = TODO() val hasDefault = nameParam.declaresDefaultValue

Slide 118

Slide 118 text

class Person(val name: String = "Joe") val proto = classData.classProto val constr = proto.constructorList.find { it.isPrimary } val nameParam = constr.valueParameterList[0] val name = nameResolver.getString(nameParam.name) val mutable = TODO() val nullable = nameParam.type.nullable val hasDefault = nameParam.declaresDefaultValue

Slide 119

Slide 119 text

class Person(val name: String = "Joe") val proto = classData.classProto val constr = proto.constructorList.find { it.isPrimary } val nameParam = constr.valueParameterList[0] val name = nameResolver.getString(nameParam.name) val mutable = proto.propertyList[0].isVar val nullable = nameParam.type.nullable val hasDefault = nameParam.declaresDefaultValue

Slide 120

Slide 120 text

class Person(val name: String = "Joe") val proto = classData.classProto val constr = proto.constructorList.find { it.isPrimary } val nameParam = constr.valueParameterList[0] val name = nameResolver.getString(nameParam.name) val mutable = proto.propertyList[0].isVar val nullable = nameParam.type.nullable val hasDefault = nameParam.declaresDefaultValue

Slide 121

Slide 121 text

kotlin-metadata

Slide 122

Slide 122 text

kotlinx-metadata

Slide 123

Slide 123 text

kotlinx-metadata https://github.com/JetBrains/kotlin/tree/master/libraries/kotlinx-metadata/jvm

Slide 124

Slide 124 text

kotlinx-metadata? https://github.com/JetBrains/kotlin/tree/master/libraries/kotlinx-metadata/jvm

Slide 125

Slide 125 text

kotlinx-metadata? https://github.com/JetBrains/kotlin/tree/master/libraries/kotlinx-metadata/jvm https://github.com/square/moshi/pull/642

Slide 126

Slide 126 text

Case Studies

Slide 127

Slide 127 text

copydynamic https://github.com/hzsweers/copydynamic

Slide 128

Slide 128 text

–Chris Banes, somewhere online once upon a time “I wish I could use copy but like, conditionally set properties”

Slide 129

Slide 129 text

data class Taco( val seasoning: Set, val isBreakfast: Boolean )a

Slide 130

Slide 130 text

data class Taco( val seasoning: Set, val isBreakfast: Boolean )a val taco = Taco(setOf("el paso"), true)

Slide 131

Slide 131 text

data class Taco( val seasoning: Set, val isBreakfast: Boolean )a val taco = Taco(setOf("el paso"), true) val newTaco = taco.copyDynamic({ if (isBreakfastTime) { isBreakfast = true } }

Slide 132

Slide 132 text

class TacoDynamicBuilder constructor( private val source: Taco) { var seasoning: Set = source.seasoning var isBreakfast: Boolean = source.isBreakfast fun build(): Taco = source.copy(seasoning, isBreakfast) }a fun Taco.copyDynamic( copyBlock: TacoDynamicBuilder.() -> Unit): Taco { return TacoDynamicBuilder(this) .also { copyBlock(it) } .build() }b

Slide 133

Slide 133 text

class TacoDynamicBuilder constructor( private val source: Taco) { var seasoning: Set = source.seasoning var isBreakfast: Boolean = source.isBreakfast fun build(): Taco = source.copy(seasoning, isBreakfast) }a fun Taco.copyDynamic( copyBlock: TacoDynamicBuilder.() -> Unit): Taco { return TacoDynamicBuilder(this) .also { copyBlock(it) } .build() }b

Slide 134

Slide 134 text

class TacoDynamicBuilder constructor( private val source: Taco) { var seasoning: Set = source.seasoning var isBreakfast: Boolean = source.isBreakfast fun build(): Taco = source.copy(seasoning, isBreakfast) }a fun Taco.copyDynamic( copyBlock: TacoDynamicBuilder.() -> Unit): Taco { return TacoDynamicBuilder(this) .also { copyBlock(it) } .build() }b

Slide 135

Slide 135 text

data class Taco( val seasoning: Set, val isBreakfast: Boolean )a

Slide 136

Slide 136 text

@CopyDynamic data class Taco( val seasoning: Set, val isBreakfast: Boolean )aa

Slide 137

Slide 137 text

@CopyDynamic data class Taco( val seasoning: Set, val isBreakfast: Boolean )aa •Read the proto off Taco •Ensure it's a data class •Find constructor •Get all params + matching properties •Generate with KotlinPoet

Slide 138

Slide 138 text

@CopyDynamic data class Taco( val seasoning: Set, val isBreakfast: Boolean )a •Read the proto off Taco •Ensure it's a data class •Find constructor •Get all params + matching properties •Generate with KotlinPoet

Slide 139

Slide 139 text

@CopyDynamic data class Taco( val seasoning: Set, val isBreakfast: Boolean )a •Read the proto off Taco •Ensure it's a data class •Find constructor •Get all params + matching properties •Generate with KotlinPoet

Slide 140

Slide 140 text

@CopyDynamic data class Taco( val seasoning: Set, val isBreakfast: Boolean )a •Read the proto off Taco •Ensure it's a data class •Find constructor •Get all params + matching properties •Generate with KotlinPoet

Slide 141

Slide 141 text

@CopyDynamic data class Taco( val seasoning: Set, val isBreakfast: Boolean )a •Read the proto off Taco •Ensure it's a data class •Find constructor •Get all params + matching properties •Generate with KotlinPoet

Slide 142

Slide 142 text

@CopyDynamic data class Taco( val seasoning: Set, val isBreakfast: Boolean )a •Read the proto off Taco •Ensure it's a data class •Find constructor •Get all params + matching properties •Generate with KotlinPoet

Slide 143

Slide 143 text

@CopyDynamic data class Taco( val seasoning: Set, val isBreakfast: Boolean )a •Read the proto off Taco •Ensure it's a data class •Find constructor •Get all params + matching properties •Generate with KotlinPoet "kapt.kotlin.generated"

Slide 144

Slide 144 text

Moshi https://github.com/square/moshi API overview blog post: https://goo.gl/dRjqFb

Slide 145

Slide 145 text

Guidelines

Slide 146

Slide 146 text

Metadata is added signal

Slide 147

Slide 147 text

Abstract your renderer

Slide 148

Slide 148 text

Be mindful of mixed source sets

Slide 149

Slide 149 text

Lean on language features

Slide 150

Slide 150 text

Be mindful of quirks and caveats

Slide 151

Slide 151 text

Quirks & Caveats • Not public yet

Slide 152

Slide 152 text

Quirks & Caveats • Not public yet • Not incremental

Slide 153

Slide 153 text

Quirks & Caveats • Not public yet • Not incremental • No multiplatform

Slide 154

Slide 154 text

Quirks & Caveats • Not public yet • Not incremental • No multiplatform • (Kapt) No multiple rounds*

Slide 155

Slide 155 text

Quirks & Caveats • Not public yet • Not incremental • No multiplatform • (Kapt) No multiple rounds* • (Kapt) Varying build system support

Slide 156

Slide 156 text

Quirks & Caveats • Not public yet • Not incremental • No multiplatform • (Kapt) No multiple rounds* • (Kapt) Varying build system support

Slide 157

Slide 157 text

–you? “I have a processor and want to support kotlin today! What should I use?”

Slide 158

Slide 158 text

“I have a processor and want to support kotlin today! What should I use?” “kotlin-metadata, probably”

Slide 159

Slide 159 text

“I have a processor and want to support kotlin today! What should I use?” “kotlin-metadata, probably” “and KotlinPoet”

Slide 160

Slide 160 text

Thanks! • kotlin-metadata: github.com/takhion/kotlin-metadata • kotlinx-metadata: https://github.com/JetBrains/kotlin/tree/master/ libraries/kotlinx-metadata/jvm • Moshi: github.com/square/moshi • Km API prototype: github.com/square/moshi/pull/642 • CopyDynamic: github.com/hzsweers/copydynamic • FR for value type API: youtrack.jetbrains.com/issue/KT-26602 • Multiple rounds demo: github.com/Takhion/generate-kotlin-multiple-rounds • redacted compiler plugin: github.com/hzsweers/redacted-compiler-plugin • KotlinPoet: github.com/square/kotlinpoet

Slide 161

Slide 161 text

Thanks! Special thanks to Eugenio Marletti (@workingkills)

Slide 162

Slide 162 text

Thanks! Zac Sweers @pandanomic