or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-features.mdbinding-dsl.mdcontainer-configuration.mddirect-access.mdindex.mdlazy-property-delegation.mdscoping-and-context.md
tile.json

tessl/maven-org-kodein-di--kodein-di

KOtlin DEpendency INjection - A straightforward and yet very useful dependency retrieval container for Kotlin Multiplatform

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.kodein.di/kodein-di@7.26.x

To install, run

npx @tessl/cli install tessl/maven-org-kodein-di--kodein-di@7.26.0

index.mddocs/

Kodein-DI

Kodein-DI is a comprehensive dependency injection framework for Kotlin Multiplatform applications that provides effortless dependency retrieval and container management. It enables lazy instantiation of dependencies, eliminates concerns about initialization order, and supports binding classes or interfaces to their instances or providers with a declarative DSL.

Package Information

  • Package Name: kodein-di
  • Package Type: maven
  • Language: Kotlin Multiplatform
  • Installation: implementation("org.kodein.di:kodein-di:7.26.1")

Core Imports

import org.kodein.di.*

For specific functionality:

import org.kodein.di.DI
import org.kodein.di.DIAware
import org.kodein.di.DirectDI
import org.kodein.di.bindSingleton
import org.kodein.di.bindProvider
import org.kodein.di.bindFactory
import org.kodein.di.instance
import org.kodein.di.provider
import org.kodein.di.factory

Basic Usage

import org.kodein.di.*

// Define interfaces and classes
interface DataSource
class SqliteDataSource : DataSource
interface UserService
class UserServiceImpl(private val dataSource: DataSource) : UserService

// Create DI container
val di = DI {
    bind<DataSource>() with singleton { SqliteDataSource() }
    bind<UserService>() with provider { UserServiceImpl(instance()) }
    constant("appName") with "MyApp"
}

// Use dependency injection
class MyController : DIAware {
    override val di: DI = di
    
    private val userService: UserService by instance()
    private val appName: String by constant()
    
    fun handleRequest() {
        // Use injected dependencies
        println("Handling request in $appName")
    }
}

// Direct access (immediate retrieval)
val directDI = di.direct
val userService = directDI.instance<UserService>()

Architecture

Kodein-DI is built around several key components:

  • DI Container: Main dependency injection container that stores bindings and manages instances
  • Binding DSL: Declarative syntax for configuring dependencies (singleton, provider, factory, instance, multiton)
  • Retrieval Patterns: Both lazy property delegation (DIAware) and direct access (DirectDI) for dependency retrieval
  • Scoping System: Context-aware dependency management with hierarchical scopes and custom scope definitions
  • Module System: Reusable configuration modules for organizing and sharing binding definitions
  • Type Safety: Full Kotlin type safety with generic preservation and TypeToken integration

Capabilities

Container Configuration

Core DI container creation and configuration with binding DSL for defining how dependencies are created and managed.

interface DI : DIAware {
    val container: DIContainer
    
    companion object {
        operator fun invoke(
            allowSilentOverride: Boolean = false,
            init: MainBuilder.() -> Unit
        ): DI
        
        fun lazy(
            allowSilentOverride: Boolean = false,
            init: MainBuilder.() -> Unit
        ): LazyDI
        
        fun direct(
            allowSilentOverride: Boolean = false,
            init: MainBuilder.() -> Unit
        ): DirectDI
        
        fun withDelayedCallbacks(
            allowSilentOverride: Boolean = false,
            init: MainBuilder.() -> Unit,
        ): Pair<DI, () -> Unit>
        
        fun from(modules: List<Module>): DI
        
        var defaultFullDescriptionOnError: Boolean
        var defaultFullContainerTreeOnError: Boolean
    }
}

data class Module(
    val allowSilentOverride: Boolean = false,
    val prefix: String = "",
    val init: Builder.() -> Unit
) {
    val name: String
    constructor(
        name: String,
        allowSilentOverride: Boolean = false,
        prefix: String = "",
        init: Builder.() -> Unit,
    )
    operator fun getValue(thisRef: Any?, property: KProperty<*>): Module
}

Container Configuration

Binding DSL

Declarative syntax for binding types to their implementations with various creation patterns including singleton, provider, factory, instance, and multiton.

interface DI.Builder {
    fun <T : Any> Bind(type: TypeToken<out T>, tag: Any? = null, overrides: Boolean? = null): TypeBinder<T>
    fun <T : Any> Bind(tag: Any? = null, overrides: Boolean? = null, binding: DIBinding<*, *, T>)
    fun constant(tag: Any, overrides: Boolean? = null): ConstantBinder
    fun <T : Any> Delegate(type: TypeToken<out T>, tag: Any? = null, overrides: Boolean? = null): DelegateBinder<T>
    fun import(module: Module, allowOverride: Boolean = false)
    fun importAll(vararg modules: Module, allowOverride: Boolean = false)
    fun importOnce(module: Module, allowOverride: Boolean = false)
    fun onReady(cb: DirectDI.() -> Unit)
    
