mirror of
https://github.com/mbierlee/poodinis.git
synced 2024-11-15 04:04:01 +01:00
Finish refactoring for now
It's still not perfect, but traits are real difficult to work with.
This commit is contained in:
parent
d1e3366549
commit
a5f6a1dc32
|
@ -1,166 +1,165 @@
|
||||||
/**
|
/**
|
||||||
* Contains functionality for autowiring dependencies using a dependency container.
|
* Contains functionality for autowiring dependencies using a dependency container.
|
||||||
*
|
*
|
||||||
* This module is used in a dependency container for autowiring dependencies when resolving them.
|
* This module is used in a dependency container for autowiring dependencies when resolving them.
|
||||||
* You typically only need this module if you want inject dependencies into a class instance not
|
* You typically only need this module if you want inject dependencies into a class instance not
|
||||||
* managed by a dependency container.
|
* managed by a dependency container.
|
||||||
*
|
*
|
||||||
* Part of the Poodinis Dependency Injection framework.
|
* Part of the Poodinis Dependency Injection framework.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Mike Bierlee, m.bierlee@lostmoment.com
|
* Mike Bierlee, m.bierlee@lostmoment.com
|
||||||
* Copyright: 2014-2015 Mike Bierlee
|
* Copyright: 2014-2015 Mike Bierlee
|
||||||
* License:
|
* License:
|
||||||
* This software is licensed under the terms of the MIT license.
|
* This software is licensed under the terms of the MIT license.
|
||||||
* The full terms of the license can be found in the LICENSE file.
|
* The full terms of the license can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module poodinis.autowire;
|
module poodinis.autowire;
|
||||||
|
|
||||||
public import poodinis.container;
|
public import poodinis.container;
|
||||||
|
|
||||||
import std.typetuple;
|
import std.typetuple;
|
||||||
import std.exception;
|
import std.exception;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.string;
|
import std.string;
|
||||||
|
|
||||||
struct UseMemberType {};
|
struct UseMemberType {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UDA for annotating class members as candidates for autowiring.
|
* UDA for annotating class members as candidates for autowiring.
|
||||||
*
|
*
|
||||||
* Optionally a template parameter can be supplied to specify the type of a qualified class. The qualified type
|
* Optionally a template parameter can be supplied to specify the type of a qualified class. The qualified type
|
||||||
* of a concrete class is used to autowire members declared by supertype. If no qualifier is supplied, the type
|
* of a concrete class is used to autowire members declared by supertype. If no qualifier is supplied, the type
|
||||||
* of the member is used as qualifier.
|
* of the member is used as qualifier.
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
* Annotate member of class to be autowired:
|
* Annotate member of class to be autowired:
|
||||||
* ---
|
* ---
|
||||||
* class Car {
|
* class Car {
|
||||||
* @Autowire
|
* @Autowire
|
||||||
* public Engine engine;
|
* public Engine engine;
|
||||||
* }
|
* }
|
||||||
* ---
|
* ---
|
||||||
*
|
*
|
||||||
* Annotate member of class with qualifier:
|
* Annotate member of class with qualifier:
|
||||||
* ---
|
* ---
|
||||||
* class FuelEngine : Engine { ... }
|
* class FuelEngine : Engine { ... }
|
||||||
* class ElectricEngine : Engine { ... }
|
* class ElectricEngine : Engine { ... }
|
||||||
*
|
*
|
||||||
* class HybridCar {
|
* class HybridCar {
|
||||||
* @Autowire!FuelEngine
|
* @Autowire!FuelEngine
|
||||||
* public Engine fuelEngine;
|
* public Engine fuelEngine;
|
||||||
*
|
*
|
||||||
* @Autowire!ElectricEngine
|
* @Autowire!ElectricEngine
|
||||||
* public Engine electricEngine;
|
* public Engine electricEngine;
|
||||||
* }
|
* }
|
||||||
* ---
|
* ---
|
||||||
* The members of an instance of "HybridCar" will now be autowired properly, because the autowire mechanism will
|
* The members of an instance of "HybridCar" will now be autowired properly, because the autowire mechanism will
|
||||||
* autowire member "fuelEngine" as if it's of type "FuelEngine". This means that the members of instance "fuelEngine"
|
* autowire member "fuelEngine" as if it's of type "FuelEngine". This means that the members of instance "fuelEngine"
|
||||||
* will also be autowired because the autowire mechanism knows that member "fuelEngine" is an instance of "FuelEngine"
|
* will also be autowired because the autowire mechanism knows that member "fuelEngine" is an instance of "FuelEngine"
|
||||||
*/
|
*/
|
||||||
struct Autowire(QualifierType = UseMemberType) {
|
struct Autowire(QualifierType = UseMemberType) {
|
||||||
QualifierType qualifier;
|
QualifierType qualifier;
|
||||||
};
|
};
|
||||||
|
|
||||||
private void printDebugAutowiredInstance(TypeInfo instanceType, void* instanceAddress) {
|
private void printDebugAutowiredInstance(TypeInfo instanceType, void* instanceAddress) {
|
||||||
writeln(format("DEBUG: Autowiring members of [%s@%s]", instanceType, instanceAddress));
|
writeln(format("DEBUG: Autowiring members of [%s@%s]", instanceType, instanceAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Autowires members of a given instance using dependencies registered in the given container.
|
* Autowires members of a given instance using dependencies registered in the given container.
|
||||||
*
|
*
|
||||||
* All public members of the given instance, which are annotated using the "Autowire" UDA, are autowired.
|
* All public members of the given instance, which are annotated using the "Autowire" UDA, are autowired.
|
||||||
* All members are resolved using the given container. Qualifiers are used to determine the type of class to
|
* All members are resolved using the given container. Qualifiers are used to determine the type of class to
|
||||||
* resolve for any member of instance.
|
* resolve for any member of instance.
|
||||||
*
|
*
|
||||||
* Note that private members will not be autowired because the autowiring mechanism is not able to by-pass
|
* Note that private members will not be autowired because the autowiring mechanism is not able to by-pass
|
||||||
* member visibility protection.
|
* member visibility protection.
|
||||||
*
|
*
|
||||||
* See_Also: Autowire
|
* See_Also: Autowire
|
||||||
*/
|
*/
|
||||||
public void autowire(Type)(DependencyContainer container, Type instance) {
|
public void autowire(Type)(DependencyContainer container, Type instance) {
|
||||||
debug(poodinisVerbose) {
|
debug(poodinisVerbose) {
|
||||||
printDebugAutowiredInstance(typeid(Type), &instance);
|
printDebugAutowiredInstance(typeid(Type), &instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (member ; __traits(allMembers, Type)) {
|
foreach (member ; __traits(allMembers, Type)) {
|
||||||
autowireMember!member(container, instance);
|
autowireMember!member(container, instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printDebugAutowiringCandidate(TypeInfo candidateInstanceType, void* candidateInstanceAddress, TypeInfo instanceType, void* instanceAddress, string member) {
|
private void printDebugAutowiringCandidate(TypeInfo candidateInstanceType, void* candidateInstanceAddress, TypeInfo instanceType, void* instanceAddress, string member) {
|
||||||
writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", candidateInstanceType, candidateInstanceAddress, instanceType, instanceAddress, member));
|
writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", candidateInstanceType, candidateInstanceAddress, instanceType, instanceAddress, member));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void autowireMember(string member, Type)(DependencyContainer container, Type instance) {
|
private void autowireMember(string member, Type)(DependencyContainer container, Type instance) {
|
||||||
// For the love of god, refactor this! <-- Doing it, bro!
|
static if(__traits(compiles, __traits(getMember, instance, member)) && __traits(compiles, __traits(getAttributes, __traits(getMember, instance, member)))) {
|
||||||
static if(__traits(compiles, __traits(getMember, instance, member)) && __traits(compiles, __traits(getAttributes, __traits(getMember, instance, member)))) {
|
foreach(autowireAttribute; __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)) {
|
||||||
static if (__traits(isSame, autowireAttribute, Autowire) || is(autowireAttribute == Autowire!T, T)) {
|
if (__traits(getMember, instance, member) is null) {
|
||||||
if (__traits(getMember, instance, member) is null) {
|
alias MemberType = typeof(__traits(getMember, instance, member));
|
||||||
alias MemberType = typeof(__traits(getMember, instance, member));
|
|
||||||
|
debug(poodinisVerbose) {
|
||||||
debug(poodinisVerbose) {
|
TypeInfo qualifiedInstanceType = typeid(MemberType);
|
||||||
TypeInfo qualifiedInstanceType = typeid(MemberType);
|
}
|
||||||
}
|
|
||||||
|
MemberType qualifiedInstance;
|
||||||
MemberType qualifiedInstance;
|
static if (is(autowireAttribute == Autowire!T, T) && !is(autowireAttribute.qualifier == UseMemberType)) {
|
||||||
static if (is(autowireAttribute == Autowire!T, T) && !is(autowireAttribute.qualifier == UseMemberType)) {
|
alias QualifierType = typeof(autowireAttribute.qualifier);
|
||||||
alias QualifierType = typeof(autowireAttribute.qualifier);
|
qualifiedInstance = container.resolve!(MemberType, QualifierType);
|
||||||
qualifiedInstance = container.resolve!(MemberType, QualifierType);
|
debug(poodinisVerbose) {
|
||||||
debug(poodinisVerbose) {
|
qualifiedInstanceType = typeid(QualifierType);
|
||||||
qualifiedInstanceType = typeid(QualifierType);
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
qualifiedInstance = container.resolve!(MemberType);
|
||||||
qualifiedInstance = container.resolve!(MemberType);
|
}
|
||||||
}
|
|
||||||
|
__traits(getMember, instance, member) = qualifiedInstance;
|
||||||
__traits(getMember, instance, member) = qualifiedInstance;
|
|
||||||
|
debug(poodinisVerbose) {
|
||||||
debug(poodinisVerbose) {
|
printDebugAutowiringCandidate(qualifiedInstanceType, &qualifiedInstance, typeid(Type), &instance, member);
|
||||||
printDebugAutowiringCandidate(qualifiedInstanceType, &qualifiedInstance, typeid(Type), &instance, member);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
/**
|
* Autowire the given instance using the globally available dependency container.
|
||||||
* Autowire the given instance using the globally available dependency container.
|
*
|
||||||
*
|
* See_Also: DependencyContainer
|
||||||
* See_Also: DependencyContainer
|
*/
|
||||||
*/
|
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 {
|
||||||
class AutowiredRegistration(RegistrationType : Object) : Registration {
|
private DependencyContainer container;
|
||||||
private DependencyContainer container;
|
|
||||||
|
public this(TypeInfo registeredType, DependencyContainer container) {
|
||||||
public this(TypeInfo registeredType, DependencyContainer container) {
|
enforce(!(container is null), "Argument 'container' is null. Autowired registrations need to autowire using a container.");
|
||||||
enforce(!(container is null), "Argument 'container' is null. Autowired registrations need to autowire using a container.");
|
this.container = container;
|
||||||
this.container = container;
|
super(registeredType, typeid(RegistrationType));
|
||||||
super(registeredType, typeid(RegistrationType));
|
}
|
||||||
}
|
|
||||||
|
public override Object getInstance(InstantiationContext context = new AutowireInstantiationContext()) {
|
||||||
public override Object getInstance(InstantiationContext context = new AutowireInstantiationContext()) {
|
RegistrationType instance = cast(RegistrationType) super.getInstance(context);
|
||||||
RegistrationType instance = cast(RegistrationType) super.getInstance(context);
|
|
||||||
|
AutowireInstantiationContext autowireContext = cast(AutowireInstantiationContext) context;
|
||||||
AutowireInstantiationContext autowireContext = cast(AutowireInstantiationContext) context;
|
enforce(!(autowireContext is null), "Given instantiation context type could not be cast to an AutowireInstantiationContext. If you relied on using the default assigned context: make sure you're calling getInstance() on an instance of type AutowiredRegistration!");
|
||||||
enforce(!(autowireContext is null), "Given instantiation context type could not be cast to an AutowireInstantiationContext. If you relied on using the default assigned context: make sure you're calling getInstance() on an instance of type AutowiredRegistration!");
|
if (autowireContext.autowireInstance) {
|
||||||
if (autowireContext.autowireInstance) {
|
container.autowire(instance);
|
||||||
container.autowire(instance);
|
}
|
||||||
}
|
|
||||||
|
return instance;
|
||||||
return instance;
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
}
|
|
||||||
|
class AutowireInstantiationContext : InstantiationContext {
|
||||||
class AutowireInstantiationContext : InstantiationContext {
|
public bool autowireInstance = true;
|
||||||
public bool autowireInstance = true;
|
}
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue