Compile-time dependency injection for Kotlin Multiplatform

Overview

Maven Central License

Kinzhal

Kinzhal is a Kotlin Multiplatform library for compile-time dependency injection. The goal is to emulate basic features of Dagger to achieve similar experience in Kotlin Multiplatform projects

Kinzhal is based on Kotlin Symbol Processing (KSP) — the API for lightweight compiler plugins. You'll need to set up KSP in your project to use Kinzhal

Setup

Add KSP to your plugins section:

plugins {
    id("com.google.devtools.ksp") version "1.5.30-1.0.0"
    kotlin("multiplatform")
    // ...
}

Apply Kinzhal KSP processor:

dependencies {
    ksp("com.daugeldauge.kinzhal:kinzhal-processor:$kinzhalVersion")
}

Add compile-only kinzhal-annotations dependency to your common source set:

kotlin {    
    sourceSets {
        getByName("commonMain") {
            dependencies {
                compileOnly("com.daugeldauge.kinzhal:kinzhal-annotations:$kinzhalVersion")
                // ...
            }
        }

        // Optional workaround for intellij-based IDEs to see generated code. This probably will be fixed someday in KSP plugin.
        // You can replace `jvmName` with any of your target source sets. After the source set is built IDE will start to recognize generate code
        if (System.getProperty("idea.sync.active") != null) {
            kotlin.srcDir("$buildDir/generated/ksp/jvmMain/kotlin")
        }
    }
}

FAQ

What does kinzhal mean?

It's a russian word for dagger. Yes, K is not a pun

Will this project become deprecated after Dagger releases support for KSP and Multiplatform?

Probably. But we'll see

Examples

@AppScope
@Component(modules = [
    NetworkModule::class,
], dependencies = [
    AppDependencies::class,
])
interface AppComponent {
    fun createAuthPresenter(): AuthPresenter
}

interface AppDependencies {
    val application: Application
}

@Scope
annotation class AppScope

class Application

@AppScope
class Database @Inject constructor(application: Application)

class AuthPresenter @Inject constructor(database: Database, lastFmApi: LastFmApi)

class HttpClient

interface LastFmApi

class LastFmKtorApi @Inject constructor(client: HttpClient) : LastFmApi

interface NetworkModule {
    companion object {
        @AppScope
        fun provideHttpClient() = HttpClient()
    }

    fun bindLastFm(lastFmApi: LastFmKtorApi): LastFmApi
}

// somewhere in your app
val component = KinzhalAppComponent(object : AppDependencies {
    override val application = Application()
})

val presenter = component.createAuthPresenter()

See more in the source code

Dagger2 compatibility table

Feature Kinzhal support Notes
@Component
Constructor injection
Field injection 🚫
Component provision functions and properties
@Module ⚠️ Kinzhal has modules but does not have @Module annotation. All classes in component module list are treated as modules. Only object modules with provides=functions and interface modules with binds-functions are allowed
@Provides ⚠️ Kinzhal does not have @Provides annotation. All non-abstract functions in a module are considered to be provides-functions
@Binds ⚠️ Kinzhal does not have @Binds annotation. All abstract functions in a module are considered to be binds-functions
@Scope
@Qualifier
Component dependencies Dependency instances are passed to generated component's constructor instead of builder functions
@Subcomponent 🚫 You can use component dependency to emulate behaviour of subcomponents
@Reusable 🚫
@BindsInstance 🚫 You can use component dependency to bind instances
Lazy/provider injections 🚫
@BindsOptionalOf 🚫
Multibindings 🚫
Assisted injection 🚫
You might also like...
Learn Kotlin, easy bites at a time
Learn Kotlin, easy bites at a time

Welcome! I hope you're having an amazing day! 🚀 This repository is a reference of how I think one should approach learning kotlin step-by-step. Insid

Integration Testing Kotlin Multiplatform Kata for Kotlin Developers. The main goal is to practice integration testing using Ktor and Ktor Client Mock
Integration Testing Kotlin Multiplatform Kata for Kotlin Developers. The main goal is to practice integration testing using Ktor and Ktor Client Mock

This kata is a Kotlin multiplatform version of the kata KataTODOApiClientKotlin of Karumi. We are here to practice integration testing using HTTP stub

Kotlin-phoenix - A set of tools aimed to bridge Phoenix with the Kotlin Multiplatform world

Kotlin Phoenix This project is aimed to allow developers to work with Phoenix Ch

FlowExt is a Kotlin Multiplatform library, that provides many operators and extensions to Kotlin Coroutines Flow

FlowExt | Kotlinx Coroutines Flow Extensions | Kotlinx Coroutines Flow Extensions. Extensions to the Kotlin Flow library | kotlin-flow-extensions | Coroutines Flow Extensions | Kotlin Flow extensions | kotlin flow extensions | Flow extensions

MMKV for Kotlin Multiplatform is a wrapper for MMKV using Kotlin API

MMKV for Kotlin Multiplatform is a wrapper for MMKV using Kotlin API

Android Project to find FatMax in real time with a Polar H10
Android Project to find FatMax in real time with a Polar H10

FatMaxxer According to recent research (see below) the FatMaxxer Android app may help you to exercise at the optimum effort level for fat burning, mea

A webapp which generates a simple Discord profile banner image in real-time which shows user's status and activity.

DiscordProfileBanner This tool generates a Discord profile banner image in realtime. I wrote it for use in my AniList profile. An example in action: H

