Add registration class that will autowire instances itself

This commit is contained in:
Mike Bierlee 2015-01-25 15:07:11 +01:00
parent 82ea4369b8
commit 9d931f511b
2 changed files with 64 additions and 36 deletions

View file

@ -10,6 +10,7 @@ module poodinis.autowire;
public import poodinis.container; public import poodinis.container;
import std.typetuple; import std.typetuple;
import std.exception;
debug { debug {
import std.stdio; import std.stdio;
@ -81,3 +82,19 @@ mixin template AutowireConstructor() {
public void globalAutowire(Type)(Type instance) { public void globalAutowire(Type)(Type instance) {
DependencyContainer.getInstance().autowire(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;
}
}

View file

@ -11,69 +11,69 @@ import std.exception;
version(unittest) { version(unittest) {
class ComponentA {} class ComponentA {}
class ComponentB { class ComponentB {
public @Autowire ComponentA componentA; public @Autowire ComponentA componentA;
public bool componentIsNull() { public bool componentIsNull() {
return componentA is null; return componentA is null;
} }
} }
interface InterfaceA {} interface InterfaceA {}
class ComponentC : InterfaceA {} class ComponentC : InterfaceA {}
class ComponentD { class ComponentD {
public @Autowire InterfaceA componentC = null; public @Autowire InterfaceA componentC = null;
public bool componentIsNull() { public bool componentIsNull() {
return componentC is null; return componentC is null;
} }
} }
class DummyAttribute{}; class DummyAttribute{};
class ComponentE { class ComponentE {
@DummyAttribute @DummyAttribute
public ComponentC componentC; public ComponentC componentC;
} }
class ComponentF { class ComponentF {
@Autowired @Autowired
public ComponentA componentA; public ComponentA componentA;
mixin AutowireConstructor; mixin AutowireConstructor;
} }
class ComponentDeclarationCocktail { class ComponentDeclarationCocktail {
alias noomer = int; alias noomer = int;
@Autowire @Autowire
public ComponentA componentA; public ComponentA componentA;
public void doesNothing() { public void doesNothing() {
} }
~this(){ ~this(){
} }
} }
class ComponentX : InterfaceA {} class ComponentX : InterfaceA {}
class MonkeyShine { class MonkeyShine {
@Autowire!ComponentX @Autowire!ComponentX
public InterfaceA component; public InterfaceA component;
} }
class BootstrapBootstrap { class BootstrapBootstrap {
@Autowire!ComponentX @Autowire!ComponentX
public InterfaceA componentX; public InterfaceA componentX;
@Autowire!ComponentC @Autowire!ComponentC
public InterfaceA componentC; public InterfaceA componentC;
} }
// Test autowiring concrete type to existing instance // Test autowiring concrete type to existing instance
unittest { unittest {
auto container = new DependencyContainer(); auto container = new DependencyContainer();
@ -82,7 +82,7 @@ version(unittest) {
container.autowire!(ComponentB)(componentB); container.autowire!(ComponentB)(componentB);
assert(!componentB.componentIsNull(), "Autowirable dependency failed to autowire"); assert(!componentB.componentIsNull(), "Autowirable dependency failed to autowire");
} }
// Test autowiring interface type to existing instance // Test autowiring interface type to existing instance
unittest { unittest {
auto container = new DependencyContainer(); auto container = new DependencyContainer();
@ -91,7 +91,7 @@ version(unittest) {
container.autowire!(ComponentD)(componentD); container.autowire!(ComponentD)(componentD);
assert(!componentD.componentIsNull(), "Autowirable dependency failed to autowire"); assert(!componentD.componentIsNull(), "Autowirable dependency failed to autowire");
} }
// Test autowiring will only happen once // Test autowiring will only happen once
unittest { unittest {
auto container = new DependencyContainer(); auto container = new DependencyContainer();
@ -103,14 +103,14 @@ version(unittest) {
auto actualComponent = componentD.componentC; auto actualComponent = componentD.componentC;
assert(expectedComponent is actualComponent, "Autowiring the second time wired a different instance"); assert(expectedComponent is actualComponent, "Autowiring the second time wired a different instance");
} }
// Test autowiring unregistered type // Test autowiring unregistered type
unittest { unittest {
auto container = new DependencyContainer(); auto container = new DependencyContainer();
auto componentD = new ComponentD(); auto componentD = new ComponentD();
assertThrown!(ResolveException)(container.autowire!(ComponentD)(componentD), "Autowiring unregistered type should throw ResolveException"); assertThrown!(ResolveException)(container.autowire!(ComponentD)(componentD), "Autowiring unregistered type should throw ResolveException");
} }
// Test autowiring member with non-autowire attribute does not autowire // Test autowiring member with non-autowire attribute does not autowire
unittest { unittest {
auto container = new DependencyContainer(); auto container = new DependencyContainer();
@ -118,7 +118,7 @@ version(unittest) {
container.autowire!ComponentE(componentE); container.autowire!ComponentE(componentE);
assert(componentE.componentC is null, "Autowiring should not occur for members with attributes other than @Autowire"); assert(componentE.componentC is null, "Autowiring should not occur for members with attributes other than @Autowire");
} }
// Test autowire in constructor // Test autowire in constructor
unittest { unittest {
auto container = DependencyContainer.getInstance(); auto container = DependencyContainer.getInstance();
@ -127,37 +127,37 @@ version(unittest) {
auto autowiredComponentA = componentF.componentA; auto autowiredComponentA = componentF.componentA;
container.register!(ComponentF).existingInstance(componentF); container.register!(ComponentF).existingInstance(componentF);
assert(componentF.componentA !is null, "Constructor did not autowire component F"); assert(componentF.componentA !is null, "Constructor did not autowire component F");
auto resolvedComponentF = container.resolve!ComponentF; auto resolvedComponentF = container.resolve!ComponentF;
assert(resolvedComponentF.componentA is autowiredComponentA, "Resolving instance of ComponentF rewired members"); assert(resolvedComponentF.componentA is autowiredComponentA, "Resolving instance of ComponentF rewired members");
container.clearAllRegistrations(); container.clearAllRegistrations();
} }
// Test autowire class with alias declaration // Test autowire class with alias declaration
unittest { unittest {
auto container = new DependencyContainer(); auto container = new DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
auto componentDeclarationCocktail = new ComponentDeclarationCocktail(); auto componentDeclarationCocktail = new ComponentDeclarationCocktail();
container.autowire(componentDeclarationCocktail); container.autowire(componentDeclarationCocktail);
assert(componentDeclarationCocktail.componentA !is null, "Autowiring class with non-assignable declarations failed"); assert(componentDeclarationCocktail.componentA !is null, "Autowiring class with non-assignable declarations failed");
} }
// Test autowire class with qualifier // Test autowire class with qualifier
unittest { unittest {
auto container = new DependencyContainer(); auto container = new DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX); container.register!(InterfaceA, ComponentX);
auto componentX = container.resolve!(InterfaceA, ComponentX); auto componentX = container.resolve!(InterfaceA, ComponentX);
auto monkeyShine = new MonkeyShine(); auto monkeyShine = new MonkeyShine();
container.autowire(monkeyShine); container.autowire(monkeyShine);
assert(monkeyShine.component is componentX, "Autowiring class with qualifier failed"); assert(monkeyShine.component is componentX, "Autowiring class with qualifier failed");
} }
// Test autowire class with multiple qualifiers // Test autowire class with multiple qualifiers
unittest { unittest {
auto container = new DependencyContainer(); auto container = new DependencyContainer();
@ -165,11 +165,22 @@ version(unittest) {
container.register!(InterfaceA, ComponentX); container.register!(InterfaceA, ComponentX);
auto componentC = container.resolve!(InterfaceA, ComponentC); auto componentC = container.resolve!(InterfaceA, ComponentC);
auto componentX = container.resolve!(InterfaceA, ComponentX); auto componentX = container.resolve!(InterfaceA, ComponentX);
auto bootstrapBootstrap = new BootstrapBootstrap(); auto bootstrapBootstrap = new BootstrapBootstrap();
container.autowire(bootstrapBootstrap); container.autowire(bootstrapBootstrap);
assert(bootstrapBootstrap.componentX is componentX, "Autowiring class with multiple qualifiers failed"); assert(bootstrapBootstrap.componentX is componentX, "Autowiring class with multiple qualifiers failed");
assert(bootstrapBootstrap.componentC is componentC, "Autowiring class with multiple qualifiers failed"); assert(bootstrapBootstrap.componentC is componentC, "Autowiring class with multiple qualifiers failed");
} }
}
// 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());
}
}