Annotation Processing in a Kotlin World Zac Sweers @pandanomic - - PowerPoint PPT Presentation

annotation processing in a kotlin world
SMART_READER_LITE
LIVE PREVIEW

Annotation Processing in a Kotlin World Zac Sweers @pandanomic - - PowerPoint PPT Presentation

Annotation Processing in a Kotlin World Zac Sweers @pandanomic Annotation Processing in a Kotlin World https://goo.gl/rSHTn4 Annotation Processing in a Kotlin World Annotation Processing in a Kotlin World Annotation Processing in a


slide-1
SLIDE 1

Annotation Processing in a Kotlin World

Zac Sweers @pandanomic

slide-2
SLIDE 2

Annotation Processing in a Kotlin World

slide-3
SLIDE 3

https://goo.gl/rSHTn4

slide-4
SLIDE 4
slide-5
SLIDE 5

Annotation Processing in a Kotlin World

slide-6
SLIDE 6

Annotation Processing in a Kotlin World

slide-7
SLIDE 7

Annotation Processing in a Kotlin World

slide-8
SLIDE 8

Dagger

@Inject @Qualifier

slide-9
SLIDE 9

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

slide-10
SLIDE 10

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

slide-11
SLIDE 11

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

slide-12
SLIDE 12

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

🤕

slide-13
SLIDE 13

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

slide-14
SLIDE 14

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

slide-15
SLIDE 15

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

slide-16
SLIDE 16

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

slide-17
SLIDE 17

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

slide-18
SLIDE 18

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

slide-19
SLIDE 19

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

slide-20
SLIDE 20

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

slide-21
SLIDE 21

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

slide-22
SLIDE 22

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

slide-23
SLIDE 23

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

slide-24
SLIDE 24

Quick refresher

slide-25
SLIDE 25

Quick refresher

  • Compile time
slide-26
SLIDE 26

Quick refresher

  • Compile time
  • Since Java 5ish (APIs in Java 6)
slide-27
SLIDE 27

Quick refresher

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

format

slide-28
SLIDE 28

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

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

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

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

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

class Person(val name: String)

slide-34
SLIDE 34 @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

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

class Person(val name: String)

slide-37
SLIDE 37

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

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

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

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

slide-41
SLIDE 41

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

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

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

class Person(val names: List<String>)

slide-45
SLIDE 45

class Person(val names: List<String>) public Person(@NotNull List<String> names)

slide-46
SLIDE 46

class Person(val names: MutableList<String>)

public Person(@NotNull List<String> names)

slide-47
SLIDE 47

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 @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 @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

annotation class Metadata( )a

slide-51
SLIDE 51

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

slide-52
SLIDE 52

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

slide-53
SLIDE 53

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

slide-54
SLIDE 54

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

slide-55
SLIDE 55

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

slide-56
SLIDE 56

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

slide-57
SLIDE 57 @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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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
slide-70
SLIDE 70
slide-71
SLIDE 71
slide-72
SLIDE 72
slide-73
SLIDE 73

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

slide-74
SLIDE 74

"Reading information from an annotation, you say?"

slide-75
SLIDE 75

Compiler Plugins

slide-76
SLIDE 76

Compiler Plugins

  • Faster/incremental
slide-77
SLIDE 77

Compiler Plugins

  • Faster/incremental
  • No stubs generation
slide-78
SLIDE 78

Compiler Plugins

  • Faster/incremental
  • No stubs generation
  • No kapt
slide-79
SLIDE 79

Compiler Plugins

  • Faster/incremental
  • No stubs generation
  • No kapt
slide-80
SLIDE 80

BUT!

slide-81
SLIDE 81

BUT!

slide-82
SLIDE 82

BUT!

  • Undocumented and not stable
slide-83
SLIDE 83

BUT!

  • Undocumented and not stable
  • Only applies to Kotlin sources
slide-84
SLIDE 84

BUT!

  • Undocumented and not stable
  • Only applies to Kotlin sources
  • Tooling can be painful
slide-85
SLIDE 85

BUT!

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

plugin

slide-86
SLIDE 86

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

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

"Reading information from an annotation, you say?"

slide-89
SLIDE 89

kotlin-metadata

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

slide-90
SLIDE 90

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

slide-91
SLIDE 91

