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"
|
||||
}
|
||||
|
||||
class StorageComponentContainer(id: String) : ComponentContainer, ComponentProvider, Closeable {
|
||||
val unknownContext: ComponentResolveContext by lazy { ComponentResolveContext(this, DynamicComponentDescriptor) }
|
||||
val componentStorage = ComponentStorage(id)
|
||||
class StorageComponentContainer(id: String, parent: StorageComponentContainer? = null) : ComponentContainer, ComponentProvider, Closeable {
|
||||
val unknownContext: ComponentResolveContext by lazy {
|
||||
val parentContext = parent?.let { ComponentResolveContext(it, DynamicComponentDescriptor) }
|
||||
ComponentResolveContext(this, DynamicComponentDescriptor, parentContext)
|
||||
}
|
||||
val componentStorage: ComponentStorage = ComponentStorage(id, parent?.componentStorage)
|
||||
|
||||
override fun createResolveContext(requestingDescriptor: ValueDescriptor): ValueResolveContext {
|
||||
if (requestingDescriptor == DynamicComponentDescriptor) // cache unknown component descriptor
|
||||
|
||||
@@ -18,8 +18,8 @@ package org.jetbrains.kotlin.container
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
fun createContainer(id: String, init: StorageComponentContainer.() -> Unit): StorageComponentContainer {
|
||||
val c = StorageComponentContainer(id)
|
||||
fun createContainer(id: String, parent: StorageComponentContainer? = null, init: StorageComponentContainer.() -> Unit): StorageComponentContainer {
|
||||
val c = StorageComponentContainer(id, parent)
|
||||
c.init()
|
||||
c.compose()
|
||||
return c
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
package org.jetbrains.kotlin.container
|
||||
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import java.util.ArrayList
|
||||
import java.lang.reflect.*
|
||||
import java.lang.reflect.Type
|
||||
|
||||
internal class ComponentRegistry {
|
||||
fun buildRegistrationMap(descriptors: Collection<ComponentDescriptor>): MultiMap<Type, ComponentDescriptor> {
|
||||
@@ -40,4 +39,8 @@ internal class ComponentRegistry {
|
||||
fun tryGetEntry(request: Type): Collection<ComponentDescriptor> {
|
||||
return registrationMap.get(request)
|
||||
}
|
||||
|
||||
fun addAll(other: ComponentRegistry) {
|
||||
registrationMap.putAllValues(other.registrationMap)
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,12 @@ interface ValueResolveContext {
|
||||
fun resolve(registration: Type): ValueDescriptor?
|
||||
}
|
||||
|
||||
class ComponentResolveContext(val container: StorageComponentContainer, val requestingDescriptor: ValueDescriptor) : ValueResolveContext {
|
||||
override fun resolve(registration: Type): ValueDescriptor? = container.resolve(registration, this)
|
||||
class ComponentResolveContext(
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -35,9 +35,13 @@ enum class ComponentStorageState {
|
||||
|
||||
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
|
||||
private val registry = ComponentRegistry()
|
||||
init {
|
||||
parent?.let { registry.addAll(it.registry) }
|
||||
}
|
||||
|
||||
private val descriptors = LinkedHashSet<ComponentDescriptor>()
|
||||
private val dependencies = MultiMap.createLinkedSet<ComponentDescriptor, Type>()
|
||||
|
||||
|
||||
+42
@@ -270,4 +270,46 @@ class ComponentContainerTest {
|
||||
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