Fix chained registration scopes getting rid of initializedBy's factory method

This commit is contained in:
Mike Bierlee 2021-08-24 23:17:26 +03:00
parent 8bde8963c2
commit 4faf7f2e47
4 changed files with 114 additions and 27 deletions

View file

@ -13,7 +13,8 @@
module poodinis.container; module poodinis.container;
import poodinis.registration : Registration, singleInstance, toConcreteTypeListString; import poodinis.registration : Registration, singleInstance,
toConcreteTypeListString, initializeFactoryType;
import poodinis.autowire : AutowiredRegistration, AutowireInstantiationContext; import poodinis.autowire : AutowiredRegistration, AutowireInstantiationContext;
import poodinis.factory : ConstructorInjectingInstanceFactory; import poodinis.factory : ConstructorInjectingInstanceFactory;
import poodinis.valueinjection : ValueInjectionException; import poodinis.valueinjection : ValueInjectionException;
@ -202,7 +203,7 @@ synchronized class DependencyContainer
auto instanceFactory = new ConstructorInjectingInstanceFactory!ConcreteType(this); auto instanceFactory = new ConstructorInjectingInstanceFactory!ConcreteType(this);
auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType,
instanceFactory, this); instanceFactory, this);
newRegistration.singleInstance(); newRegistration.initializeFactoryType().singleInstance();
static if (!is(SuperType == ConcreteType)) static if (!is(SuperType == ConcreteType))
{ {

View file

@ -95,6 +95,29 @@ class Registration
} }
} }
private InstanceFactoryParameters copyFactoryParameters(Registration registration)
{
return registration.instanceFactory.factoryParameters;
}
private void setFactoryParameters(Registration registration, InstanceFactoryParameters newParameters)
{
registration.instanceFactory.factoryParameters = newParameters;
}
/**
* Sets the registration's instance factory type the same as the registration's.
*
* This is not a registration scope. Typically used by Poodinis internally only.
*/
public Registration initializeFactoryType(Registration registration)
{
auto params = registration.copyFactoryParameters();
params.instanceType = registration.instanceType;
registration.setFactoryParameters(params);
return registration;
}
/** /**
* Scopes registrations to return the same instance every time a given registration is resolved. * Scopes registrations to return the same instance every time a given registration is resolved.
* *
@ -102,8 +125,9 @@ class Registration
*/ */
public Registration singleInstance(Registration registration) public Registration singleInstance(Registration registration)
{ {
registration.instanceFactory.factoryParameters = InstanceFactoryParameters( auto params = registration.copyFactoryParameters();
registration.instanceType, CreatesSingleton.yes); params.createsSingleton = CreatesSingleton.yes;
registration.setFactoryParameters(params);
return registration; return registration;
} }
@ -112,8 +136,10 @@ public Registration singleInstance(Registration registration)
*/ */
public Registration newInstance(Registration registration) public Registration newInstance(Registration registration)
{ {
registration.instanceFactory.factoryParameters = InstanceFactoryParameters( auto params = registration.copyFactoryParameters();
registration.instanceType, CreatesSingleton.no); params.createsSingleton = CreatesSingleton.no;
params.existingInstance = null;
registration.setFactoryParameters(params);
return registration; return registration;
} }
@ -122,8 +148,10 @@ public Registration newInstance(Registration registration)
*/ */
public Registration existingInstance(Registration registration, Object instance) public Registration existingInstance(Registration registration, Object instance)
{ {
registration.instanceFactory.factoryParameters = InstanceFactoryParameters( auto params = registration.copyFactoryParameters();
registration.instanceType, CreatesSingleton.yes, instance); params.createsSingleton = CreatesSingleton.yes;
params.existingInstance = instance;
registration.setFactoryParameters(params);
return registration; return registration;
} }
@ -131,13 +159,12 @@ public Registration existingInstance(Registration registration, Object instance)
* Scopes registrations to create new instances using the given initializer delegate. * Scopes registrations to create new instances using the given initializer delegate.
*/ */
public Registration initializedBy(T)(Registration registration, T delegate() initializer) public Registration initializedBy(T)(Registration registration, T delegate() initializer)
if(is(T == class) || is(T == interface)) if (is(T == class) || is(T == interface))
{ {
registration.instanceFactory.factoryParameters = InstanceFactoryParameters( auto params = registration.copyFactoryParameters();
registration.instanceType, CreatesSingleton.no, null, { params.createsSingleton = CreatesSingleton.no;
return cast(Object) initializer(); params.factoryMethod = () => cast(Object) initializer();
}); registration.setFactoryParameters(params);
return registration; return registration;
} }
@ -146,11 +173,10 @@ public Registration initializedBy(T)(Registration registration, T delegate() ini
*/ */
public Registration initializedOnceBy(T : Object)(Registration registration, T delegate() initializer) public Registration initializedOnceBy(T : Object)(Registration registration, T delegate() initializer)
{ {
registration.instanceFactory.factoryParameters = InstanceFactoryParameters( auto params = registration.copyFactoryParameters();
registration.instanceType, CreatesSingleton.yes, null, { params.createsSingleton = CreatesSingleton.yes;
return cast(Object) initializer(); params.factoryMethod = () => cast(Object) initializer();
}); registration.setFactoryParameters(params);
return registration; return registration;
} }

View file

@ -129,7 +129,7 @@ version (unittest)
container.register!ComponentA; container.register!ComponentA;
auto registration = new AutowiredRegistration!ComponentB(typeid(ComponentB), auto registration = new AutowiredRegistration!ComponentB(typeid(ComponentB),
new InstanceFactory(), container).singleInstance(); new InstanceFactory(), container).initializeFactoryType().singleInstance();
auto instance = cast(ComponentB) registration.getInstance( auto instance = cast(ComponentB) registration.getInstance(
new AutowireInstantiationContext()); new AutowireInstantiationContext());

View file

@ -24,7 +24,7 @@ version (unittest)
unittest unittest
{ {
Registration registration = new Registration(null, typeid(TestType), Registration registration = new Registration(null, typeid(TestType),
new InstanceFactory(), null); new InstanceFactory(), null).initializeFactoryType();
auto chainedRegistration = registration.singleInstance(); auto chainedRegistration = registration.singleInstance();
auto instance1 = registration.getInstance(); auto instance1 = registration.getInstance();
auto instance2 = registration.getInstance(); auto instance2 = registration.getInstance();
@ -38,7 +38,7 @@ version (unittest)
unittest unittest
{ {
Registration registration = new Registration(null, typeid(TestType), Registration registration = new Registration(null, typeid(TestType),
new InstanceFactory(), null); new InstanceFactory(), null).initializeFactoryType();
auto chainedRegistration = registration.newInstance(); auto chainedRegistration = registration.newInstance();
auto instance1 = registration.getInstance(); auto instance1 = registration.getInstance();
auto instance2 = registration.getInstance(); auto instance2 = registration.getInstance();
@ -55,7 +55,7 @@ version (unittest)
auto expectedInstance = new TestType(); auto expectedInstance = new TestType();
auto chainedRegistration = registration.existingInstance(expectedInstance); auto chainedRegistration = registration.existingInstance(expectedInstance);
auto actualInstance = registration.getInstance(); auto actualInstance = registration.getInstance();
assert(expectedInstance is expectedInstance, assert(expectedInstance is actualInstance,
"Registration with existing instance scope did not return the same instance"); "Registration with existing instance scope did not return the same instance");
assert(registration is chainedRegistration, assert(registration is chainedRegistration,
"Registration returned by scope setting is not the same as the registration being set"); "Registration returned by scope setting is not the same as the registration being set");
@ -65,10 +65,11 @@ version (unittest)
unittest unittest
{ {
Registration firstRegistration = new Registration(typeid(TestInterface), Registration firstRegistration = new Registration(typeid(TestInterface),
typeid(TestImplementation), new InstanceFactory(), null).singleInstance(); typeid(TestImplementation), new InstanceFactory(), null).initializeFactoryType()
.singleInstance();
Registration secondRegistration = new Registration(typeid(TestImplementation), Registration secondRegistration = new Registration(typeid(TestImplementation),
typeid(TestImplementation), new InstanceFactory(), null).singleInstance() typeid(TestImplementation), new InstanceFactory(), null).initializeFactoryType()
.linkTo(firstRegistration); .singleInstance().linkTo(firstRegistration);
auto firstInstance = firstRegistration.getInstance(); auto firstInstance = firstRegistration.getInstance();
auto secondInstance = secondRegistration.getInstance(); auto secondInstance = secondRegistration.getInstance();
@ -76,4 +77,63 @@ version (unittest)
assert(firstInstance is secondInstance); assert(firstInstance is secondInstance);
} }
// Test custom factory method via initializedBy
unittest
{
Registration registration = new Registration(typeid(TestInterface),
typeid(TestImplementation), new InstanceFactory(), null);
registration.initializedBy({
auto instance = new TestImplementation();
instance.someContent = "createdbyinitializer";
return instance;
});
TestImplementation instanceOne = cast(TestImplementation) registration.getInstance();
TestImplementation instanceTwo = cast(TestImplementation) registration.getInstance();
assert(instanceOne.someContent == "createdbyinitializer");
assert(instanceTwo.someContent == "createdbyinitializer");
assert(instanceOne !is instanceTwo);
}
// Test custom factory method via initializedOnceBy
unittest
{
Registration registration = new Registration(typeid(TestInterface),
typeid(TestImplementation), new InstanceFactory(), null);
registration.initializedOnceBy({
auto instance = new TestImplementation();
instance.someContent = "createdbyinitializer";
return instance;
});
TestImplementation instanceOne = cast(TestImplementation) registration.getInstance();
TestImplementation instanceTwo = cast(TestImplementation) registration.getInstance();
assert(instanceOne.someContent == "createdbyinitializer");
assert(instanceTwo.someContent == "createdbyinitializer");
assert(instanceOne is instanceTwo);
}
// Test chaining single/new instance scope to initializedBy will not overwrite the factory method.
unittest
{
Registration registration = new Registration(typeid(TestInterface),
typeid(TestImplementation), new InstanceFactory(), null);
registration.initializedBy({
auto instance = new TestImplementation();
instance.someContent = "createdbyinitializer";
return instance;
});
registration.singleInstance();
TestImplementation instanceOne = cast(TestImplementation) registration.getInstance();
TestImplementation instanceTwo = cast(TestImplementation) registration.getInstance();
assert(instanceOne.someContent == "createdbyinitializer");
assert(instanceTwo.someContent == "createdbyinitializer");
assert(instanceOne is instanceTwo);
}
} }