diff --git a/source/poodinis/autowire.d b/source/poodinis/autowire.d index cd3d9c2..00f103c 100644 --- a/source/poodinis/autowire.d +++ b/source/poodinis/autowire.d @@ -10,6 +10,7 @@ module poodinis.autowire; public import poodinis.container; import std.typetuple; +import std.exception; debug { import std.stdio; @@ -81,3 +82,19 @@ mixin template AutowireConstructor() { public void globalAutowire(Type)(Type instance) { DependencyContainer.getInstance().autowire(instance); } + +class AutowiredRegistration(RegistrationType : Object) : Registration { + private DependencyContainer container; + + public this(TypeInfo registeredType, DependencyContainer container) { + enforce(!(container is null), "Argument 'container' is null. Autowired registrations need to autowire using a container."); + this.container = container; + super(registeredType, typeid(RegistrationType)); + } + + public override Object getInstance() { + RegistrationType instance = cast(RegistrationType) super.getInstance(); + container.autowire(instance); + return instance; + } +} diff --git a/test/poodinis/autowiretest.d b/test/poodinis/autowiretest.d index 09ba841..0aa3cca 100644 --- a/test/poodinis/autowiretest.d +++ b/test/poodinis/autowiretest.d @@ -11,69 +11,69 @@ import std.exception; version(unittest) { class ComponentA {} - + class ComponentB { public @Autowire ComponentA componentA; - + public bool componentIsNull() { return componentA is null; } } - + interface InterfaceA {} - + class ComponentC : InterfaceA {} - + class ComponentD { public @Autowire InterfaceA componentC = null; - + public bool componentIsNull() { return componentC is null; } } - + class DummyAttribute{}; - + class ComponentE { @DummyAttribute public ComponentC componentC; } - + class ComponentF { @Autowired public ComponentA componentA; - + mixin AutowireConstructor; } - + class ComponentDeclarationCocktail { alias noomer = int; - + @Autowire public ComponentA componentA; - + public void doesNothing() { } - + ~this(){ } } - + class ComponentX : InterfaceA {} - + class MonkeyShine { @Autowire!ComponentX public InterfaceA component; } - + class BootstrapBootstrap { @Autowire!ComponentX public InterfaceA componentX; - + @Autowire!ComponentC public InterfaceA componentC; } - + // Test autowiring concrete type to existing instance unittest { auto container = new DependencyContainer(); @@ -82,7 +82,7 @@ version(unittest) { container.autowire!(ComponentB)(componentB); assert(!componentB.componentIsNull(), "Autowirable dependency failed to autowire"); } - + // Test autowiring interface type to existing instance unittest { auto container = new DependencyContainer(); @@ -91,7 +91,7 @@ version(unittest) { container.autowire!(ComponentD)(componentD); assert(!componentD.componentIsNull(), "Autowirable dependency failed to autowire"); } - + // Test autowiring will only happen once unittest { auto container = new DependencyContainer(); @@ -103,14 +103,14 @@ version(unittest) { auto actualComponent = componentD.componentC; assert(expectedComponent is actualComponent, "Autowiring the second time wired a different instance"); } - + // Test autowiring unregistered type unittest { auto container = new DependencyContainer(); auto componentD = new ComponentD(); assertThrown!(ResolveException)(container.autowire!(ComponentD)(componentD), "Autowiring unregistered type should throw ResolveException"); } - + // Test autowiring member with non-autowire attribute does not autowire unittest { auto container = new DependencyContainer(); @@ -118,7 +118,7 @@ version(unittest) { container.autowire!ComponentE(componentE); assert(componentE.componentC is null, "Autowiring should not occur for members with attributes other than @Autowire"); } - + // Test autowire in constructor unittest { auto container = DependencyContainer.getInstance(); @@ -127,37 +127,37 @@ version(unittest) { auto autowiredComponentA = componentF.componentA; container.register!(ComponentF).existingInstance(componentF); assert(componentF.componentA !is null, "Constructor did not autowire component F"); - + auto resolvedComponentF = container.resolve!ComponentF; assert(resolvedComponentF.componentA is autowiredComponentA, "Resolving instance of ComponentF rewired members"); - + container.clearAllRegistrations(); } - + // Test autowire class with alias declaration unittest { auto container = new DependencyContainer(); container.register!ComponentA; auto componentDeclarationCocktail = new ComponentDeclarationCocktail(); - + container.autowire(componentDeclarationCocktail); - + 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(); @@ -165,11 +165,22 @@ version(unittest) { 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"); } -} \ No newline at end of file + + // Test getting instance from autowired registration will autowire instance + unittest { + auto container = new DependencyContainer(); + container.register!ComponentA; + + auto registration = new AutowiredRegistration!ComponentB(typeid(ComponentB), container).singleInstance(); + auto instance = cast(ComponentB) registration.getInstance(); + + assert(!instance.componentIsNull()); + } +}