KAPT vs KSP

In this blog, we'll dive into the details of KAPT vs KSP, comparing their performance, ease of use, and how you can use them in your Android projects. By the end, you'll understand which tool is better suited for your needs, and how you can implement them in your codebase effectively.

What is Annotation Processing?

Annotation processing is a technique used to process annotations in code. It allows tools to generate additional code or resources at compile-time, saving developers from manually writing boilerplate code. This is especially useful in Android development, where libraries like Room, Dagger, and Retrofit heavily rely on annotations to generate code dynamically.

KAPT and KSP are both designed to help with annotation processing in Kotlin, but they do so in different ways, which we'll explore now.

KAPT (Kotlin Annotation Processing Tool)

KAPT is a Kotlin-specific extension for Java's Annotation Processing Tool (APT). It allows Kotlin code to be processed by Java annotation processors, which means you can use Java-based annotation processors with Kotlin code. However, since Kotlin and Java have different compilation models, KAPT works by converting Kotlin code into Java code behind the scenes and then applying Java annotation processors.

How KAPT Works

KAPT essentially works by:

  1. Translating the Kotlin code into Java stubs.

  2. Running Java annotation processors (like Dagger, Room, etc.) on the generated Java stubs.

  3. Generating the required code based on the annotations.

Example of Using KAPT

Let’s use Dagger as an example, a popular dependency injection library that uses annotations. Here’s how you would typically set up Dagger with KAPT:

  1. Add KAPT and Dagger dependencies in your build.gradle:

dependencies {
    implementation "com.google.dagger:dagger:2.40.5"
    kapt "com.google.dagger:dagger-compiler:2.40.5"
}
  1. Create your annotated classes:

// UserService.kt
class UserService @Inject constructor(private val api: Api) {
    fun getUser() {
        // Logic to fetch user
    }
}
  1. Create a component interface:

@Component
interface AppComponent {
    fun inject(activity: MainActivity)
}
  1. In your MainActivity:

class MainActivity : AppCompatActivity() {

    @Inject lateinit var userService: UserService

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        (applicationContext as MyApp).appComponent.inject(this)
    }
}

With KAPT, the annotation processing happens during the build time and generates the necessary code for Dagger’s dependency injection to work.

Drawbacks of KAPT

  • Slow Build Times: KAPT can slow down build times significantly, especially in large projects, as it relies on Java's annotation processing tools, which are not optimized for Kotlin.

  • Java Stubs: Since KAPT generates Java stubs, it often leads to mismatches between the Kotlin code and the generated stubs, potentially introducing bugs.

  • Memory Consumption: KAPT's need to hold the entire Kotlin code in memory during processing can increase memory consumption, further impacting performance.

KSP (Kotlin Symbol Processing)

KSP is a newer tool introduced by Google for Kotlin, designed to overcome the limitations of KAPT. KSP works directly with Kotlin code and its abstract syntax tree (AST) without needing to convert it into Java stubs, making it faster and more memory efficient.

How KSP Works

Unlike KAPT, which works by generating Java stubs and using Java annotation processors, KSP directly processes Kotlin symbols (classes, functions, properties, etc.) without needing any intermediate Java code. This makes KSP faster and more efficient.

Example of Using KSP

Let’s demonstrate KSP with a simple annotation processor that generates a custom toJson function for data classes.

  1. Add KSP dependencies in your build.gradle:

dependencies {
    implementation "com.google.devtools.ksp:symbol-processing-api:1.0.0"
    ksp "com.example:my-ksp-processor:1.0.0"
}
  1. Define an annotation:

@Target(AnnotationTarget.CLASS)
annotation class ToJson
  1. Create a symbol processor to generate the toJson function:

@SymbolProcessor
class ToJsonProcessor : SymbolProcessor {
    override fun process(resolver: SymbolProcessorResolver) {
        resolver.getSymbolsWithAnnotation(ToJson::class.java.name)
            .forEach { symbol ->
                if (symbol is KSClassDeclaration) {
                    generateToJson(symbol)
                }
            }
    }

    private fun generateToJson(symbol: KSClassDeclaration) {
        // Logic to generate the toJson method
    }
}
  1. Apply the annotation on a data class:

@ToJson
data class User(val name: String, val age: Int)

KSP processes this class and generates a toJson method for the User class, reducing boilerplate code.

Advantages of KSP

  • Better Performance: Since KSP works directly with Kotlin code and its symbols, it performs faster than KAPT, particularly in large projects.

  • Low Memory Consumption: KSP is optimized for Kotlin, leading to lower memory usage and faster execution.

  • Better Integration with Kotlin: KSP works natively with Kotlin, so it’s more reliable when it comes to handling Kotlin-specific features like coroutines, nullability, and data classes.

Drawbacks of KSP

  • Limited Support for Java Libraries: KSP is Kotlin-specific, so it can't work with Java annotation processors. This limits the immediate use of libraries like Dagger or Room that rely on Java-based processors. However, this is improving, as Google continues to update KSP.

When to Use KAPT

  • If you are using libraries like Dagger, Room, or Retrofit that rely on Java-based annotation processors, KAPT is your go-to choice. If KSP support is available, then use KSP

  • If your project has significant dependencies on Java-based libraries, KAPT remains the default option.

When to Use KSP

  • If you are building Kotlin-specific annotation processors or working on new libraries that don't rely on Java-based processors, KSP is the better choice.

  • If you need better performance and memory usage, especially in large Kotlin projects, KSP will significantly reduce build times.

Conclusion

In summary, while KAPT is a tried and tested solution for annotation processing in Kotlin, KSP is a more modern, faster, and more memory-efficient alternative that is optimized for Kotlin. If you are starting a new Kotlin-based project or creating your own annotation processor, KSP is the way to go. On the other hand, if you rely on established Java-based annotation processors, KAPT is still the tool of choice.

Akshay Nandwana
Founder AndroidEngineers

You can connect with me on:


Book 1:1 Session here
Click Here

Join our upcoming classes
https://www.androidengineers.in/courses

Love from our past students

Excellent list of questions really helped me to coverup all the topics before interview.

Saiteja Janjirala

10th Oct, 2024

I had an exceptional experience with the 1:1 mentorship session. Akshay was incredibly friendly and provided invaluable guidance on focusing on long-term goals. They also gave great interview tips, including a thorough resume review. Additionally, the discussion on Data Structures and Algorithms (DSA) was insightful and practical. Highly recommended for anyone looking to advance their career!

Nayab khan

11th Sep, 2024

Cleared my major points for what I am missing in the resume and also suggested what I can work on for further growth in the career.

Ketan Chaurasiya

7th Aug, 2024

What impressed me most was his personalized approach and practical tips that I could immediately apply. Akshay’s guidance not only improved my technical skills but also boosted my confidence in navigating my career path. His insights and encouragement have been a game-changer for me. I highly recommend Akshay’s mentorship to anyone looking to advance their Android development career.

Hardik Kubavat

5th Aug, 2024

2025© Made with   by Android Engineers.