A Simple Android library to get the number of words and give you the time it will take you to finish an article/story.

MinRead A Simple Android library to get the number of words and give you the time it will take you to finish an article/story. Prerequisite Androidx K

Comments
  • Support assisted injection

    Support assisted injection

    It would be convenient with library such as Decompose. Decompose Components are created by hand in factory lambda and must be initialized with ComponentContext provided from parent.

    I'll demonstrate with example. Here what we must do with Decompose without auto DI

    class RootComponent(
        componentContext: ComponentContext
    ) : ComponentContext by componentContext {
    
        val navigation = StackNavigation<Config>()
    
        val stack =
            childStack(
                source = navigation,
                initialConfiguration = Config.List,
                handleBackButton = true,
                childFactory = ::createChild,
            )
    
        fun createChild(config: Config, componentContext: ComponentContext): ComponentContext =
            // Here we must use provided componentContext to create child component
            when (config) {
                is Config.List -> ListComponent(componentContext, ???) // Where to get depA, depB, depC, etc.???
                is Config.Details -> // ...
            }
    
        sealed class Config : Parcelable {
            @Parcelize
            object List : Config()
    
            @Parcelize
            data class Details(val itemId: Long) : Config()
        }
    }
    
    class ListComponent(
        componentContext: ComponentContext,
        depA: DepA,
        depB: DepB,
        depC: DepC,
        // ...
    ) : ComponentContext by componentContext {
        // ...
    } 
    

    We can improve this example with assisted injection like so

    class RootComponent @Inject constructor(
        componentContext: ComponentContext,
        listComponentFactory: ListComponentFactory,
        // Rest component factories
    ) : ComponentContext by componentContext {
    
        val navigation = StackNavigation<Config>()
    
        val stack =
            childStack(
                source = navigation,
                initialConfiguration = Config.List,
                handleBackButton = true,
                childFactory = ::createChild,
            )
    
        fun createChild(config: Config, componentContext: ComponentContext): ComponentContext =
            when (config) {
                is Config.List -> listComponentFactory.create(componentContext)
                is Config.Details -> // ...
            }
    }
    
    @AssistedFactory
    interface ListComponentFactory {
        fun create(componentContext: ComponentContext): ListComponent
    } 
    
    class ListComponent @AssistedInject constructor(
        @Assisted componentContext: ComponentContext,
        depA: DepA,
        depB: DepB,
        depC: DepC,
        // ...
    ) : ComponentContext by componentContext {
        // ...
    }
    
    opened by vganin 0
Releases(v0.0.4)
Owner
Artem Daugel-Dauge
Artem Daugel-Dauge
A pragmatic lightweight dependency injection framework for Kotlin developers.

A pragmatic lightweight dependency injection framework for Kotlin developers. Koin is a DSL, a light container and a pragmatic API

insert-koin.io 11 Dec 14, 2022
🍓CookHelper - food social network. The Api and Websocket are based on Ktor framework. Dependency injection with Koin library.

CookHelper [ ?? Work in Progress ?? ] CookHelper is a cross-platform application that will allow you to cook a delicious dish from an existing recipe

Arthur 11 Nov 9, 2022
Map-vs-list-comparator - The project compares the time needed to find a given element in a map vs the time needed to find a given element in a list.

Map vs List Comparator The project compares the time needed to find a given element in a map vs the time needed to find a given element in a list. To

null 0 Jan 4, 2022
Kotlin dropwizard app running on Java 11. With Guice injection loaded.

hello world How to start the hello world application Run mvn clean install to build your application Start application with java -jar target/dropwizar

null 0 Nov 24, 2021
A Zero-Dependency Kotlin Faker implementation built to leave you fully satisfied

Satisfaketion A Zero-Dependency Kotlin Faker implementation built to leave you fully satisfied ?? ... With your fake data How to Install ?? Satisfaket

Ryan Brink 7 Oct 3, 2022
This lib is the framework for dependency tasks, specially for the asynchronous tasks.

DependencyTask This lib is the framework for dependency tasks, specially for the asynchronous tasks. Backgroud Image that there is a progress with som

null 1 May 6, 2022
My own approach to what I think an Android MVVM project with Clean Architecture should look like with Dagger-Hilt as Dependency Injector engine

MVVM Project Hilt Introducción Este proyecto es mi visión particular, ni mejor ni peor (sólo una más) que cualquier otra aproximación a lo que yo enti

Antonio Fdez. Alabarce 7 Dec 16, 2022
Mocking for Kotlin/Native and Kotlin Multiplatform using the Kotlin Symbol Processing API (KSP)

Mockative Mocking for Kotlin/Native and Kotlin Multiplatform using the Kotlin Symbol Processing API (KSP). Installation Mockative uses KSP to generate

Mockative 121 Dec 26, 2022
FirestoreCleanArchitectureApp is an app built with Kotlin and Firestore that displays data in real-time using the MVVM Architecture Pattern. For the UI it uses Jetpack Compose, Android's modern toolkit for building native UI.

FirestoreCleanArchitectureApp FirestoreCleanArchitectureApp is an app built with Kotlin and Cloud Firestore that displays data in real-time using Andr

Alex 66 Dec 15, 2022
TimeTrackerApp Android - Time Tracker App developed in kotlin

Time Tracker App (Android) It is a simple android app developed in kotlin progra

null 0 Feb 18, 2022