mirror of
https://github.com/mbierlee/poodinis.git
synced 2024-11-15 04:04:01 +01:00
Add registration class that will autowire instances itself
This commit is contained in:
parent
82ea4369b8
commit
9d931f511b
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue