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)
|
class ContainerConsistencyException(message: String) : Exception(message)
|
||||||
|
|
||||||
interface ComponentContainer {
|
interface ComponentContainer {
|
||||||
|
val containerId: String
|
||||||
|
|
||||||
fun createResolveContext(requestingDescriptor: ValueDescriptor): ValueResolveContext
|
fun createResolveContext(requestingDescriptor: ValueDescriptor): ValueResolveContext
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +110,7 @@ class StorageComponentContainer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> create(request: Class<T>): T {
|
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()
|
val args = constructorBinding.argumentDescriptors.map { it.getValue() }.toTypedArray()
|
||||||
return runWithUnwrappingInvocationException {
|
return runWithUnwrappingInvocationException {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@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 {
|
fun StorageComponentContainer.registerSingleton(klass: Class<*>): StorageComponentContainer {
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ class ComponentResolveContext(
|
|||||||
val requestingDescriptor: ValueDescriptor,
|
val requestingDescriptor: ValueDescriptor,
|
||||||
val parentContext: ValueResolveContext? = null
|
val parentContext: ValueResolveContext? = null
|
||||||
) : ValueResolveContext {
|
) : 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"
|
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 computeArguments(argumentDescriptors: List<ValueDescriptor>): List<Any> = argumentDescriptors.map { it.getValue() }
|
||||||
|
|
||||||
fun Class<*>.bindToConstructor(context: ValueResolveContext): ConstructorBinding {
|
fun Class<*>.bindToConstructor(containerId: String, context: ValueResolveContext): ConstructorBinding {
|
||||||
val constructorInfo = getInfo().constructorInfo ?: error("No constructor for $this: ${getInfo()}")
|
val constructorInfo = getInfo().constructorInfo ?: error("No constructor for $this: ${getInfo()} in $containerId")
|
||||||
val candidate = constructorInfo.constructor
|
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 {
|
fun Method.bindToMethod(containerId: String, context: ValueResolveContext): MethodBinding {
|
||||||
return MethodBinding(this, bindArguments(genericParameterTypes.toList(), context))
|
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)
|
val bound = ArrayList<ValueDescriptor>(parameters.size)
|
||||||
var unsatisfied: MutableList<Type>? = null
|
var unsatisfied: MutableList<Type>? = null
|
||||||
|
|
||||||
@@ -71,13 +76,12 @@ private fun Member.bindArguments(parameters: List<Type>, context: ValueResolveCo
|
|||||||
if (unsatisfied == null)
|
if (unsatisfied == null)
|
||||||
unsatisfied = ArrayList<Type>()
|
unsatisfied = ArrayList<Type>()
|
||||||
unsatisfied.add(parameter)
|
unsatisfied.add(parameter)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
bound.add(descriptor)
|
bound.add(descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unsatisfied != null) {
|
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
|
return bound
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ open class SingletonTypeComponentDescriptor(container: ComponentContainer, val k
|
|||||||
override fun getRegistrations(): Iterable<Type> = klass.getInfo().registrations
|
override fun getRegistrations(): Iterable<Type> = klass.getInfo().registrations
|
||||||
|
|
||||||
private fun createInstanceOf(klass: Class<*>, context: ValueResolveContext): Any {
|
private fun createInstanceOf(klass: Class<*>, context: ValueResolveContext): Any {
|
||||||
val binding = klass.bindToConstructor(context)
|
val binding = klass.bindToConstructor(container.containerId, context)
|
||||||
state = ComponentState.Initializing
|
state = ComponentState.Initializing
|
||||||
for (argumentDescriptor in binding.argumentDescriptors) {
|
for (argumentDescriptor in binding.argumentDescriptors) {
|
||||||
if (argumentDescriptor is Closeable && argumentDescriptor !is SingletonDescriptor) {
|
if (argumentDescriptor is Closeable && argumentDescriptor !is SingletonDescriptor) {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
|||||||
|
|
||||||
return nonDefault.singleOrNull()
|
return nonDefault.singleOrNull()
|
||||||
?: throw InvalidCardinalityException(
|
?: 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()}"
|
"Clashed registrations: ${entry.joinToString()}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun dump(printer: PrintStream): Unit = with(printer) {
|
fun dump(printer: PrintStream): Unit = with(printer) {
|
||||||
val heading = "Container: $myId"
|
val heading = containerId
|
||||||
println(heading)
|
println(heading)
|
||||||
println("=".repeat(heading.length))
|
println("=".repeat(heading.length))
|
||||||
println()
|
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> {
|
fun resolveMultiple(request: Type, context: ValueResolveContext): Iterable<ValueDescriptor> {
|
||||||
registerDependency(request, context)
|
registerDependency(request, context)
|
||||||
@@ -132,7 +134,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
|||||||
|
|
||||||
fun compose(context: ComponentResolveContext) {
|
fun compose(context: ComponentResolveContext) {
|
||||||
if (state != ComponentStorageState.Initial)
|
if (state != ComponentStorageState.Initial)
|
||||||
throw ContainerConsistencyException("Container $myId was already composed.")
|
throw ContainerConsistencyException("$containerId $myId was already composed.")
|
||||||
|
|
||||||
state = ComponentStorageState.Initialized
|
state = ComponentStorageState.Initialized
|
||||||
composeDescriptors(context, descriptors)
|
composeDescriptors(context, descriptors)
|
||||||
@@ -216,7 +218,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va
|
|||||||
val classInfo = instance::class.java.getInfo()
|
val classInfo = instance::class.java.getInfo()
|
||||||
|
|
||||||
classInfo.setterInfos.forEach { (method) ->
|
classInfo.setterInfos.forEach { (method) ->
|
||||||
val methodBinding = method.bindToMethod(context)
|
val methodBinding = method.bindToMethod(containerId, context)
|
||||||
methodBinding.invoke(instance)
|
methodBinding.invoke(instance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user