mirror of
https://github.com/mbierlee/poodinis.git
synced 2024-11-15 04:04:01 +01:00
Add optional value injection when values cannot be injected by injectors
This commit is contained in:
parent
9eb3a89695
commit
52dcecef9a
|
@ -140,7 +140,7 @@ Besides injecting class instances, Poodinis can also inject values:
|
|||
```
|
||||
class ExampleClass {
|
||||
@Value("a.key.for.this.value")
|
||||
private int someNumber;
|
||||
private int someNumber = 9; // Assignment is kept when the injector cannot find the value associated with key
|
||||
}
|
||||
```
|
||||
The value will automatically be injected during the autowiring process. In order for Poodinis to be able to inject values, ValueInjectors must be available and registered with the dependency container:
|
||||
|
|
|
@ -134,7 +134,7 @@ private void autowireMember(string member, size_t memberIndex, Type)(shared(Depe
|
|||
injectInstance!(member, memberIndex, UseMemberType)(container, instance);
|
||||
} else static if (is(typeof(attribute) == Value)) {
|
||||
enum key = attribute.key;
|
||||
injectValue!(member, memberIndex, key)(container, instance);
|
||||
injectValue!(member, memberIndex, key, false)(container, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ 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, bool mandatory, Type)(shared(DependencyContainer) container, Type instance) {
|
||||
alias MemberType = typeof(Type.tupleof[memberIndex]);
|
||||
try {
|
||||
auto injector = container.resolve!(ValueInjector!MemberType);
|
||||
|
@ -214,6 +214,10 @@ private void injectValue(string member, size_t memberIndex, string key, Type)(sh
|
|||
}
|
||||
} 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));
|
||||
} catch (ValueNotAvailableException e) {
|
||||
static if (mandatory) {
|
||||
throw new ValueInjectionException(format("Could not inject value of type %s into %s.%s", typeid(MemberType), typeid(Type), member), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
module poodinis.valueinjection;
|
||||
|
||||
import std.exception;
|
||||
import std.string;
|
||||
|
||||
/**
|
||||
* Thrown when something goes wrong during value injection.
|
||||
|
@ -20,6 +21,19 @@ class ValueInjectionException : Exception {
|
|||
mixin basicExceptionCtors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown by injectors when the value with the given key cannot be found.
|
||||
*/
|
||||
class ValueNotAvailableException : Exception {
|
||||
this(string key) {
|
||||
super(format("Value for key %s is not available", key));
|
||||
}
|
||||
|
||||
this(string key, Throwable cause) {
|
||||
super(format("Value for key %s is not available", key), cause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* UDA used for marking class members which should be value-injected.
|
||||
*
|
||||
|
@ -53,9 +67,8 @@ struct Value {
|
|||
* type or that of a struct. While class types are also supported, value injectors
|
||||
* are not intended for them.
|
||||
*
|
||||
* Note that value injectors are also autowired before being used. Value injectors should
|
||||
* not contain dependencies on classes which require value injection. Neither should a
|
||||
* value injector have members which are to be value-injected.
|
||||
* Note that value injectors are also autowired before being used. Values within dependencies of
|
||||
* a value injector are not injected. Neither are values within the value injector itself.
|
||||
*
|
||||
* Value injection is not supported for constructor injection.
|
||||
*
|
||||
|
@ -75,6 +88,8 @@ interface ValueInjector(Type) {
|
|||
*
|
||||
* The key can have any format. Generally you are encouraged
|
||||
* to accept a dot separated path, for example: server.http.port
|
||||
*
|
||||
* Throws: ValueNotAvailableException when the value for the given key is not available for any reason
|
||||
*/
|
||||
Type get(string key);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,11 @@ version(unittest) {
|
|||
Thing thing;
|
||||
}
|
||||
|
||||
class ConfigWithDefaults {
|
||||
@Value("conf.missing")
|
||||
int noms = 9;
|
||||
}
|
||||
|
||||
// Test injection of values
|
||||
unittest {
|
||||
auto container = new shared DependencyContainer();
|
||||
|
@ -69,4 +74,21 @@ version(unittest) {
|
|||
|
||||
assertThrown!ValueInjectionException(autowire(container, new MyConfig()));
|
||||
}
|
||||
|
||||
// Test injection of values with defaults
|
||||
unittest {
|
||||
auto container = new shared DependencyContainer();
|
||||
container.register!ConfigWithDefaults;
|
||||
|
||||
class IntInjector : ValueInjector!int {
|
||||
public override int get(string key) {
|
||||
throw new ValueNotAvailableException(key);
|
||||
}
|
||||
}
|
||||
|
||||
container.register!(ValueInjector!int, IntInjector);
|
||||
|
||||
auto instance = container.resolve!ConfigWithDefaults;
|
||||
assert(instance.noms == 9);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue