From f7507f384459b57460af899bf9ceae4f52f1ea21 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Fri, 6 Dec 2024 19:27:07 +0100 Subject: refactor: Add DI and packages --- src/main/kotlin/moe/nea/ledger/utils/DI.kt | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/main/kotlin/moe/nea/ledger/utils/DI.kt (limited to 'src/main/kotlin/moe/nea/ledger/utils/DI.kt') diff --git a/src/main/kotlin/moe/nea/ledger/utils/DI.kt b/src/main/kotlin/moe/nea/ledger/utils/DI.kt new file mode 100644 index 0000000..1114127 --- /dev/null +++ b/src/main/kotlin/moe/nea/ledger/utils/DI.kt @@ -0,0 +1,63 @@ +package moe.nea.ledger.utils + +import java.lang.reflect.AnnotatedElement +import java.util.Collections +import java.util.Stack + +@Suppress("UNCHECKED_CAST") +class DI { + private fun internalProvide(type: Class, element: AnnotatedElement? = null): T { + val provider = providers[type] as BaseDIProvider + 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: ${injectionStack.joinToString(" -> ")} -> $type") + } + injectionStack.push(type) + val value = try { + provider.provideWithContext(this, context) + } catch (ex: Exception) { + throw RuntimeException("Could not create instance for type $type", ex) + } + val cycleCheckCookie = injectionStack.pop() + require(cycleCheckCookie == type) { "Unbalanced stack cookie: $cycleCheckCookie != $type" } + values[key] = value + return value + } + + fun provide(type: Class, element: AnnotatedElement? = null): T { + return internalProvide(type, element) + } + + fun register(type: Class, provider: BaseDIProvider) { + providers[type] = provider + } + + fun registerInjectableClasses(vararg type: Class<*>) { + type.forEach { internalRegisterInjectableClass(it) } + } + + private fun internalRegisterInjectableClass(type: Class) { + register(type, DIProvider.fromInjectableClass(type)) + } + + fun instantiateAll() { + providers.keys.forEach { + provide(it, null) + } + } + + fun getAllInstances(): Collection = + Collections.unmodifiableCollection(values.values) + + fun registerSingleton(value: T) { + register(value.javaClass, DIProvider.singeleton(value)) + } + + private val injectionStack: Stack> = Stack() + private val values = mutableMapOf, *>, Any>() + private val providers = mutableMapOf, BaseDIProvider<*, *>>() + +} \ No newline at end of file -- cgit