[Injection] Discriminate default instances during clashes resolution
The idea is to try to resolve the dependency without considering default instances first. This makes containers more composable, e.g., it is now possible to put several containers together as long as all except one provide default implemenetation for some particular service (non-default implementation will be automatically chosen, and all defaults will be discarded).
This commit is contained in:
@@ -33,7 +33,7 @@ enum class ComponentStorageState {
|
||||
Disposed
|
||||
}
|
||||
|
||||
internal class InvalidCardinalityException(message: String, val descriptors: Collection<ComponentDescriptor>) : Exception(message)
|
||||
internal class InvalidCardinalityException(message: String) : Exception(message)
|
||||
|
||||
class ComponentStorage(private val myId: String, parent: ComponentStorage?) : ValueResolver {
|
||||
var state = ComponentStorageState.Initial
|
||||
@@ -46,6 +46,9 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
||||
private val dependencies = MultiMap.createLinkedSet<ComponentDescriptor, Type>()
|
||||
|
||||
override fun resolve(request: Type, context: ValueResolveContext): ValueDescriptor? {
|
||||
fun ComponentDescriptor.isDefaultComponent(): Boolean =
|
||||
this is DefaultInstanceComponentDescriptor || this is DefaultSingletonTypeComponentDescriptor
|
||||
|
||||
if (state == ComponentStorageState.Initial)
|
||||
throw ContainerConsistencyException("Container was not composed before resolving")
|
||||
|
||||
@@ -53,9 +56,16 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
||||
if (entry.isNotEmpty()) {
|
||||
registerDependency(request, context)
|
||||
|
||||
if (entry.size > 1)
|
||||
throw InvalidCardinalityException("Request $request cannot be satisfied because there is more than one type registered", entry)
|
||||
return entry.singleOrNull()
|
||||
if (entry.size == 1) return entry.single()
|
||||
|
||||
val nonDefault = entry.filterNot { it.isDefaultComponent() }
|
||||
if (nonDefault.isEmpty()) return entry.first()
|
||||
|
||||
return nonDefault.singleOrNull()
|
||||
?: throw InvalidCardinalityException(
|
||||
"Request $request cannot be satisfied because there is more than one type registered\n" +
|
||||
"Clashed registrations: ${entry.joinToString()}"
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user