Annotation Processing in a Kotlin World
Zac Sweers @pandanomic
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
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 Kotlin World
Dagger
@Inject @Qualifier
@Provides fun provideList(): List<Taco> { return emptyList() }a
@Provides fun provideList(): List<Taco> { return emptyList() }a @Inject lateinit var tacoList: List<Taco>
@Provides fun provideList(): List<Taco> { return emptyList() }a @Inject lateinit var tacoList: List<@SuppressJvmWildcard Taco>
@Provides fun provideList(): List<Taco> { return emptyList() }a @Inject lateinit var tacoList: List<@SuppressJvmWildcard Taco>
@Provides fun provideTaco(): Taco { return BreakfastTaco() }a @Inject lateinit var taco: Taco
@Breakfast @Provides fun provideTaco(): Taco { return BreakfastTaco() }a @Breakfast @Inject lateinit var taco: Taco
@Breakfast @Provides fun provideTaco(): Taco { return BreakfastTaco() }a @field:Breakfast @Inject lateinit var taco: Taco
@Breakfast @Provides fun provideTaco(): Taco { return BreakfastTaco() }a @field:Breakfast @Inject lateinit var taco: Taco 🤕
@Module class NetworkModule { @Provides static HttpClient provideHttpClient() { return HttpClient.create(); }a }b
@Module class NetworkModule { @Provides static HttpClient provideHttpClient() { return HttpClient.create(); }a companion object { }c }b
@Module class NetworkModule { companion object { @Provides fun provideHttpClient(): HttpClient { return HttpClient.create() }a }c }b
@Module class NetworkModule { companion object { @JvmStatic @Provides fun provideHttpClient(): HttpClient { return HttpClient.create() }a }c }b
@Module class NetworkModule { @Module companion object { @JvmStatic @Provides fun provideHttpClient(): HttpClient { return HttpClient.create() }a }c }b
@Module class NetworkModule { @Module companion object { @JvmStatic @Provides fun provideHttpClient(): HttpClient { return HttpClient.create() }a }c }b
@Module class NetworkModule { @Module companion object { @JvmStatic @Provides fun provideHttpClient(): HttpClient { return HttpClient.create() }a }c }b
Quick refresher
Quick refresher
Quick refresher
Quick refresher
format
Quick refresher
format
Quick refresher
format
Quick refresher
Quick refresher
Quick refresher
class Person(val name: String)
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(); } }
class Person(val name: String)
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
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
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
class Person(val name: String = "Joe")
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
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
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
class Person(val names: List<String>)
class Person(val names: List<String>) public Person(@NotNull List<String> names)
class Person(val names: MutableList<String>)
public Person(@NotNull List<String> names)
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(); } }
annotation class Metadata( )a
annotation class Metadata( val k: Int = 1 )a
annotation class Metadata( val k: Int = 1, val mv: IntArray = [] )a
annotation class Metadata( val k: Int = 1, val mv: IntArray = [], val bv: IntArray = [] )a
annotation class Metadata( val k: Int = 1, val mv: IntArray = [], val bv: IntArray = [], val d1: Array<String> = [] )a
annotation class Metadata( val k: Int = 1, val mv: IntArray = [], val bv: IntArray = [], val d1: Array<String> = [], val d2: Array<String> = [] )a
internal annotation class Metadata( val k: Int = 1, val mv: IntArray = [], val bv: IntArray = [], val d1: Array<String> = [], val d2: Array<String> = [] )a
@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
@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
@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
@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
@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
@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
@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
@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
@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
@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
@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
val metadata = typeElement.getAnnotation(Metadata::class.java)
"Reading information from an annotation, you say?"
Compiler Plugins
Compiler Plugins
Compiler Plugins
Compiler Plugins
Compiler Plugins
BUT!
BUT!
BUT!
BUT!
BUT!
plugin
BUT!
plugin
a Kotlin
BUT!*
plugin
a Kotlin
"Reading information from an annotation, you say?"
kotlin-metadata
https://github.com/takhion/kotlin-metadata
val metadata = typeElement.getAnnotation(Metadata::class.java)
val Element.kotlinMetadata: KotlinMetadata?
val metadata = typeElement.getAnnotation(Metadata::class.java)
val Element.kotlinMetadata: KotlinMetadata?
val metadata = typeElement.kotlinMetadata
when (typeElement.kotlinMetadata) { is KotlinPackageMetadata -> is KotlinClassMetadata -> is KotlinFileMetadata -> is KotlinMultiFileClassPartMetadata -> is KotlinMultiFileClassFacadeMetadata -> is KotlinSyntheticClassMetadata -> is KotlinUnknownMetadata -> }a
when (typeElement.kotlinMetadata) { is KotlinClassMetadata -> }a
when (metadata) { is KotlinClassMetadata -> { val classData: ClassData = metadata.data }a }b
when (metadata) { is KotlinClassMetadata -> { val classData: ClassData = metadata.data val proto: ProtoBuf.Class = classData.classProto }a }b
when (metadata) { is KotlinClassMetadata -> { val classData: ClassData = metadata.data val proto: ProtoBuf.Class = classData.classProto }a }b
when (metadata) { is KotlinClassMetadata -> { val classData: ClassData = metadata.data val proto: ProtoBuf.Class = classData.classProto val nameResolver = classData.nameResolver }a }b
@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
@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
@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
when (metadata) { is KotlinClassMetadata -> { val classData: ClassData = metadata.data val proto: ProtoBuf.Class = classData.classProto val nameResolver = classData.nameResolver }a }b
val proto: ProtoBuf.Class = classData.classProto val constructors: List<Constructor> = proto.constructorList val properties: List<Property> = proto.propertyList val functions: List<Function> = proto.functionList
class Person(val name: String = "Joe")
class Person(val name: String = "Joe") val name = TODO()
class Person(val name: String = "Joe") val name = TODO() val mutable = TODO()
class Person(val name: String = "Joe") val name = TODO() val mutable = TODO() val nullable = TODO()
class Person(val name: String = "Joe") val name = TODO() val mutable = TODO() val nullable = TODO() val hasDefault = TODO()
class Person(val name: String = "Joe") val name = TODO() val mutable = TODO() val nullable = TODO() val hasDefault = TODO()
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()
it.isPrimary
val Constructor.isPrimary: Boolean get() { return !Flags.IS_SECONDARY[flags] }
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()
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()
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()
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
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
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
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
kotlin-metadata
kotlinx-metadata
kotlinx-metadata
https://github.com/JetBrains/kotlin/tree/master/libraries/kotlinx-metadata/jvmkotlinx-metadata?
https://github.com/JetBrains/kotlin/tree/master/libraries/kotlinx-metadata/jvmkotlinx-metadata?
https://github.com/JetBrains/kotlin/tree/master/libraries/kotlinx-metadata/jvmhttps://github.com/square/moshi/pull/642
Case Studies
copydynamic
https://github.com/hzsweers/copydynamic
–Chris Banes, somewhere online once upon a time
“I wish I could use copy but like, conditionally set properties”
data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )a
data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )a val taco = Taco(setOf("el paso"), true)
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 } }
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
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
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
data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )a
@CopyDynamic data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )aa
@CopyDynamic data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )aa
@CopyDynamic data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )a
@CopyDynamic data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )a
@CopyDynamic data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )a
@CopyDynamic data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )a
@CopyDynamic data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )a
@CopyDynamic data class Taco( val seasoning: Set<String>, val isBreakfast: Boolean )a
"kapt.kotlin.generated"
Moshi
https://github.com/square/moshi
API overview blog post: https://goo.gl/dRjqFb
Guidelines
Metadata is added signal
Abstract your renderer
Be mindful of mixed source sets
Lean on language features
Be mindful of quirks and caveats
Quirks & Caveats
Quirks & Caveats
Quirks & Caveats
Quirks & Caveats
Quirks & Caveats
Quirks & Caveats
–you?
“I have a processor and want to support kotlin today! What should I use?”
“I have a processor and want to support kotlin today! What should I use?” “kotlin-metadata, probably”
“I have a processor and want to support kotlin today! What should I use?” “kotlin-metadata, probably” “and KotlinPoet”
Thanks!
libraries/kotlinx-metadata/jvm
Thanks!
Special thanks to Eugenio Marletti (@workingkills)
Thanks!
Zac Sweers @pandanomic