Skip to content

[Koin Kotlin Compiler Plugin] [Preview]Β #2333

@arnaudgiuliani

Description

@arnaudgiuliani

Hello all πŸ‘‹

I'm pleased to share a new upcoming part in Koin project: Koin Kotlin Compiler Plugin!

A Kotlin Compiler Plugin for Koin with automatic constructor injection. Write single<MyService>() instead of singleOf(::MyService) or single { MyService(get(), get()) } β€” the plugin handles the wiring at compile-time.

A native Kotlin Compiler Plugin that replaces the KSP compiler in Koin Annotations. Use @Singleton/@factory annotations (and others) β€” all resolved at compile-time by the Kotlin compiler, no KSP required.

Note: this note will be updated to keep you posted with the latest info, and let you help us test the latest Koin Plugin version πŸ‘

Koin DSL & Annotations will get updates, thanks to the new plugin.

Here is an overview of what's coming πŸ‘‡


Part 1: DSL Transformations

Write concise DSL, get optimized code:

single<MyService>()
// or 
single(::MyService)
// Transformed to β†’ single { MyService(get(), get()) }

Supported DSL Functions

Function Receiver Description
single(::T) / single() Module Singleton definition
factory(::T) / factory() Module Factory definition
viewModel(::T) / viewModel() Module ViewModel definition
scoped(::T) / scoped() ScopeDSL Scoped definition
create(::T) Scope Create instance in scope

Syntax Styles

Constructor reference:

single(::MyService)
factory(::MyRepository)
viewModel(::MyViewModel)

Type parameter (even simpler!):

single<MyService>()
factory<MyRepository>()
viewModel<MyViewModel>()

Function reference:

fun createService(repo: Repository, config: Config? = null) = MyService(repo, config)
single(::createService)

With options:

single<MyService>() withOptions { createdAtStart() }

Interface binding:

// don't expose implementation
single<MyInterface> { create(::MyInterfaceImpl) }
// or with bind
single<MyInterfaceImpl>() bind MyInterface::class

Scoped definitions:

// works with all scopes and scope archetypes
scope(named("myScope")) {
  scoped<SessionManager>()
  factory<ScopedFactory>()
}

Smart Parameter Resolution

Parameter Type Generated Code
val repo: Repository get()
val config: Config? = null getOrNull()
val lazy: Lazy inject()
@nAmed("prod") val db: Database get(named("prod"))
@InjectedParam val id: Int it.get()

(No need of named() written manually)

DSL Example

val appModule = module {
  single<ApiClient>()
  single(::Repository)
  factory<GetUserUseCase>()
  viewModel<UserViewModel>()

  scope(named("session")) {
      scoped<SessionManager>()
  }
}

startKoin {
  modules(appModule)
}

Part 2: Annotation-Driven Configuration

Define your dependency graph declaratively with annotations.

Class Annotations

Annotation Effect
@singleton Generates single()
@factory Generates factory()
@KoinViewModel Generates viewModel()
@Scoped Generates scoped()
@scope(T::class) Associates with scope
@nAmed("qualifier") Adds qualifier to definition

Module Annotations

Annotation Effect
@module Marks class as module container
@componentscan Auto-scans package for annotated classes
@module(includes = [...]) Includes other modules
@configuration Enables cross-module discovery

Parameter Annotations

Annotation Effect
@nAmed("qualifier") Injects with qualifier
@InjectedParam Gets value from parametersOf()

Annotation Example

@Module(includes = [NetworkModule::class])
@ComponentScan
class AppModule {
  @Singleton
  fun provideAnalytics(repo: Repository) = Analytics(repo)
}

@Singleton
class Repository(val api: ApiClient)

@Factory
class GetUserUseCase(val repo: Repository)

@KoinViewModel
class UserViewModel(val useCase: GetUserUseCase) : ViewModel()

@Scope(UserSession::class)
@Scoped
class UserPreferences

Application Boostrap & Modules

@KoinApplication(modules = [AppModule::class])
object MyApp

fun main() {
  // Start Koin with "MyApp" configuration, loading all associated modules
  startKoin<MyApp> {
      printLogger()
  }
}

Cross-Module Discovery with @configuration

Modules marked with @configuration are automatically discovered across project dependencies:

// feature-module
@Module @ComponentScan @Configuration
class FeatureModule

@Singleton
class FeatureService

// app-module (depends on feature-module)
@KoinApplication  // No explicit modules needed!
object MyApp

fun main() {
  startKoin<MyApp> { }
  // FeatureService is available - FeatureModule was auto-discovered!
}

Part 3: Compile Safety

for both Koin DSL & Annotations!


What's Coming

  • Plugin available on Maven Central (soon)
  • worker() for Android WorkManager
  • Compile-time dependency graph validation
  • full cover of Koin Annotations scope

Feedback will be Welcome!

This is an early preview. We'd love your feedback on the API design and edge cases you encounter.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions