From 4ebeeb9c9fce13e79c846de6f309cb81ad21728e Mon Sep 17 00:00:00 2001 From: heromyth Date: Sun, 9 Feb 2020 23:43:11 +0800 Subject: [PATCH 1/6] isFunction may not work --- source/poodinis/autowire.d | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/poodinis/autowire.d b/source/poodinis/autowire.d index fb5ae01..22d0d29 100644 --- a/source/poodinis/autowire.d +++ b/source/poodinis/autowire.d @@ -267,9 +267,10 @@ class AutowiredRegistration(RegistrationType : Object) : Registration { void delegate() preDestructor = null; foreach (memberName; __traits(allMembers, RegistrationType)) { mixin(createImportsString!RegistrationType); + enum QualifiedName = fullyQualifiedName!RegistrationType ~ `.` ~ memberName; static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) && __traits(getProtection, __traits(getMember, instance, memberName)) == "public" - && isFunction!(mixin(fullyQualifiedName!RegistrationType ~ `.` ~ memberName)) + && isFunction!(QualifiedName) && hasUDA!(__traits(getMember, instance, memberName), PreDestroy)) { preDestructor = &__traits(getMember, instance, memberName); } From b9d4bd1b83d6accc1055a0713a167a1e440d0639 Mon Sep 17 00:00:00 2001 From: heromyth Date: Sun, 9 Feb 2020 23:46:06 +0800 Subject: [PATCH 2/6] Register with an initializer. --- example/constructorinjection/app.d | 16 +++++-- source/poodinis/container.d | 67 +++++++++++++++++++++++++----- 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/example/constructorinjection/app.d b/example/constructorinjection/app.d index f270262..183a0aa 100644 --- a/example/constructorinjection/app.d +++ b/example/constructorinjection/app.d @@ -36,9 +36,17 @@ class Calendar { } } +import std.stdio; + class HardwareClock { // Parameterless constructors will halt any further selection of constructors. - this() {} + this() { + writeln("default constructor"); + } + + this(string name) { + writeln(name); + } // As a result, this constructor will not be used when HardwareClock is created. this(Calendar calendar) { @@ -46,7 +54,6 @@ class HardwareClock { } public void doThings() { - import std.stdio; writeln("Things are being done!"); } } @@ -57,7 +64,10 @@ void main() { auto dependencies = new shared DependencyContainer(); dependencies.register!Scheduler; dependencies.register!Calendar; - dependencies.register!HardwareClock; + dependencies.register!HardwareClock( { + writeln("Running the creator"); + return new HardwareClock("clock name"); + }); auto scheduler = dependencies.resolve!Scheduler; scheduler.scheduleJob(); diff --git a/source/poodinis/container.d b/source/poodinis/container.d index 7a2e42f..73b6a15 100644 --- a/source/poodinis/container.d +++ b/source/poodinis/container.d @@ -30,6 +30,8 @@ debug { import std.stdio; } +alias InjectionInitializer(T) = T delegate(); + /** * Exception thrown when errors occur while resolving a type in a dependency container. */ @@ -147,6 +149,11 @@ synchronized class DependencyContainer { return register!(ConcreteType, ConcreteType)(options); } + Registration register(ConcreteType)(InjectionInitializer!ConcreteType creator, + RegistrationOption options = RegistrationOption.none) { + return register!(ConcreteType, ConcreteType)(creator, options); + } + /** * Register a dependency by super type. * @@ -164,7 +171,9 @@ synchronized class DependencyContainer { * * See_Also: singleInstance, newInstance, existingInstance, RegistrationOption */ - public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption options = RegistrationOption.none) if (!is(ConcreteType == struct)) { + public Registration register(SuperType, ConcreteType : SuperType)( + RegistrationOption options = RegistrationOption.none) if (!is(ConcreteType == struct)) { + TypeInfo registeredType = typeid(SuperType); TypeInfo_Class concreteType = typeid(ConcreteType); @@ -192,6 +201,44 @@ synchronized class DependencyContainer { return newRegistration; } + /** + * + */ + Registration register(SuperType, ConcreteType : SuperType)(InjectionInitializer!ConcreteType creator, + RegistrationOption options = RegistrationOption.none) if (!is(ConcreteType == struct)) { + + TypeInfo registeredType = typeid(SuperType); + TypeInfo_Class concreteType = typeid(ConcreteType); + + debug(poodinisVerbose) { + writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString())); + } + + auto existingRegistration = getExistingRegistration(registeredType, concreteType); + if (existingRegistration) { + return existingRegistration; + } + + InstanceFactory instanceFactory = new class InstanceFactory { + protected override Object createInstance() { + return creator(); + } + }; + + auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, instanceFactory, this); + newRegistration.singleInstance(); + + static if (!is(SuperType == ConcreteType)) { + if (!hasOption(options, persistentRegistrationOptions, RegistrationOption.doNotAddConcreteTypeRegistration)) { + auto concreteTypeRegistration = register!ConcreteType; + concreteTypeRegistration.linkTo(newRegistration); + } + } + + registrations[registeredType] ~= cast(shared(Registration)) newRegistration; + return newRegistration; + } + private bool hasOption(OptionType)(OptionType options, OptionType persistentOptions, OptionType option) { return ((options | persistentOptions) & option) != 0; } @@ -391,16 +438,16 @@ synchronized class DependencyContainer { } private void callPostConstructors(Type)(Type instance) { - foreach (memberName; __traits(allMembers, Type)) { - mixin(createImportsString!Type); + // foreach (memberName; __traits(allMembers, Type)) { + // mixin(createImportsString!Type); - static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) - && __traits(getProtection, __traits(getMember, instance, memberName)) == "public" - && isFunction!(mixin(fullyQualifiedName!Type ~ `.` ~ memberName)) - && hasUDA!(__traits(getMember, instance, memberName), PostConstruct)) { - __traits(getMember, instance, memberName)(); - } - } + // static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) + // && __traits(getProtection, __traits(getMember, instance, memberName)) == "public" + // && isFunction!(mixin(fullyQualifiedName!Type ~ `.` ~ memberName)) + // && hasUDA!(__traits(getMember, instance, memberName), PostConstruct)) { + // __traits(getMember, instance, memberName)(); + // } + // } } /** From 15d8c7e754398632f76c3c99d1a3d6e2e2dde037 Mon Sep 17 00:00:00 2001 From: heromyth Date: Mon, 10 Feb 2020 15:34:00 +0800 Subject: [PATCH 3/6] Restore callPostConstructors --- source/poodinis/container.d | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/poodinis/container.d b/source/poodinis/container.d index 73b6a15..5b0f759 100644 --- a/source/poodinis/container.d +++ b/source/poodinis/container.d @@ -438,16 +438,16 @@ synchronized class DependencyContainer { } private void callPostConstructors(Type)(Type instance) { - // foreach (memberName; __traits(allMembers, Type)) { - // mixin(createImportsString!Type); - - // static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) - // && __traits(getProtection, __traits(getMember, instance, memberName)) == "public" - // && isFunction!(mixin(fullyQualifiedName!Type ~ `.` ~ memberName)) - // && hasUDA!(__traits(getMember, instance, memberName), PostConstruct)) { - // __traits(getMember, instance, memberName)(); - // } - // } + foreach (memberName; __traits(allMembers, Type)) { + mixin(createImportsString!Type); + enum QualifiedName = fullyQualifiedName!Type ~ `.` ~ memberName; + static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) + && __traits(getProtection, __traits(getMember, instance, memberName)) == "public" + && isFunction!(QualifiedName) + && hasUDA!(__traits(getMember, instance, memberName), PostConstruct)) { + __traits(getMember, instance, memberName)(); + } + } } /** From 55726e84db0ec4435c759e457f46c2035be6f3f8 Mon Sep 17 00:00:00 2001 From: heromyth Date: Tue, 11 Feb 2020 10:19:08 +0800 Subject: [PATCH 4/6] All the unittests passed --- source/poodinis/autowire.d | 2 +- source/poodinis/container.d | 2 +- source/poodinis/polyfill.d | 13 ++++++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/source/poodinis/autowire.d b/source/poodinis/autowire.d index 22d0d29..80864aa 100644 --- a/source/poodinis/autowire.d +++ b/source/poodinis/autowire.d @@ -270,7 +270,7 @@ class AutowiredRegistration(RegistrationType : Object) : Registration { enum QualifiedName = fullyQualifiedName!RegistrationType ~ `.` ~ memberName; static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) && __traits(getProtection, __traits(getMember, instance, memberName)) == "public" - && isFunction!(QualifiedName) + && isFunction1!(mixin(QualifiedName)) && hasUDA!(__traits(getMember, instance, memberName), PreDestroy)) { preDestructor = &__traits(getMember, instance, memberName); } diff --git a/source/poodinis/container.d b/source/poodinis/container.d index 5b0f759..47e8c95 100644 --- a/source/poodinis/container.d +++ b/source/poodinis/container.d @@ -443,7 +443,7 @@ synchronized class DependencyContainer { enum QualifiedName = fullyQualifiedName!Type ~ `.` ~ memberName; static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) && __traits(getProtection, __traits(getMember, instance, memberName)) == "public" - && isFunction!(QualifiedName) + && isFunction1!(mixin(QualifiedName)) && hasUDA!(__traits(getMember, instance, memberName), PostConstruct)) { __traits(getMember, instance, memberName)(); } diff --git a/source/poodinis/polyfill.d b/source/poodinis/polyfill.d index 0d6dc99..33d5d2a 100644 --- a/source/poodinis/polyfill.d +++ b/source/poodinis/polyfill.d @@ -43,21 +43,24 @@ static if (!__traits(compiles, basicExceptionCtors)) { } } -static if (!__traits(compiles, isFunction)) { - template isFunction(X...) if (X.length == 1) +static if (!__traits(compiles, isFunction1)) { + template isFunction1(X...) { + static if (X.length > 1) { + enum isFunction1 = false; + } else static if (is(typeof(&X[0]) U : U*) && is(U == function) || is(typeof(&X[0]) U == delegate)) { // x is a (nested) function symbol. - enum isFunction = true; + enum isFunction1 = true; } else static if (is(X[0] T)) { // x is a type. Take the type of it and examine. - enum isFunction = is(T == function); + enum isFunction1 = is(T == function); } else - enum isFunction = false; + enum isFunction1 = false; } } From 3b11c4aec4410b8fd406fa98192fb4a2a0ba96a4 Mon Sep 17 00:00:00 2001 From: heromyth Date: Wed, 26 Feb 2020 16:14:12 +0800 Subject: [PATCH 5/6] Add a constuction handler --- example/postconstructorpredestructor/app.d | 10 ++++++++-- source/poodinis/factory.d | 10 ++++++++++ source/poodinis/registration.d | 7 ++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/example/postconstructorpredestructor/app.d b/example/postconstructorpredestructor/app.d index f72f3dc..fb7c963 100644 --- a/example/postconstructorpredestructor/app.d +++ b/example/postconstructorpredestructor/app.d @@ -42,8 +42,14 @@ class AClass { public void main() { auto container = new shared DependencyContainer(); - container.register!ADependency; - container.register!AClass; + container.register!(ADependency).onConstructed((Object obj) { + writeln("ADependency constructed"); + }); + + container.register!(AClass).onConstructed((Object obj) { + writeln("AClass constructed"); + }); + auto instance = container.resolve!AClass; // Will cause the post constructor to be called. container.removeRegistration!AClass; // Will cause the pre destructor to be called. diff --git a/source/poodinis/factory.d b/source/poodinis/factory.d index aae3f52..5d80d5b 100644 --- a/source/poodinis/factory.d +++ b/source/poodinis/factory.d @@ -22,6 +22,7 @@ import std.stdio; alias CreatesSingleton = Flag!"CreatesSingleton"; alias InstanceFactoryMethod = Object delegate(); +alias InstanceEventHandler = void delegate(Object instance); class InstanceCreationException : Exception { this(string message, string file = __FILE__, size_t line = __LINE__) { @@ -39,6 +40,7 @@ struct InstanceFactoryParameters { class InstanceFactory { private Object instance = null; private InstanceFactoryParameters _factoryParameters; + private InstanceEventHandler _constructionHandler; this() { factoryParameters = InstanceFactoryParameters(); @@ -75,9 +77,17 @@ class InstanceFactory { } instance = _factoryParameters.factoryMethod(); + if(_constructionHandler !is null) { + _constructionHandler(instance); + } + return instance; } + void onConstructed(InstanceEventHandler handler) { + _constructionHandler = handler; + } + private void printDebugUseExistingInstance() { if (_factoryParameters.instanceType !is null) { writeln(format("DEBUG: Existing instance returned of type %s", _factoryParameters.instanceType.toString())); diff --git a/source/poodinis/registration.d b/source/poodinis/registration.d index cfaca3b..1a4970b 100644 --- a/source/poodinis/registration.d +++ b/source/poodinis/registration.d @@ -60,7 +60,6 @@ class Registration { return linkedRegistration.getInstance(context); } - if (instanceFactory is null) { throw new InstanceCreationException("No instance factory defined for registration of type " ~ registeredType.toString()); } @@ -72,6 +71,12 @@ class Registration { this.linkedRegistration = registration; return this; } + + Registration onConstructed(InstanceEventHandler handler) { + if(instanceFactory !is null) + instanceFactory.onConstructed(handler); + return this; + } } /** From 0c8c1434f7f55501c5bc68aac56e5938d7760242 Mon Sep 17 00:00:00 2001 From: heromyth Date: Wed, 11 Mar 2020 09:55:15 +0800 Subject: [PATCH 6/6] Check if a Type is registered --- source/poodinis/container.d | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/poodinis/container.d b/source/poodinis/container.d index 47e8c95..ae9c36b 100644 --- a/source/poodinis/container.d +++ b/source/poodinis/container.d @@ -373,6 +373,12 @@ synchronized class DependencyContainer { } } + bool isRegistered(RegistrationType)() { + TypeInfo typeInfo = typeid(RegistrationType); + auto candidates = typeInfo in registrations; + return candidates !is null; + } + private QualifierType resolveAutowiredInstance(QualifierType)(Registration registration) { QualifierType instance; if (!(cast(Registration[]) autowireStack).canFind(registration)) {