| # KSP Hello World Example |
| |
| This project is a minimal, self-contained KSP project. |
| |
| It configures KSP via its Gradle plugin as one would normally do, |
| in the hopes of providing an example that a new user can read and learn from. |
| |
| The project has three subprojects: |
| - `annotations`: This subproject defines the `HelloWorld` annotation. By keeping annotations in a separate |
| module, we avoid leaking the processor's implementation or the KSP API to the app's runtime. |
| - `processor`: This subproject defines a minimal processor that selects functions annotated with |
| `HelloWorld` and generates a function that prints a message. |
| - `app`: This subproject defines a single `main` that calls the generated function. |
| The `main` function is annotated with `HelloWorld` to trigger the processor. |
| |
| ## Key Concepts |
| |
| While this is a minimal example, it demonstrates several core KSP mechanisms that are essential to |
| understand: |
| |
| ### Selecting Functions to Process |
| |
| The processor's entry point is the `process` method, which receives a `Resolver`. |
| The `Resolver` type is the primary tool for querying the KSP's view of the source code. |
| |
| In `HelloWorldProcessor.kt`, we use: |
| - `resolver.getSymbolsWithAnnotation(...)`: To find all symbols annotated with our fully qualified |
| annotation name (`com.example.annotations.HelloWorld`). |
| - `.filterIsInstance<KSFunctionDeclaration>()`: Since our processor is designed to work on |
| functions, we filter the results to ensure we are only dealing with function declarations. |
| |
| Once filtered, we use the **Visitor Pattern** (`it.accept(HelloWorldVisitor(), Unit)`) to perform the actual code generation. This is the recommended way to traverse the KSP AST (Abstract Syntax Tree). |
| |
| Note the file in `processor/src/main/resources/META-INF/services/`. |
| It contains the fully qualified name of the `SymbolProcessorProvider` implementation. |
| Without this, KSP will not know your processor exists. |
| |
| ### Generating Code |
| |
| Using the selected function in the `HelloWorldVisitor`, we can create a new file and write directly |
| to it like any other output stream. |
| |
| ### Dependency Management |
| |
| In `app/build.gradle.kts`, notice how the dependencies are split: |
| - `implementation(project(":annotations"))`: Gives the app access to the `HelloWorld` annotation |
| definition. |
| - `ksp(project(":processor"))`: Tells the KSP plugin to run the processor during compilation. |
| |
| The separation ensures the processor's code only exists during the build phase and isn't bundled |
| into your final application. |
| Note in `processor/build.gradle.kts` that the processor also depends on the annotations project with |
| `implementation(project(":annotations"))`. |
| |
| ### Inspecting Generated Code |
| |
| You can find the source code generated by this processor in the build directory of the app: |
| `app/build/generated/ksp/main/kotlin/GeneratedHelloWorld.kt` |
| |
| ## Further Reading |
| |
| Visit the [KSP documentation](https://kotlinlang.org/docs/ksp-overview.html) for more information. |