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;
import poodinis.registration : Registration, singleInstance, toConcreteTypeListString;
import poodinis.registration : Registration, singleInstance,
toConcreteTypeListString, initializeFactoryType;
import poodinis.autowire : AutowiredRegistration, AutowireInstantiationContext;
import poodinis.factory : ConstructorInjectingInstanceFactory;
import poodinis.valueinjection : ValueInjectionException;
@ -202,7 +203,7 @@ synchronized class DependencyContainer
auto instanceFactory = new ConstructorInjectingInstanceFactory!ConcreteType(this);
auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType,
instanceFactory, this);
newRegistration.singleInstance();
newRegistration.initializeFactoryType().singleInstance();
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.
*
@ -102,8 +125,9 @@ class Registration
*/
public Registration singleInstance(Registration registration)
{
registration.instanceFactory.factoryParameters = InstanceFactoryParameters(
registration.instanceType, CreatesSingleton.yes);
auto params = registration.copyFactoryParameters();
params.createsSingleton = CreatesSingleton.yes;
registration.setFactoryParameters(params);
return registration;
}
@ -112,8 +136,10 @@ public Registration singleInstance(Registration registration)
*/
public Registration newInstance(Registration registration)
{
registration.instanceFactory.factoryParameters = InstanceFactoryParameters(
registration.instanceType, CreatesSingleton.no);
auto params = registration.copyFactoryParameters();
params.createsSingleton = CreatesSingleton.no;
params.existingInstance = null;
registration.setFactoryParameters(params);
return registration;
}
@ -122,22 +148,23 @@ public Registration newInstance(Registration registration)
*/
public Registration existingInstance(Registration registration, Object instance)
{
registration.instanceFactory.factoryParameters = InstanceFactoryParameters(
registration.instanceType, CreatesSingleton.yes, instance);
auto params = registration.copyFactoryParameters();
params.createsSingleton = CreatesSingleton.yes;
params.existingInstance = instance;
registration.setFactoryParameters(params);
return registration;
}
/**
* Scopes registrations to create new instances using the given initializer delegate.
*/
public Registration initializedBy(T)(Registration registration, T delegate() initializer)
if(is(T == class) || is(T == interface))
public Registration initializedBy(T)(Registration registration, T delegate() initializer)
if (is(T == class) || is(T == interface))
{
registration.instanceFactory.factoryParameters = InstanceFactoryParameters(
registration.instanceType, CreatesSingleton.no, null, {
return cast(Object) initializer();
});
auto params = registration.copyFactoryParameters();
params.createsSingleton = CreatesSingleton.no;
params.factoryMethod = () => cast(Object) initializer();
registration.setFactoryParameters(params);
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)
{
registration.instanceFactory.factoryParameters = InstanceFactoryParameters(
registration.instanceType, CreatesSingleton.yes, null, {
return cast(Object) initializer();
});
auto params = registration.copyFactoryParameters();
params.createsSingleton = CreatesSingleton.yes;
params.factoryMethod = () => cast(Object) initializer();
registration.setFactoryParameters(params);
return registration;
}

View file

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

View file

@ -24,7 +24,7 @@ version (unittest)
unittest
{
Registration registration = new Registration(null, typeid(TestType),
new InstanceFactory(), null);
new InstanceFactory(), null).initializeFactoryType();
auto chainedRegistration = registration.singleInstance();
auto instance1 = registration.getInstance();
auto instance2 = registration.getInstance();
@ -38,7 +38,7 @@ version (unittest)
unittest
{
Registration registration = new Registration(null, typeid(TestType),
new InstanceFactory(), null);
new InstanceFactory(), null).initializeFactoryType();
auto chainedRegistration = registration.newInstance();
auto instance1 = registration.getInstance();
auto instance2 = registration.getInstance();
@ -55,7 +55,7 @@ version (unittest)
auto expectedInstance = new TestType();
auto chainedRegistration = registration.existingInstance(expectedInstance);
auto actualInstance = registration.getInstance();
assert(expectedInstance is expectedInstance,
assert(expectedInstance is actualInstance,
"Registration with existing instance scope did not return the same instance");
assert(registration is chainedRegistration,
"Registration returned by scope setting is not the same as the registration being set");
@ -65,10 +65,11 @@ version (unittest)
unittest
{
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),
typeid(TestImplementation), new InstanceFactory(), null).singleInstance()
.linkTo(firstRegistration);
typeid(TestImplementation), new InstanceFactory(), null).initializeFactoryType()
.singleInstance().linkTo(firstRegistration);
auto firstInstance = firstRegistration.getInstance();
auto secondInstance = secondRegistration.getInstance();
@ -76,4 +77,63 @@ version (unittest)
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);
}
}