StorageComponentContainer: allow to specify parent container which can be reused to provide components to several child containers
This commit is contained in:
@@ -38,9 +38,12 @@ object DynamicComponentDescriptor : ValueDescriptor {
|
|||||||
override fun toString(): String = "Dynamic"
|
override fun toString(): String = "Dynamic"
|
||||||
}
|
}
|
||||||
|
|
||||||
class StorageComponentContainer(id: String) : ComponentContainer, ComponentProvider, Closeable {
|
class StorageComponentContainer(id: String, parent: StorageComponentContainer? = null) : ComponentContainer, ComponentProvider, Closeable {
|
||||||
val unknownContext: ComponentResolveContext by lazy { ComponentResolveContext(this, DynamicComponentDescriptor) }
|
val unknownContext: ComponentResolveContext by lazy {
|
||||||
val componentStorage = ComponentStorage(id)
|
val parentContext = parent?.let { ComponentResolveContext(it, DynamicComponentDescriptor) }
|
||||||
|
ComponentResolveContext(this, DynamicComponentDescriptor, parentContext)
|
||||||
|
}
|
||||||
|
val componentStorage: ComponentStorage = ComponentStorage(id, parent?.componentStorage)
|
||||||
|
|
||||||
override fun createResolveContext(requestingDescriptor: ValueDescriptor): ValueResolveContext {
|
override fun createResolveContext(requestingDescriptor: ValueDescriptor): ValueResolveContext {
|
||||||
if (requestingDescriptor == DynamicComponentDescriptor) // cache unknown component descriptor
|
if (requestingDescriptor == DynamicComponentDescriptor) // cache unknown component descriptor
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ package org.jetbrains.kotlin.container
|
|||||||
|
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
fun createContainer(id: String, init: StorageComponentContainer.() -> Unit): StorageComponentContainer {
|
fun createContainer(id: String, parent: StorageComponentContainer? = null, init: StorageComponentContainer.() -> Unit): StorageComponentContainer {
|
||||||
val c = StorageComponentContainer(id)
|
val c = StorageComponentContainer(id, parent)
|
||||||
c.init()
|
c.init()
|
||||||
c.compose()
|
c.compose()
|
||||||
return c
|
return c
|
||||||
|
|||||||
@@ -17,8 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.container
|
package org.jetbrains.kotlin.container
|
||||||
|
|
||||||
import com.intellij.util.containers.MultiMap
|
import com.intellij.util.containers.MultiMap
|
||||||
import java.util.ArrayList
|
import java.lang.reflect.Type
|
||||||
import java.lang.reflect.*
|
|
||||||
|
|
||||||
internal class ComponentRegistry {
|
internal class ComponentRegistry {
|
||||||
fun buildRegistrationMap(descriptors: Collection<ComponentDescriptor>): MultiMap<Type, ComponentDescriptor> {
|
fun buildRegistrationMap(descriptors: Collection<ComponentDescriptor>): MultiMap<Type, ComponentDescriptor> {
|
||||||
@@ -40,4 +39,8 @@ internal class ComponentRegistry {
|
|||||||
fun tryGetEntry(request: Type): Collection<ComponentDescriptor> {
|
fun tryGetEntry(request: Type): Collection<ComponentDescriptor> {
|
||||||
return registrationMap.get(request)
|
return registrationMap.get(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addAll(other: ComponentRegistry) {
|
||||||
|
registrationMap.putAllValues(other.registrationMap)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -30,8 +30,12 @@ interface ValueResolveContext {
|
|||||||
fun resolve(registration: Type): ValueDescriptor?
|
fun resolve(registration: Type): ValueDescriptor?
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComponentResolveContext(val container: StorageComponentContainer, val requestingDescriptor: ValueDescriptor) : ValueResolveContext {
|
class ComponentResolveContext(
|
||||||
override fun resolve(registration: Type): ValueDescriptor? = container.resolve(registration, this)
|
val container: StorageComponentContainer,
|
||||||
|
val requestingDescriptor: ValueDescriptor,
|
||||||
|
val parentContext: ValueResolveContext? = null
|
||||||
|
) : ValueResolveContext {
|
||||||
|
override fun resolve(registration: Type): ValueDescriptor? = container.resolve(registration, this) ?: parentContext?.resolve(registration)
|
||||||
|
|
||||||
override fun toString(): String = "for $requestingDescriptor in $container"
|
override fun toString(): String = "for $requestingDescriptor in $container"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,9 +35,13 @@ enum class ComponentStorageState {
|
|||||||
|
|
||||||
internal class InvalidCardinalityException(message: String, val descriptors: Collection<ComponentDescriptor>) : Exception(message)
|
internal class InvalidCardinalityException(message: String, val descriptors: Collection<ComponentDescriptor>) : Exception(message)
|
||||||
|
|
||||||
class ComponentStorage(val myId: String) : ValueResolver {
|
class ComponentStorage(val myId: String, parent: ComponentStorage?) : ValueResolver {
|
||||||
var state = ComponentStorageState.Initial
|
var state = ComponentStorageState.Initial
|
||||||
private val registry = ComponentRegistry()
|
private val registry = ComponentRegistry()
|
||||||
|
init {
|
||||||
|
parent?.let { registry.addAll(it.registry) }
|
||||||
|
}
|
||||||
|
|
||||||
private val descriptors = LinkedHashSet<ComponentDescriptor>()
|
private val descriptors = LinkedHashSet<ComponentDescriptor>()
|
||||||
private val dependencies = MultiMap.createLinkedSet<ComponentDescriptor, Type>()
|
private val dependencies = MultiMap.createLinkedSet<ComponentDescriptor, Type>()
|
||||||
|
|
||||||
|
|||||||
+42
@@ -270,4 +270,46 @@ class ComponentContainerTest {
|
|||||||
assertTrue(c is C)
|
assertTrue(c is C)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun use_parent_context_to_discover_dependencies() {
|
||||||
|
class A
|
||||||
|
class B(val a: A)
|
||||||
|
|
||||||
|
val ac = createContainer("a") {
|
||||||
|
useImpl<A>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val bc = createContainer("b", ac) {
|
||||||
|
useImpl<B>()
|
||||||
|
}
|
||||||
|
val b = bc.get<B>()
|
||||||
|
|
||||||
|
val a = ac.get<A>()
|
||||||
|
assertTrue(b is B)
|
||||||
|
assertTrue(b.a is A)
|
||||||
|
assertTrue(a is A)
|
||||||
|
assertTrue(b.a === a)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun several_child_dependencies() {
|
||||||
|
class A
|
||||||
|
class B(val a: A)
|
||||||
|
|
||||||
|
val ac = createContainer("a") {
|
||||||
|
useImpl<A>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val bc1 = createContainer("b1", ac) {
|
||||||
|
useImpl<B>()
|
||||||
|
}
|
||||||
|
val bc2 = createContainer("b2", ac) {
|
||||||
|
useImpl<B>()
|
||||||
|
}
|
||||||
|
val a = ac.get<A>()
|
||||||
|
assertTrue(a is A)
|
||||||
|
assertTrue(a === bc2.get<B>().a)
|
||||||
|
assertTrue(a === bc1.get<B>().a)
|
||||||
|
assertTrue(a === bc1.get<A>())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user