From 9eb3a89695f6153e8d7e09ea9703c8a40e88bfc5 Mon Sep 17 00:00:00 2001 From: Mike Bierlee Date: Sun, 11 Dec 2016 00:53:21 +0100 Subject: [PATCH] Make it clear when a value injector is missing --- source/poodinis/autowire.d | 12 ++++++++---- source/poodinis/container.d | 12 +++++++++++- source/poodinis/valueinjection.d | 21 +++++++++++++++++++-- test/poodinis/valueinjectiontest.d | 11 +++++++++++ 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/source/poodinis/autowire.d b/source/poodinis/autowire.d index 941bf8d..398c0fa 100644 --- a/source/poodinis/autowire.d +++ b/source/poodinis/autowire.d @@ -206,10 +206,14 @@ private QualifierType createOrResolveInstance(MemberType, QualifierType, bool cr private void injectValue(string member, size_t memberIndex, string key, Type)(shared(DependencyContainer) container, Type instance) { alias MemberType = typeof(Type.tupleof[memberIndex]); - auto injector = container.resolve!(ValueInjector!MemberType); - instance.tupleof[memberIndex] = injector.get(key); - debug(poodinisVerbose) { - printDebugValueInjection(typeid(Type), &instance, member, typeid(MemberType), key); + try { + auto injector = container.resolve!(ValueInjector!MemberType); + instance.tupleof[memberIndex] = injector.get(key); + debug(poodinisVerbose) { + printDebugValueInjection(typeid(Type), &instance, member, typeid(MemberType), key); + } + } catch (ResolveException e) { + throw new ValueInjectionException(format("Could not inject value of type %s into %s.%s: value injector is missing for this type.", typeid(MemberType), typeid(Type), member)); } } diff --git a/source/poodinis/container.d b/source/poodinis/container.d index 7d6229d..00c8df6 100644 --- a/source/poodinis/container.d +++ b/source/poodinis/container.d @@ -25,6 +25,7 @@ import poodinis.registration; import poodinis.autowire; import poodinis.context; import poodinis.factory; +import poodinis.valueinjection; /** * Exception thrown when errors occur while resolving a type in a dependency container. @@ -33,6 +34,10 @@ class ResolveException : Exception { this(string message, TypeInfo resolveType) { super(format("Exception while resolving type %s: %s", resolveType.toString(), message)); } + + this(Throwable cause, TypeInfo resolveType) { + super(format("Exception while resolving type %s", resolveType.toString()), cause); + } } /** @@ -286,7 +291,12 @@ synchronized class DependencyContainer { } Registration registration = getQualifiedRegistration(resolveType, qualifierType, cast(Registration[]) *candidates); - return resolveAutowiredInstance!QualifierType(registration); + + try { + return resolveAutowiredInstance!QualifierType(registration); + } catch (ValueInjectionException e) { + throw new ResolveException(e, resolveType); + } } private QualifierType resolveAutowiredInstance(QualifierType)(Registration registration) { diff --git a/source/poodinis/valueinjection.d b/source/poodinis/valueinjection.d index 3a28579..964f9c8 100644 --- a/source/poodinis/valueinjection.d +++ b/source/poodinis/valueinjection.d @@ -11,23 +11,40 @@ */ module poodinis.valueinjection; +import std.exception; + +/** + * Thrown when something goes wrong during value injection. + */ +class ValueInjectionException : Exception { + mixin basicExceptionCtors; +} + /** * UDA used for marking class members which should be value-injected. * * A key must be supplied, which can be in any format depending on how * a value injector reads it. * + * When the injector throws a ValueNotAvailableException, the value is + * not injected and will keep its original assignment. + * * Examples: * --- * class MyClass { * @Value("general.importantNumber") - * private int number; + * private int number = 8; * } * --- */ struct Value { + /** + * The textual key used to find the value by injectors. + * + * The format is injector-specific. + */ string key; -}; +} /** * Interface which should be implemented by value injectors. diff --git a/test/poodinis/valueinjectiontest.d b/test/poodinis/valueinjectiontest.d index 19b96bb..78526ad 100644 --- a/test/poodinis/valueinjectiontest.d +++ b/test/poodinis/valueinjectiontest.d @@ -7,6 +7,8 @@ import poodinis; +import std.exception; + version(unittest) { struct Thing { int x; @@ -58,4 +60,13 @@ version(unittest) { assert(instance.name == "Le Chef"); assert(instance.thing.x == 8899); } + + // Test injection of values throws exception when injector is not there + unittest { + auto container = new shared DependencyContainer(); + container.register!MyConfig; + assertThrown!ResolveException(container.resolve!MyConfig); + + assertThrown!ValueInjectionException(autowire(container, new MyConfig())); + } }