    // Set binding methods
    fun <T : Any> BindInSet(tag: Any? = null, overrides: Boolean? = null, type: TypeToken<out T>, creator: SetBinder<T>.() -> Unit)
    fun <T : Any> InBindSet(tag: Any? = null, overrides: Boolean? = null, type: TypeToken<out T>, creator: SetBinder<T>.() -> Unit)
    fun <T : Any> AddBindInSet(tag: Any? = null, overrides: Boolean? = null, binding: DIBinding<*, *, T>)
}

fun <T : Any> DI.BindBuilder<*>.singleton(
    creator: NoArgBindingDI<*>.() -> T
): Singleton<*, T>

fun <T : Any> DI.BindBuilder<*>.provider(
    creator: NoArgBindingDI<*>.() -> T
): Provider<*, T>

fun <A, T : Any> DI.BindBuilder<*>.factory(
    creator: BindingDI<*>.(A) -> T
): Factory<*, A, T>

Binding DSL

Lazy Property Delegation

Property delegation pattern for lazy dependency retrieval using DIAware interface with automatic initialization and caching.

interface DIAware {
    val di: DI
    val diContext: DIContext<*>
    val diTrigger: DITrigger?
}

fun <T : Any> DIAware.instance(tag: Any? = null): LazyDelegate<T>
fun <T : Any> DIAware.provider(tag: Any? = null): LazyDelegate<() -> T>
fun <A, T : Any> DIAware.factory(tag: Any? = null): LazyDelegate<(A) -> T>
fun <T : Any> DIAware.constant(): LazyDelegate<T>

Lazy Property Delegation

Direct Access

Immediate dependency retrieval without property delegation for cases requiring direct access to dependencies.

interface DirectDI : DirectDIBase {
    fun <T : Any> Instance(type: TypeToken<T>, tag: Any? = null): T
    fun <T : Any> Provider(type: TypeToken<T>, tag: Any? = null): () -> T
    fun <A, T : Any> Factory(argType: TypeToken<in A>, type: TypeToken<T>, tag: Any? = null): (A) -> T
    fun On(context: DIContext<*>): DirectDI
}

interface DirectDIAware {
    val directDI: DirectDI
}

Direct Access

Scoping and Context

Context-aware dependency management with support for hierarchical scopes, context translation, and lifecycle management.

interface DIContext<C : Any> {
    val type: TypeToken<in C>
    val value: C
    
    data class Value<C : Any>(override val type: TypeToken<in C>, override val value: C) : DIContext<C>
    class Lazy<C : Any>(override val type: TypeToken<in C>, val getValue: () -> C) : DIContext<C>
}

interface Scope<C> {
    fun getRegistry(context: C): ScopeRegistry
}

interface ContextTranslator<C, S> {
    fun translate(key: DI.Key<*, *, *>, context: C): S?
}

Scoping and Context

Advanced Features

Advanced dependency injection patterns including constructor injection, external sources, binding search, and sub-DI creation.

fun <T> DirectDIAware.new(constructor: () -> T): T
fun <P1, T> DirectDIAware.new(constructor: (P1) -> T): T

interface ExternalSource {
    fun <C : Any, A, T : Any> getFactory(
        key: DI.Key<C, A, T>,
        context: C
    ): ((A) -> T)?
}

fun DirectDIAware.subDI(
    allowSilentOverride: Boolean = false,
    copy: Copy = Copy.NonCached,
    init: DI.MainBuilder.() -> Unit
): DI

Advanced Features

Exception Handling

Kodein-DI defines several specific exception types for different error conditions:

class DI.NotFoundException(val key: Key<*, *, *>, message: String) : RuntimeException(message)
class DI.DependencyLoopException(message: String) : RuntimeException(message)
class DI.OverridingException(message: String) : RuntimeException(message)
class DI.NoResultException(val search: SearchSpecs, message: String) : RuntimeException(message)
class DI.UnusedParameterException(message: String, cause: Exception? = null) : RuntimeException(message, cause)

Type System

data class DI.Key<in C : Any, in A, out T : Any>(
    val contextType: TypeToken<in C>,
    val argType: TypeToken<in A>,
    val type: TypeToken<out T>,
    val tag: Any?
)

interface Typed<A> {
    val type: TypeToken<A>
    val value: A
}