allow autowiring private fields too

This commit is contained in:
Stephan Dilly 2016-02-09 18:01:21 +01:00
parent 7d206e8964
commit 7d2ba1bef9
4 changed files with 45 additions and 37 deletions

View file

@ -31,7 +31,7 @@ class RelationalDatabase : Database {}
class DataWriter {
@Autowire
public Database database; // Automatically injected when class is resolved
private Database database; // Automatically injected when class is resolved
}
void main() {

View file

@ -70,7 +70,7 @@ class ExampleClassA {}
class ExampleClassB {
@Autowire
public ExampleClassA dependency;
private ExampleClassA dependency;
}
dependencies.register!ExampleClassA;
@ -78,7 +78,7 @@ auto exampleInstance = new ExampleClassB();
dependencies.autowire(exampleInstance);
assert(exampleInstance.dependency !is null);
```
At the moment, it is only possible to autowire public members or properties.
It is possible to autowire public and private members.
Dependencies are automatically autowired when a class is resolved. So when you register ExampleClassB, its member, *dependency*, is automatically autowired:
```d

View file

@ -101,8 +101,8 @@ public void autowire(Type)(shared(DependencyContainer) container, Type instance)
printDebugAutowiredInstance(typeid(Type), &instance);
}
foreach (member ; __traits(allMembers, Type)) {
autowireMember!member(container, instance);
foreach(idx, name; FieldNameTuple!Type) {
autowireMember!(name, idx, Type)(container, instance);
}
}
@ -114,48 +114,46 @@ private void printDebugAutowiringArray(TypeInfo superTypeInfo, TypeInfo instance
writeln(format("DEBUG: Autowired all registered instances of super type %s to [%s@%s].%s", superTypeInfo, instanceType, instanceAddress, member));
}
private void autowireMember(string member, Type)(shared(DependencyContainer) container, Type instance) {
static if(__traits(compiles, __traits(getMember, instance, member)) && __traits(compiles, __traits(getAttributes, __traits(getMember, instance, member)))) {
foreach(autowireAttribute; __traits(getAttributes, __traits(getMember, instance, member))) {
static if (__traits(isSame, autowireAttribute, Autowire) || is(autowireAttribute == Autowire!T, T)) {
if (__traits(getMember, instance, member) is null) {
alias MemberType = typeof(__traits(getMember, instance, member));
private void autowireMember(string member, size_t tupleIdx, Type)(shared(DependencyContainer) container, Type instance) {
foreach(autowireAttribute; __traits(getAttributes, Type.tupleof[tupleIdx])) {
static if (__traits(isSame, autowireAttribute, Autowire) || is(autowireAttribute == Autowire!T, T)) {
if (instance.tupleof[tupleIdx] is null) {
alias MemberType = typeof(Type.tupleof[tupleIdx]);
enum assignNewInstance = hasUDA!(__traits(getMember, instance, member), AssignNewInstance);
enum assignNewInstance = hasUDA!(Type.tupleof[tupleIdx], AssignNewInstance);
static if (isDynamicArray!MemberType) {
alias MemberElementType = ElementType!MemberType;
auto instances = container.resolveAll!MemberElementType;
__traits(getMember, instance, member) = instances;
static if (isDynamicArray!MemberType) {
alias MemberElementType = ElementType!MemberType;
auto instances = container.resolveAll!MemberElementType;
instance.tupleof[tupleIdx] = instances;
debug(poodinisVerbose) {
printDebugAutowiringArray(typeid(MemberElementType), typeid(Type), &instance, member);
}
} else {
debug(poodinisVerbose) {
TypeInfo qualifiedInstanceType = typeid(MemberType);
}
MemberType qualifiedInstance;
static if (is(autowireAttribute == Autowire!T, T) && !is(autowireAttribute.qualifier == UseMemberType)) {
alias QualifierType = typeof(autowireAttribute.qualifier);
qualifiedInstance = createOrResolveInstance!(MemberType, QualifierType, assignNewInstance)(container);
debug(poodinisVerbose) {
printDebugAutowiringArray(typeid(MemberElementType), typeid(Type), &instance, member);
qualifiedInstanceType = typeid(QualifierType);
}
} else {
debug(poodinisVerbose) {
TypeInfo qualifiedInstanceType = typeid(MemberType);
}
qualifiedInstance = createOrResolveInstance!(MemberType, MemberType, assignNewInstance)(container);
}
MemberType qualifiedInstance;
static if (is(autowireAttribute == Autowire!T, T) && !is(autowireAttribute.qualifier == UseMemberType)) {
alias QualifierType = typeof(autowireAttribute.qualifier);
qualifiedInstance = createOrResolveInstance!(MemberType, QualifierType, assignNewInstance)(container);
debug(poodinisVerbose) {
qualifiedInstanceType = typeid(QualifierType);
}
} else {
qualifiedInstance = createOrResolveInstance!(MemberType, MemberType, assignNewInstance)(container);
}
instance.tupleof[tupleIdx] = qualifiedInstance;
__traits(getMember, instance, member) = qualifiedInstance;
debug(poodinisVerbose) {
printDebugAutowiringCandidate(qualifiedInstanceType, &qualifiedInstance, typeid(Type), &instance, member);
}
debug(poodinisVerbose) {
printDebugAutowiringCandidate(qualifiedInstanceType, &qualifiedInstance, typeid(Type), &instance, member);
}
}
break;
}
break;
}
}
}

View file

@ -22,6 +22,7 @@ version(unittest) {
class ComponentD {
public @Autowire InterfaceA componentC = null;
private @Autowire InterfaceA privateComponentC = null;
}
class DummyAttribute{};
@ -87,6 +88,15 @@ version(unittest) {
assert(componentD.componentC !is null, "Autowirable dependency failed to autowire");
}
// Test autowiring private members
unittest {
shared(DependencyContainer) container = new DependencyContainer();
container.register!(InterfaceA, ComponentC);
auto componentD = new ComponentD();
container.autowire!(ComponentD)(componentD);
assert(componentD.privateComponentC is componentD.componentC, "Autowire private dependency failed");
}
// Test autowiring will only happen once
unittest {
shared(DependencyContainer) container = new DependencyContainer();