Add @Qualifier UDA for qualifying members typed by supertype

This commit is contained in:
Mike Bierlee 2014-12-13 22:06:11 +01:00
parent 9c749c0cb6
commit 1166d2811a
3 changed files with 98 additions and 16 deletions

View file

@ -130,6 +130,14 @@ container.register!(Color, Blue);
container.register!(Color, Red);
auto blueInstance = container.resolve!(Color, Blue);
```
If you want to autowire a type registered to multiple concrete types, use the @Qualifier UDA:
```d
class BluePaint {
@Autowire
@Qualifier!Blue
public Color color;
}
```
If you registered multiple concrete types to the same supertype and you do not resolve using a qualifier, a ResolveException is throw stating that there are multiple candidates for the type to be resolved.
Known issues

View file

@ -18,30 +18,61 @@ debug {
class Autowire{};
struct Qualifier(T) {
T qualifier;
}
alias Autowired = Autowire;
public void autowire(Type)(DependencyContainer container, Type instance) {
// For the love of god, refactor this!
debug {
auto memberType = typeid(Type);
auto instanceType = typeid(Type);
auto instanceAddress = &instance;
writeln(format("DEBUG: Autowiring members of [%s@%s]", memberType, instanceAddress));
writeln(format("DEBUG: Autowiring members of [%s@%s]", instanceType, instanceAddress));
}
foreach (member ; __traits(allMembers, Type)) {
static if(__traits(compiles, __traits(getMember, Type, member)) && __traits(compiles, __traits(getAttributes, __traits(getMember, Type, member)))) {
foreach(attribute; __traits(getAttributes, __traits(getMember, Type, member))) {
static if (is(attribute : Autowire)) {
foreach(autowireAttribute; __traits(getAttributes, __traits(getMember, Type, member))) {
static if (is(autowireAttribute : Autowire)) {
if (__traits(getMember, instance, member) is null) {
alias TypeTuple!(__traits(getMember, instance, member)) memberReference;
auto autowirableInstance = container.resolve!(typeof(memberReference));
alias MemberType = typeof(memberReference)[0];
debug {
auto autowirableType = typeid(typeof(memberReference[0]));
auto autowireableAddress = &autowirableInstance;
writeln(format("DEBUG: Autowire instance [%s@%s] to [%s@%s].%s", autowirableType, autowireableAddress, memberType, instanceAddress, member));
string qualifiedInstanceTypeString = typeid(MemberType).toString;
}
__traits(getMember, instance, member) = autowirableInstance;
MemberType qualifiedInstance;
auto resolvedThroughQualifier = false;
foreach (qualifierAttribute; __traits(getAttributes, __traits(getMember, Type, member))) {
static if (is(qualifierAttribute == Qualifier!T, T)) {
alias QualifierType = typeof(qualifierAttribute.qualifier);
qualifiedInstance = container.resolve!(typeof(memberReference), QualifierType);
debug {
qualifiedInstanceTypeString = typeid(QualifierType).toString;
}
resolvedThroughQualifier = true;
break;
}
}
if (!resolvedThroughQualifier) {
qualifiedInstance = container.resolve!(typeof(memberReference));
}
__traits(getMember, instance, member) = qualifiedInstance;
debug {
auto qualifiedInstanceAddress = &qualifiedInstance;
writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", qualifiedInstanceTypeString, qualifiedInstanceAddress, instanceType, instanceAddress, member));
}
}
break;
}
}
}

View file

@ -10,8 +10,7 @@ import poodinis.autowire;
import std.exception;
version(unittest) {
class ComponentA {
}
class ComponentA {}
class ComponentB {
public @Autowire ComponentA componentA;
@ -21,11 +20,9 @@ version(unittest) {
}
}
interface InterfaceA {
}
interface InterfaceA {}
class ComponentC : InterfaceA {
}
class ComponentC : InterfaceA {}
class ComponentD {
public @Autowire InterfaceA componentC = null;
@ -62,6 +59,24 @@ version(unittest) {
}
}
class ComponentX : InterfaceA {}
class MonkeyShine {
@Autowire
@Qualifier!ComponentX
public InterfaceA component;
}
class BootstrapBootstrap {
@Autowire
@Qualifier!ComponentX
public InterfaceA componentX;
@Autowire
@Qualifier!ComponentC
public InterfaceA componentC;
}
// Test autowiring concrete type to existing instance
unittest {
auto container = new DependencyContainer();
@ -132,4 +147,32 @@ version(unittest) {
assert(componentDeclarationCocktail.componentA !is null, "Autowiring class with non-assignable declarations failed");
}
// Test autowire class with qualifier
unittest {
auto container = new DependencyContainer();
container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX);
auto componentX = container.resolve!(InterfaceA, ComponentX);
auto monkeyShine = new MonkeyShine();
container.autowire(monkeyShine);
assert(monkeyShine.component is componentX, "Autowiring class with qualifier failed");
}
// Test autowire class with multiple qualifiers
unittest {
auto container = new DependencyContainer();
container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX);
auto componentC = container.resolve!(InterfaceA, ComponentC);
auto componentX = container.resolve!(InterfaceA, ComponentX);
auto bootstrapBootstrap = new BootstrapBootstrap();
container.autowire(bootstrapBootstrap);
assert(bootstrapBootstrap.componentX is componentX, "Autowiring class with multiple qualifiers failed");
assert(bootstrapBootstrap.componentC is componentC, "Autowiring class with multiple qualifiers failed");
}
}