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 {
|
class ExampleClass {
|
||||||
@Value("a.key.for.this.value")
|
@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:
|
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);
|
injectInstance!(member, memberIndex, UseMemberType)(container, instance);
|
||||||
} else static if (is(typeof(attribute) == Value)) {
|
} else static if (is(typeof(attribute) == Value)) {
|
||||||
enum key = attribute.key;
|
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]);
|
alias MemberType = typeof(Type.tupleof[memberIndex]);
|
||||||
try {
|
try {
|
||||||
auto injector = container.resolve!(ValueInjector!MemberType);
|
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) {
|
} 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));
|
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;
|
module poodinis.valueinjection;
|
||||||
|
|
||||||
import std.exception;
|
import std.exception;
|
||||||
|
import std.string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when something goes wrong during value injection.
|
* Thrown when something goes wrong during value injection.
|
||||||
|
@ -20,6 +21,19 @@ class ValueInjectionException : Exception {
|
||||||
mixin basicExceptionCtors;
|
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.
|
* 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
|
* type or that of a struct. While class types are also supported, value injectors
|
||||||
* are not intended for them.
|
* are not intended for them.
|
||||||
*
|
*
|
||||||
* Note that value injectors are also autowired before being used. Value injectors should
|
* Note that value injectors are also autowired before being used. Values within dependencies of
|
||||||
* not contain dependencies on classes which require value injection. Neither should a
|
* a value injector are not injected. Neither are values within the value injector itself.
|
||||||
* value injector have members which are to be value-injected.
|
|
||||||
*
|
*
|
||||||
* Value injection is not supported for constructor injection.
|
* 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
|
* The key can have any format. Generally you are encouraged
|
||||||
* to accept a dot separated path, for example: server.http.port
|
* 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);
|
Type get(string key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,11 @@ version(unittest) {
|
||||||
Thing thing;
|
Thing thing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConfigWithDefaults {
|
||||||
|
@Value("conf.missing")
|
||||||
|
int noms = 9;
|
||||||
|
}
|
||||||
|
|
||||||
// Test injection of values
|
// Test injection of values
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new shared DependencyContainer();
|
auto container = new shared DependencyContainer();
|
||||||
|
@ -69,4 +74,21 @@ version(unittest) {
|
||||||
|
|
||||||
assertThrown!ValueInjectionException(autowire(container, new MyConfig()));
|
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