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 { class DataWriter {
@Autowire @Autowire
public Database database; // Automatically injected when class is resolved private Database database; // Automatically injected when class is resolved
} }
void main() { void main() {

View file

@ -70,7 +70,7 @@ class ExampleClassA {}
class ExampleClassB { class ExampleClassB {
@Autowire @Autowire
public ExampleClassA dependency; private ExampleClassA dependency;
} }
dependencies.register!ExampleClassA; dependencies.register!ExampleClassA;
@ -78,7 +78,7 @@ auto exampleInstance = new ExampleClassB();
dependencies.autowire(exampleInstance); dependencies.autowire(exampleInstance);
assert(exampleInstance.dependency !is null); 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: Dependencies are automatically autowired when a class is resolved. So when you register ExampleClassB, its member, *dependency*, is automatically autowired:
```d ```d

View file

@ -101,8 +101,8 @@ public void autowire(Type)(shared(DependencyContainer) container, Type instance)
printDebugAutowiredInstance(typeid(Type), &instance); printDebugAutowiredInstance(typeid(Type), &instance);
} }
foreach (member ; __traits(allMembers, Type)) { foreach(idx, name; FieldNameTuple!Type) {
autowireMember!member(container, instance); autowireMember!(name, idx, Type)(container, instance);
} }
} }
@ -114,19 +114,18 @@ 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)); 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) { private void autowireMember(string member, size_t tupleIdx, 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, Type.tupleof[tupleIdx])) {
foreach(autowireAttribute; __traits(getAttributes, __traits(getMember, instance, member))) {
static if (__traits(isSame, autowireAttribute, Autowire) || is(autowireAttribute == Autowire!T, T)) { static if (__traits(isSame, autowireAttribute, Autowire) || is(autowireAttribute == Autowire!T, T)) {
if (__traits(getMember, instance, member) is null) { if (instance.tupleof[tupleIdx] is null) {
alias MemberType = typeof(__traits(getMember, instance, member)); 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) { static if (isDynamicArray!MemberType) {
alias MemberElementType = ElementType!MemberType; alias MemberElementType = ElementType!MemberType;
auto instances = container.resolveAll!MemberElementType; auto instances = container.resolveAll!MemberElementType;
__traits(getMember, instance, member) = instances; instance.tupleof[tupleIdx] = instances;
debug(poodinisVerbose) { debug(poodinisVerbose) {
printDebugAutowiringArray(typeid(MemberElementType), typeid(Type), &instance, member); printDebugAutowiringArray(typeid(MemberElementType), typeid(Type), &instance, member);
} }
@ -146,7 +145,7 @@ private void autowireMember(string member, Type)(shared(DependencyContainer) con
qualifiedInstance = createOrResolveInstance!(MemberType, MemberType, assignNewInstance)(container); qualifiedInstance = createOrResolveInstance!(MemberType, MemberType, assignNewInstance)(container);
} }
__traits(getMember, instance, member) = qualifiedInstance; instance.tupleof[tupleIdx] = qualifiedInstance;
debug(poodinisVerbose) { debug(poodinisVerbose) {
printDebugAutowiringCandidate(qualifiedInstanceType, &qualifiedInstance, typeid(Type), &instance, member); printDebugAutowiringCandidate(qualifiedInstanceType, &qualifiedInstance, typeid(Type), &instance, member);
@ -157,7 +156,6 @@ private void autowireMember(string member, Type)(shared(DependencyContainer) con
break; break;
} }
} }
}
} }
private QualifierType createOrResolveInstance(MemberType, QualifierType, bool createNew)(shared(DependencyContainer) container) { private QualifierType createOrResolveInstance(MemberType, QualifierType, bool createNew)(shared(DependencyContainer) container) {

View file

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