Improve container error reporting with containerId
Merge-request: KT-MR-8965 Merged-by: Vladimir Dolzhenko <Vladimir.Dolzhenko@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
eb80ba9cf7
commit
8528519d96
@@ -25,6 +25,8 @@ import java.lang.reflect.WildcardType
|
||||
class ContainerConsistencyException(message: String) : Exception(message)
|
||||
|
||||
interface ComponentContainer {
|
||||
val containerId: String
|
||||
|
||||
fun createResolveContext(requestingDescriptor: ValueDescriptor): ValueResolveContext
|
||||
}
|
||||
|
||||
@@ -108,7 +110,7 @@ class StorageComponentContainer(
|
||||
}
|
||||
|
||||
override fun <T> create(request: Class<T>): T {
|
||||
val constructorBinding = request.bindToConstructor(unknownContext)
|
||||
val constructorBinding = request.bindToConstructor(containerId, unknownContext)
|
||||
val args = constructorBinding.argumentDescriptors.map { it.getValue() }.toTypedArray()
|
||||
return runWithUnwrappingInvocationException {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -116,7 +118,10 @@ class StorageComponentContainer(
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString() = "Container $id"
|
||||
override val containerId
|
||||
get() = "Container: $id"
|
||||
|
||||
override fun toString() = containerId
|
||||
}
|
||||
|
||||
fun StorageComponentContainer.registerSingleton(klass: Class<*>): StorageComponentContainer {
|
||||
|
||||
@@ -31,11 +31,12 @@ interface ValueResolveContext {
|
||||
}
|
||||
|
||||
class ComponentResolveContext(
|
||||
val container: StorageComponentContainer,
|
||||
val requestingDescriptor: ValueDescriptor,
|
||||
val parentContext: ValueResolveContext? = null
|
||||
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 resolve(registration: Type): ValueDescriptor? =
|
||||
container.resolve(registration, this) ?: parentContext?.resolve(registration)
|
||||
|
||||
override fun toString(): String = "for $requestingDescriptor in $container"
|
||||
}
|
||||
@@ -51,17 +52,21 @@ class MethodBinding(val method: Method, private val argumentDescriptors: List<Va
|
||||
|
||||
fun computeArguments(argumentDescriptors: List<ValueDescriptor>): List<Any> = argumentDescriptors.map { it.getValue() }
|
||||
|
||||
fun Class<*>.bindToConstructor(context: ValueResolveContext): ConstructorBinding {
|
||||
val constructorInfo = getInfo().constructorInfo ?: error("No constructor for $this: ${getInfo()}")
|
||||
fun Class<*>.bindToConstructor(containerId: String, context: ValueResolveContext): ConstructorBinding {
|
||||
val constructorInfo = getInfo().constructorInfo ?: error("No constructor for $this: ${getInfo()} in $containerId")
|
||||
val candidate = constructorInfo.constructor
|
||||
return ConstructorBinding(candidate, candidate.bindArguments(constructorInfo.parameters, context))
|
||||
return ConstructorBinding(candidate, candidate.bindArguments(containerId, constructorInfo.parameters, context))
|
||||
}
|
||||
|
||||
fun Method.bindToMethod(context: ValueResolveContext): MethodBinding {
|
||||
return MethodBinding(this, bindArguments(genericParameterTypes.toList(), context))
|
||||
fun Method.bindToMethod(containerId: String, context: ValueResolveContext): MethodBinding {
|
||||
return MethodBinding(this, bindArguments(containerId, genericParameterTypes.toList(), context))
|
||||
}
|
||||
|
||||
private fun Member.bindArguments(parameters: List<Type>, context: ValueResolveContext): List<ValueDescriptor> {
|
||||
private fun Member.bindArguments(
|
||||
containerId: String,
|
||||
parameters: List<Type>,
|
||||
context: ValueResolveContext
|
||||
): List<ValueDescriptor> {
|
||||
val bound = ArrayList<ValueDescriptor>(parameters.size)
|
||||
var unsatisfied: MutableList<Type>? = null
|
||||
|
||||
@@ -71,13 +76,12 @@ private fun Member.bindArguments(parameters: List<Type>, context: ValueResolveCo
|
||||
if (unsatisfied == null)
|
||||
unsatisfied = ArrayList<Type>()
|
||||
unsatisfied.add(parameter)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
bound.add(descriptor)
|
||||
}
|
||||
}
|
||||
if (unsatisfied != null) {
|
||||
throw UnresolvedDependenciesException("Dependencies for `$this` cannot be satisfied:\n $unsatisfied")
|
||||
throw UnresolvedDependenciesException("$containerId: Dependencies for `$this` cannot be satisfied:\n $unsatisfied")
|
||||
}
|
||||
return bound
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ open class SingletonTypeComponentDescriptor(container: ComponentContainer, val k
|
||||
override fun getRegistrations(): Iterable<Type> = klass.getInfo().registrations
|
||||
|
||||
private fun createInstanceOf(klass: Class<*>, context: ValueResolveContext): Any {
|
||||
val binding = klass.bindToConstructor(context)
|
||||
val binding = klass.bindToConstructor(container.containerId, context)
|
||||
state = ComponentState.Initializing
|
||||
for (argumentDescriptor in binding.argumentDescriptors) {
|
||||
if (argumentDescriptor is Closeable && argumentDescriptor !is SingletonDescriptor) {
|
||||
|
||||
@@ -69,7 +69,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
||||
|
||||
return nonDefault.singleOrNull()
|
||||
?: throw InvalidCardinalityException(
|
||||
"Request $request cannot be satisfied because there is more than one type registered\n" +
|
||||
"$containerId: Request $request cannot be satisfied because there is more than one type registered\n" +
|
||||
"Clashed registrations: ${entry.joinToString()}"
|
||||
)
|
||||
}
|
||||
@@ -86,7 +86,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
||||
}
|
||||
|
||||
fun dump(printer: PrintStream): Unit = with(printer) {
|
||||
val heading = "Container: $myId"
|
||||
val heading = containerId
|
||||
println(heading)
|
||||
println("=".repeat(heading.length))
|
||||
println()
|
||||
@@ -107,6 +107,8 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
||||
}
|
||||
}
|
||||
|
||||
val containerId
|
||||
get() = "Container: $myId"
|
||||
|
||||
fun resolveMultiple(request: Type, context: ValueResolveContext): Iterable<ValueDescriptor> {
|
||||
registerDependency(request, context)
|
||||
@@ -132,7 +134,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
||||
|
||||
fun compose(context: ComponentResolveContext) {
|
||||
if (state != ComponentStorageState.Initial)
|
||||
throw ContainerConsistencyException("Container $myId was already composed.")
|
||||
throw ContainerConsistencyException("$containerId $myId was already composed.")
|
||||
|
||||
state = ComponentStorageState.Initialized
|
||||
composeDescriptors(context, descriptors)
|
||||
@@ -216,7 +218,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
||||
val classInfo = instance::class.java.getInfo()
|
||||
|
||||
classInfo.setterInfos.forEach { (method) ->
|
||||
val methodBinding = method.bindToMethod(context)
|
||||
val methodBinding = method.bindToMethod(containerId, context)
|
||||
methodBinding.invoke(instance)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user