val Element.kotlinMetadata: KotlinMetadata?

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

slide-92
SLIDE 92

val Element.kotlinMetadata: KotlinMetadata?

val metadata = typeElement.kotlinMetadata

slide-93
SLIDE 93

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

slide-94
SLIDE 94

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

slide-95
SLIDE 95

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

slide-96
SLIDE 96

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

slide-97
SLIDE 97
slide-98
SLIDE 98

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

slide-99
SLIDE 99

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

@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

@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

@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

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

val proto: ProtoBuf.Class = classData.classProto val constructors: List<Constructor> = proto.constructorList val properties: List<Property> = proto.propertyList val functions: List<Function> = proto.functionList

slide-105
SLIDE 105

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

slide-106
SLIDE 106

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

slide-107
SLIDE 107

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

slide-108
SLIDE 108

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

slide-109
SLIDE 109

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

slide-110
SLIDE 110

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

slide-111
SLIDE 111

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

it.isPrimary

slide-113
SLIDE 113

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

slide-114
SLIDE 114

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

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

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

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

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

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

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

kotlin-metadata

slide-122
SLIDE 122

kotlinx-metadata

slide-123
SLIDE 123

kotlinx-metadata

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

kotlinx-metadata?

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

kotlinx-metadata?

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

https://github.com/square/moshi/pull/642

slide-126
SLIDE 126

Case Studies

slide-127
SLIDE 127

copydynamic

https://github.com/hzsweers/copydynamic

slide-128
SLIDE 128

–Chris Banes, somewhere online once upon a time

“I wish I could use copy but like, conditionally set properties”

slide-129
SLIDE 129

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

slide-130
SLIDE 130

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

slide-131
SLIDE 131

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

slide-132
SLIDE 132

class TacoDynamicBuilder constructor( private val source: Taco) { var seasoning: Set<String> = 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

class TacoDynamicBuilder constructor( private val source: Taco) { var seasoning: Set<String> = 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

class TacoDynamicBuilder constructor( private val source: Taco) { var seasoning: Set<String> = 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

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

slide-136
SLIDE 136

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

slide-137
SLIDE 137

@CopyDynamic data class Taco( val seasoning: Set<String>, 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

@CopyDynamic data class Taco( val seasoning: Set<String>, 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

@CopyDynamic data class Taco( val seasoning: Set<String>, 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

@CopyDynamic data class Taco( val seasoning: Set<String>, 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

@CopyDynamic data class Taco( val seasoning: Set<String>, 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

@CopyDynamic data class Taco( val seasoning: Set<String>, 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

@CopyDynamic data class Taco( val seasoning: Set<String>, 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

Moshi

https://github.com/square/moshi

API overview blog post: https://goo.gl/dRjqFb

slide-145
SLIDE 145

Guidelines

slide-146
SLIDE 146

Metadata is added signal

slide-147
SLIDE 147

Abstract your renderer

slide-148
SLIDE 148

Be mindful of mixed source sets

slide-149
SLIDE 149

Lean on language features

slide-150
SLIDE 150

Be mindful of quirks and caveats

slide-151
SLIDE 151

Quirks & Caveats

  • Not public yet
slide-152
SLIDE 152

Quirks & Caveats

  • Not public yet
  • Not incremental
slide-153
SLIDE 153

Quirks & Caveats

  • Not public yet
  • Not incremental
  • No multiplatform
slide-154
SLIDE 154

Quirks & Caveats

  • Not public yet
  • Not incremental
  • No multiplatform
  • (Kapt) No multiple rounds*
slide-155
SLIDE 155

Quirks & Caveats

  • Not public yet
  • Not incremental
  • No multiplatform
  • (Kapt) No multiple rounds*
  • (Kapt) Varying build system support
slide-156
SLIDE 156

Quirks & Caveats

  • Not public yet
  • Not incremental
  • No multiplatform
  • (Kapt) No multiple rounds*
  • (Kapt) Varying build system support
slide-157
SLIDE 157

–you?

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

slide-158
SLIDE 158

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

slide-159
SLIDE 159

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

slide-160
SLIDE 160

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

Thanks!

Special thanks to Eugenio Marletti (@workingkills)

slide-162
SLIDE 162

Thanks!

Zac Sweers @pandanomic