diff --git a/README.md b/README.md index a8269fe..8927536 100644 --- a/README.md +++ b/README.md @@ -123,12 +123,11 @@ assert(instance.dependency !is null); If an interface is to be autowired, you must register a concrete class by interface. Any class registered by concrete type can only be injected when a dependency on a concrete type is autowired. ###Circular dependencies -Poodinis can autowire circular dependencies to a certain degree. See known issues for current limitations on this. For now you might want to consider if your design really needs circular dependencies. +Poodinis can autowire circular dependencies when they are registered with singleInstance or existingInstance registration scopes. See Known issues for the limitations on newInstance scopes. Known issues ------------ -* Circular dependencies down the dependency tree still fails if the dependencies don't refer to the type being resolved initially. -* Due to preventive measures of recursion issues in circular dependencies, registrations which are supposed to yield new instances will not autowire classes for which a recursive resolve is detected. +* Due to preventive measures of recursion issues in circular dependencies, registrations which are supposed to yield new instances will not autowire classes for which a circular dependency is detected. A new instance will be resolved but the instance's members will not be autowired. Future Work ----------- diff --git a/source/poodinis/container.d b/source/poodinis/container.d index 78f68f1..0fc4bce 100644 --- a/source/poodinis/container.d +++ b/source/poodinis/container.d @@ -9,6 +9,7 @@ module poodinis.container; import std.string; import std.array; +import std.algorithm; public import poodinis.registration; public import poodinis.autowire; @@ -31,7 +32,7 @@ class Container { private Registration[TypeInfo] registrations; - private Registration* registrationBeingResolved; + private Registration*[] autowireStack; public Registration register(ConcreteType)() { return register!(ConcreteType, ConcreteType)(); @@ -54,18 +55,12 @@ class Container { throw new ResolveException("Type not registered.", resolveType); } - auto initialResolve = false; - if (registrationBeingResolved is null) { - registrationBeingResolved = registration; - initialResolve = true; - } - RegistrationType instance = cast(RegistrationType) registration.getInstance(); - if (initialResolve || registrationBeingResolved !is registration) { + + if (!autowireStack.canFind(registration)) { + autowireStack ~= registration; this.autowire!(RegistrationType)(instance); - } - if (initialResolve) { - registrationBeingResolved = null; + autowireStack.popBack(); } return instance; diff --git a/test/poodinis/containertest.d b/test/poodinis/containertest.d index 1e5a6d8..f833f4c 100644 --- a/test/poodinis/containertest.d +++ b/test/poodinis/containertest.d @@ -58,6 +58,21 @@ version(unittest) { public Eenie eenie; } + class Ittie { + @Autowire + public Bittie bittie; + } + + class Bittie { + @Autowire + public Banana banana; + } + + class Banana { + @Autowire + public Bittie bittie; + } + // Test register concrete type unittest { auto container = new Container(); @@ -185,4 +200,28 @@ version(unittest) { assert(eenie.meenie.moe.eenie is eenie, "Autowiring third-degree circular dependency failed"); } + + // Test autowiring deep circular dependencies + unittest { + auto container = new Container(); + container.register!Ittie; + container.register!Bittie; + container.register!Banana; + + auto ittie = container.resolve!Ittie; + + assert(ittie.bittie is ittie.bittie.banana.bittie, "Autowiring deep dependencies failed."); + } + + // Test autowiring deep circular dependencies with newInstance scope does not autowire new instance second time + unittest { + auto container = new Container(); + container.register!(Ittie).newInstance(); + container.register!(Bittie).newInstance(); + container.register!(Banana).newInstance(); + + auto ittie = container.resolve!Ittie; + + assert(ittie.bittie.banana.bittie.banana is null, "Autowiring deep dependencies with newInstance scope autowired a reoccuring type."); + } } \ No newline at end of file