Created
July 31, 2019 10:23
-
-
Save eugeneek/7b0e0dd146cd50af6a2a533c41a3f536 to your computer and use it in GitHub Desktop.
DI Container
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.eugeneek.injector | |
| import java.util.* | |
| import kotlin.reflect.KClass | |
| object Injector { | |
| private val scopes = HashMap<String, Scope>() | |
| @JvmStatic | |
| @JvmOverloads | |
| fun openScope(scope: Scope, parentScopeClass: KClass<*>? = null) { | |
| val scopeName = scope::class.qualifiedName ?: throw IllegalArgumentException( | |
| "Scope class should not be local or anonymous object") | |
| if (parentScopeClass == null) { | |
| for (openedScope in scopes) { | |
| if (openedScope.value.isRoot && openedScope.key != scopeName) { | |
| throw IllegalArgumentException("Only one root scope can be opened. Use root scope name " + | |
| "'${openedScope.key}' or other opened scope name as 'parentScopeName' parameter") | |
| } | |
| } | |
| } else { | |
| val parentScope = scopes[parentScopeClass.qualifiedName] ?: throw IllegalArgumentException( | |
| "Parent scope with name '${parentScopeClass.qualifiedName}' is not opened or was closed") | |
| parentScope.addChildScopeName(scopeName) | |
| scope.setParentScope(parentScope) | |
| } | |
| scope.init() | |
| scopes[scopeName] = scope | |
| } | |
| @JvmStatic | |
| fun closeScope(scopeClass: KClass<*>) { | |
| val scopeName = scopeClass.qualifiedName ?: throw IllegalStateException( | |
| "Tried to close invalid scope class: $scopeClass") | |
| closeScopeByName(scopeName) | |
| } | |
| private fun closeScopeByName(scopeName: String) { | |
| val scope = scopes[scopeName] | |
| if (scope != null) { | |
| for (childScope in scope.childScopes) { | |
| closeScopeByName(childScope) | |
| } | |
| scopes.remove(scopeName) | |
| } | |
| } | |
| inline fun <reified T> inject(name: String? = T::class.qualifiedName): Lazy<T> = lazy { | |
| get<T>(name) | |
| } | |
| inline fun <reified T> get(name: String? = T::class.qualifiedName): T = | |
| get(T::class, name) | |
| @JvmStatic | |
| @JvmOverloads | |
| fun <T> get(type: KClass<*>, name: String? = type.qualifiedName): T { | |
| if (name == null) { | |
| throw IllegalArgumentException("You need to provide not null 'name' parameter to get instance of this class") | |
| } | |
| for (scope in scopes.values) { | |
| scope.getInstance<T>(type, name)?.let { return it } | |
| } | |
| val namedErrorAddition = if (name != type.qualifiedName) { | |
| " and name \"$name\"" | |
| } else { | |
| ". Check that you provided unnamed instance for this type" | |
| } | |
| throw IllegalArgumentException("No instances bound for $type class$namedErrorAddition") | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.eugeneek.injector | |
| import java.util.* | |
| import kotlin.reflect.KClass | |
| abstract class Scope { | |
| private val instances = mutableMapOf<KClass<*>, MutableMap<String, Any>>() | |
| private var parentScope: Scope? = null | |
| internal val childScopes = HashSet<String>() | |
| internal val isRoot: Boolean | |
| get() = parentScope == null | |
| abstract fun init() | |
| inline fun <reified T: Any> bind(instance: T, name: String? = T::class.qualifiedName) { | |
| bind(T::class, instance, name) | |
| } | |
| @JvmOverloads | |
| fun <T: Any> bind(type: KClass<*>, instance: T, name: String? = type.qualifiedName) { | |
| if (name == null) { | |
| throw IllegalArgumentException("You must to provide not null name to bind instance of this class") | |
| } | |
| val namedInstances = instances[type] ?: mutableMapOf() | |
| namedInstances[name] = instance | |
| instances[type] = namedInstances | |
| } | |
| internal fun setParentScope(parentScope: Scope) { | |
| this.parentScope = parentScope | |
| } | |
| internal fun addChildScopeName(childScopeName: String) { | |
| childScopes.add(childScopeName) | |
| } | |
| @Suppress("UNCHECKED_CAST") | |
| internal fun <T> getInstance(type: KClass<*>, name: String): T? = | |
| instances[type]?.get(name) as? T ?: parentScope?.getInstance(type, name) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment