Make it clear when a value injector is missing

This commit is contained in:
Mike Bierlee 2016-12-11 00:53:21 +01:00
parent 4954979574
commit 9eb3a89695
4 changed files with 49 additions and 7 deletions

View file

@ -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) { private void injectValue(string member, size_t memberIndex, string key, Type)(shared(DependencyContainer) container, Type instance) {
alias MemberType = typeof(Type.tupleof[memberIndex]); alias MemberType = typeof(Type.tupleof[memberIndex]);
auto injector = container.resolve!(ValueInjector!MemberType); try {
instance.tupleof[memberIndex] = injector.get(key); auto injector = container.resolve!(ValueInjector!MemberType);
debug(poodinisVerbose) { instance.tupleof[memberIndex] = injector.get(key);
printDebugValueInjection(typeid(Type), &instance, member, typeid(MemberType), 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));
} }
} }

View file

@ -25,6 +25,7 @@ import poodinis.registration;
import poodinis.autowire; import poodinis.autowire;
import poodinis.context; import poodinis.context;
import poodinis.factory; import poodinis.factory;
import poodinis.valueinjection;
/** /**
* Exception thrown when errors occur while resolving a type in a dependency container. * 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) { this(string message, TypeInfo resolveType) {
super(format("Exception while resolving type %s: %s", resolveType.toString(), message)); 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); 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) { private QualifierType resolveAutowiredInstance(QualifierType)(Registration registration) {

View file

@ -11,23 +11,40 @@
*/ */
module poodinis.valueinjection; 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. * 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 key must be supplied, which can be in any format depending on how
* a value injector reads it. * a value injector reads it.
* *
* When the injector throws a ValueNotAvailableException, the value is
* not injected and will keep its original assignment.
*
* Examples: * Examples:
* --- * ---
* class MyClass { * class MyClass {
* @Value("general.importantNumber") * @Value("general.importantNumber")
* private int number; * private int number = 8;
* } * }
* --- * ---
*/ */
struct Value { struct Value {
/**
* The textual key used to find the value by injectors.
*
* The format is injector-specific.
*/
string key; string key;
}; }
/** /**
* Interface which should be implemented by value injectors. * Interface which should be implemented by value injectors.

View file

@ -7,6 +7,8 @@
import poodinis; import poodinis;
import std.exception;
version(unittest) { version(unittest) {
struct Thing { struct Thing {
int x; int x;
@ -58,4 +60,13 @@ version(unittest) {
assert(instance.name == "Le Chef"); assert(instance.name == "Le Chef");
assert(instance.thing.x == 8899); 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()));
}
} }