diff --git a/README.md b/README.md index f614548..8ad96c9 100644 --- a/README.md +++ b/README.md @@ -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() { diff --git a/TUTORIAL.md b/TUTORIAL.md index 979de01..916a82b 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -75,7 +75,7 @@ class ExampleClassA {} class ExampleClassB { @Autowire - public ExampleClassA dependency; + private ExampleClassA dependency; } dependencies.register!ExampleClassA; @@ -83,7 +83,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 diff --git a/source/poodinis/autowire.d b/source/poodinis/autowire.d index 39a9049..8d73861 100644 --- a/source/poodinis/autowire.d +++ b/source/poodinis/autowire.d @@ -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; } } } diff --git a/test/poodinis/autowiretest.d b/test/poodinis/autowiretest.d index e723d0f..e3ae57b 100644 --- a/test/poodinis/autowiretest.d +++ b/test/poodinis/autowiretest.d @@ -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();