1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
package moe.nea.ledger.utils.di
import java.lang.reflect.AnnotatedElement
import java.util.Collections
import java.util.Stack
@Suppress("UNCHECKED_CAST")
class DI {
private fun formatInjectionStack() =
injectionStack.joinToString(" -> ")
private fun <T : Any, C> internalProvide(type: Class<T>, element: AnnotatedElement? = null): T {
val provider = providers[type] as BaseDIProvider<T, C>
val context = if (element == null) provider.createEmptyContext() else provider.createContext(element)
val key = Pair(type, context)
val existingValue = values[key]
if (existingValue != null) return existingValue as T
if (type in injectionStack) {
error("Found injection cycle: ${formatInjectionStack()} -> $type")
}
injectionStack.push(type)
val value = try {
provider.provideWithContext(this, context)
} catch (ex: Exception) {
throw RuntimeException("Could not create instance for type $type (in stack ${formatInjectionStack()})", ex)
}
val cycleCheckCookie = injectionStack.pop()
require(cycleCheckCookie == type) { "Unbalanced stack cookie: $cycleCheckCookie != $type" }
values[key] = value
return value
}
fun <T : Any> provide(type: Class<T>, element: AnnotatedElement? = null): T {
return internalProvide<T, Any>(type, element)
}
inline fun <reified T : Any> provide(): T = provide(T::class.java)
fun <T : Any> register(type: Class<T>, provider: BaseDIProvider<T, *>) {
providers[type] = provider
}
fun registerInjectableClasses(vararg type: Class<*>) {
type.forEach { internalRegisterInjectableClass(it) }
}
private fun <T : Any> internalRegisterInjectableClass(type: Class<T>) {
register(type, DIProvider.fromInjectableClass(type))
}
fun instantiateAll() {
providers.keys.forEach {
provide(it, null)
}
}
fun getAllInstances(): Collection<Any> =
Collections.unmodifiableCollection(values.values)
fun <T : Any> registerSingleton(value: T) {
register(value.javaClass, DIProvider.singeleton(value))
}
private val injectionStack: Stack<Class<*>> = Stack()
private val values = mutableMapOf<Pair<Class<*>, *>, Any>()
private val providers = mutableMapOf<Class<*>, BaseDIProvider<*, *>>()
init {
registerSingleton(this)
}
}
|