com.github.salomonbrys.kodein.Injector.kt Maven / Gradle / Ivy
package com.github.salomonbrys.kodein
import com.github.salomonbrys.kodein.internal.KodeinContainer
import java.io.Serializable
import java.lang.reflect.Type
import java.util.*
import kotlin.reflect.KProperty
private object UNINITIALIZED_VALUE
abstract class Injected internal constructor(val bind: Kodein.Bind) : Serializable {
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
val value: T
@Suppress("UNCHECKED_CAST")
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE)
return _v1 as T
return synchronized(this) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE)
_v2 as T
else
throw KodeinInjector.UninjectedException()
}
}
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value
fun isInjected(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInjected()) value.toString() else "Uninjected $_type: $bind."
internal fun _inject(container: KodeinContainer) {
_value = _getInjection(container)
}
protected abstract fun _getInjection(container: KodeinContainer): T
protected abstract val _type: String
}
class InjectedFactory(private val _key: Kodein.Key) : Injected<(A) -> T>(_key.bind) {
override fun _getInjection(container: KodeinContainer) = container.nonNullFactory(_key)
override val _type = "factory"
}
class InjectedNullableFactory(private val _key: Kodein.Key) : Injected<((A) -> T)?>(_key.bind) {
override fun _getInjection(container: KodeinContainer) = container.factoryOrNull(_key)
override val _type = "factory"
}
class InjectedProvider(bind: Kodein.Bind) : Injected<() -> T>(bind) {
override fun _getInjection(container: KodeinContainer) = container.nonNullProvider(bind)
override val _type = "provider"
}
class InjectedNullableProvider(bind: Kodein.Bind) : Injected<(() -> T)?>(bind) {
override fun _getInjection(container: KodeinContainer) = container.providerOrNull(bind)
override val _type = "provider"
}
class InjectedInstance(bind: Kodein.Bind) : Injected(bind) {
override fun _getInjection(container: KodeinContainer) = container.nonNullProvider(bind).invoke()
override val _type = "instance"
}
class InjectedNullableInstance(bind: Kodein.Bind) : Injected(bind) {
override fun _getInjection(container: KodeinContainer) = container.providerOrNull(bind)?.invoke()
override val _type = "instance"
}
class KodeinInjector() {
class UninjectedException : RuntimeException("Value has not been injected")
private val _list = LinkedList>()
private var _kodein: Kodein? = null
private var _onInjected: (Kodein) -> Unit = {}
fun onInjected(cb: (Kodein) -> Unit) { _onInjected = cb }
fun _register(injected: Injected) = injected.apply { _list.add(this) }
inline fun factory(tag: Any? = null): Injected<(A) -> T> = _register(InjectedFactory(Kodein.Key(Kodein.Bind(typeToken(), tag), typeToken())))
inline fun factoryOrNull(tag: Any? = null): Injected<((A) -> T)?> = _register(InjectedNullableFactory(Kodein.Key(Kodein.Bind(typeToken(), tag), typeToken())))
inline fun provider(tag: Any? = null): Injected<() -> T> = _register(InjectedProvider(Kodein.Bind(typeToken(), tag)))
inline fun providerOrNull(tag: Any? = null): Injected<(() -> T)?> = _register(InjectedNullableProvider(Kodein.Bind(typeToken(), tag)))
inline fun instance(tag: Any? = null): Injected = _register(InjectedInstance(Kodein.Bind(typeToken(), tag)))
inline fun instanceOrNull(tag: Any? = null): Injected = _register(InjectedNullableInstance(Kodein.Bind(typeToken(), tag)))
inner class CurriedFactory(val arg: A, val argType: Type) {
// https://youtrack.jetbrains.com/issue/KT-12126
fun _register(injected: Injected) = this@KodeinInjector._register(injected)
inline fun provider(tag: Any? = null): Lazy<() -> T> = _register(InjectedFactory(Kodein.Key(Kodein.Bind(typeToken(), tag), argType))).toProvider(arg)
inline fun providerOrNull(tag: Any? = null): Lazy<(() -> T)?> = _register(InjectedNullableFactory(Kodein.Key(Kodein.Bind(typeToken(), tag), argType))).toNullableProvider(arg)
inline fun instance(tag: Any? = null): Lazy = _register(InjectedFactory(Kodein.Key(Kodein.Bind(typeToken(), tag), argType))).toInstance(arg)
inline fun instanceOrNull(tag: Any? = null): Lazy = _register(InjectedNullableFactory(Kodein.Key(Kodein.Bind(typeToken(), tag), argType))).toNullableInstance(arg)
}
inline fun with(arg: A) = CurriedFactory(arg, typeToken())
inline fun providerFromFactory(arg: A, tag: Any? = null): Lazy<() -> T> = factory(tag).toProvider(arg)
inline fun providerFromFactoryOrNull(arg: A, tag: Any? = null): Lazy<(() -> T)?> = factoryOrNull(tag).toNullableProvider(arg)
inline fun instanceFromFactory(arg: A, tag: Any? = null): Lazy = factory(tag).toInstance(arg)
inline fun instanceFromFactoryOrNull(arg: A, tag: Any? = null): Lazy = factoryOrNull(tag).toNullableInstance(arg)
fun kodein(): Lazy = lazy { _kodein ?: throw KodeinInjector.UninjectedException() }
fun inject(kodein: Kodein) {
_list.forEach { it._inject(kodein._container) }
_kodein = kodein
_onInjected(kodein)
}
}
fun Injected<(A) -> T>.toProvider(arg: A): Lazy<() -> T> = lazy { { value(arg) } }
fun Injected<((A) -> T)?>.toNullableProvider(arg: A): Lazy<(() -> T)?> = lazy {
val v = value ?: return@lazy null
return@lazy { v(arg) }
}
fun Injected<(A) -> T>.toInstance(arg: A): Lazy = lazy { value(arg) }
fun Injected<((A) -> T)?>.toNullableInstance(arg: A): Lazy = lazy {
val v = value ?: return@lazy null
return@lazy v(arg)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy