Slide 1

Slide 1 text

Android Code Generation with Kotlin Symbol Processing (KSP) Kotlin Symbol Processing

Slide 2

Slide 2 text

Kotlin Symbol Processing is a tool that allows developer to write custom code generators for Kotlin Kotlin Poet is a popular library that helps in generating Kotlin code programmatically. What is KSP? What is Kotlin Poet In this slide, we will learn how to set up KSP with Kotlin Poet for code generation in an Android project. Where’re we going? Introduction to KSP KSP #

Slide 3

Slide 3 text

Headline goes here KSP # 01 Familiar with Android Annotation 02 Processor, Symbols & Visitor in KSP (Interfaces) 03 Dependency Structure for KSP 04 Deep Dive Into Code

Slide 4

Slide 4 text

Brief description of annotation Familiar with Annotation Section 01

Slide 5

Slide 5 text

5 Annotation in Android development are code elements marked with "@" that associate metadata with other code elements. They help convey information and can be used for automatic source code generation through annotation processing. This can reduce boilerplate code, and enhances code functionality and readability. Annotation Annotation #

Slide 6

Slide 6 text

Addressing to KSP Processor Processor, Symbols & Visitor in KSP (Interfaces) Section 02

Slide 7

Slide 7 text

Entry point of KSP Analyze and dynamically code generate SymbolProcessor Provider SymbolProcessor Symbol Custom KSVisitor for SymbolProcessor Visitor Processor, Symbols & Visitor in KSP KSP #

Slide 8

Slide 8 text

SymbolProcessorProvider Processor in KSP # interface used by plugins to integrate into Kotlin Symbol Processing It contains current information about current compilation session and has communication with Kotlin Compiler Called by Kotlin Symbol Processing to create the processor

Slide 9

Slide 9 text

SymbolProcessor Processor in KSP # Main component for symbol processing in KSP such as class , field, property and annotation symbol analyze and manipulate these symbols during compilation process provides information about the symbol being processed, such as its name, kind (class, function, property, etc.), annotations, modifiers, etc

Slide 10

Slide 10 text

KSVisitor Visitor in KSP # Main component for symbol processing in KSP such as class , field, property and annotation symbol analyze and manipulate these symbols during compilation process provides information about the symbol being processed, such as its name, kind (class, function, property, etc.), annotations, modifiers, etc

Slide 11

Slide 11 text

Overall dependency structure Dependency Structure for KSP Section 03

Slide 12

Slide 12 text

● Annotation: This holds your annotation class. ● Processor: This contains KSP code generation logic. ● App: This is the Android app that consumes the generated files. Three Modules KSP #

Slide 13

Slide 13 text

How to create modules Create new two modules 1. annotation 2. processor in enumKSP module as shown in picture below

Slide 14

Slide 14 text

Step by Step code generation Deep Dive into code Section 04

Slide 15

Slide 15 text

Add KSP plugin Kotlin DSLG plugins { id("com.google.devtools.ksp") version "1.8.10-1.0.9" apply false } plugins { id("com.google.devtools.ksp") } build.gradle.kts

Slide 16

Slide 16 text

Add KSP Symbol Processing API in build.gradle.kts in processor module implementation( "com.google.devtools.ksp:symbol-processing-api:latest-version" ) implementation("com.squareup:kotlinpoet-ksp:1.12.0") Add Kotlin Poet for code generation in build.gradle.kts in processor module Add KSP plugin

Slide 17

Slide 17 text

Generate User class into Enum code data class User( @Enum(enumConstants = [ "Male", "Female", "Other" ]) val genderType: Int = 1 )

Slide 18

Slide 18 text

@Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.PROPERTY) annotation class Enum(val enumConstants: Array) Create Annotations

Slide 19

Slide 19 text

Use case for SymbolProcessor SymbolProcessor # Using Kotlin reflect to get Sequence from Enum Annotation filter valid KSAnnotated Symbols Sequence Accept visitor from KSNode

Slide 20

Slide 20 text

process method in SymbolProcessor override fun process(resolver: Resolver): List { // Using Kotlin reflect to get class from GenerateEnum Annotation (User) val symbols = resolver.getSymbols(GenerateEnum::class) val validatedSymbols = symbols.filter { it.validate() }.toList() val visitor = EnumGenerateVisitor(logger, codeGenerator) validatedSymbols.forEach { symbol -> symbol.accept(visitor, Unit) } return emptyList() }

Slide 21

Slide 21 text

The Purpose of using KSVisitor Purpose of KSP # Code Analysis: better to find potential errors Code Generation : better code generation such as class or functions Code Refactoring : better refactoring and renaming code

Slide 22

Slide 22 text

Use case for Visitor Visitor # Get Information from declared Annotation Generate code with KotlinPoet Library File Write in auto generated code (ksp folder)

Slide 23

Slide 23 text

class EnumGenerateVisitorFromProperty( private val logger: KSPLogger, private val codeGenerator: CodeGenerator, ) : KSVisitorVoid() { private val enumClass = Enum::class.simpleName override fun visitPropertyDeclaration(property: KSPropertyDeclaration,...) { // code generate StringBuilder or Kotlin Poet Library } }

Slide 24

Slide 24 text

Get information from declared annotation KSP # Find Annotation @Enum Listing Arguments from parameters of @Enum annotation ( Male, Female, Other) Now we think logic and generate code that we want to change

Slide 25

Slide 25 text

val enumAnnotation = property.annotations.find { it.shortName.asString() == enumClass } // Get parameters (Male, Female, Other) from declare Enum annotation val listArguments = enumAnnotation?.arguments?.find { arg -> arg.name?.asString() == enumConstants }?.value as List<*> "enumConstants" "Enum::class.simpleName"

Slide 26

Slide 26 text

Code generation with KotlinPoet KotlinPoet # Code Analysis: better to find potential errors Code Generation : better code generation such as class or functions Code Refactoring : better refactoring and renaming code

Slide 27

Slide 27 text

Generate Enum class with private constructor “type” val type = FunSpec.constructorBuilder() .addParameter("type", Int::class) .build() val enumClass = TypeSpec.enumBuilder(propertyName) .primaryConstructor(type) .addProperty( PropertySpec.builder("type", Int::class) .initializer("type") .addModifiers(KModifier.PRIVATE) .build(), )

Slide 28

Slide 28 text

Generate Enum constants “MALE(0)”,“FEMALE(1)”,“OTHER(2)” listArguments.forEachIndexed { index, value -> val enumConstantValue = TypeSpec .anonymousClassBuilder() .addSuperclassConstructorParameter("%L", index) .build() addEnumConstant( value.toString().uppercase(), enumConstantValue, ).build() }

Slide 29

Slide 29 text

File write in generate file ksp val fileSpec = FileSpec.builder(packageName, propertyName).apply { addType(enumClass) }.build() fileSpec.writeTo(codeGenerator, false) "Enum::class.simpleName"

Slide 30

Slide 30 text

Resources KotlinPoet Documentation - https://square.github.io/kotlinpoet/ Medium Blog - https://medium.com/@thawzintoe/unlocking-the-art-a-guide-to-generating-code-with-kotlin -symbol-processor-26eb5760cd4b KSP API - https://kotlinlang.org/docs/ksp-overview.html CodeLab - https://github.com/thawzintoe-ptut/KSPEnumCodelab.git

Slide 31

Slide 31 text

Thank You Thaw Zin Toe (PTut) Mobile Developer - Android