Improve performance of Dynamic Application Factories

Also added a method overload to provide a Package Name.
Useful for DX based second generation packages. Now each package can have their own bindings.
This commit is contained in:
wim
2023-09-01 15:39:25 +01:00
parent b658e6226b
commit a0fc1bd10d
22 changed files with 416 additions and 139 deletions
@@ -32,53 +32,38 @@ public virtual class fflib_DynamicServiceFactory
extends fflib_DynamicAppFactory
implements fflib_IServiceFactory
{
public static final fflib_AppBindingType SERVICE_BINDING_TYPE = fflib_AppBindingType.Service;
protected Map<System.Type, Object> mockServiceImplByObjectType = new Map<System.Type, Object>();
protected fflib_ClassicServiceFactory serviceFactory;
public fflib_DynamicServiceFactory(fflib_IAppBindingResolver resolver)
{
this(resolver, null);
}
public fflib_DynamicServiceFactory(fflib_IAppBindingResolver resolver, String packageName)
{
this.resolver = resolver;
this.packageName = packageName;
}
public Object newInstance(Type serviceInterfaceType)
{
if (hasMock(serviceInterfaceType)) return getMock(serviceInterfaceType);
if (serviceFactory == null) loadBindings();
List<fflib_IAppBinding> bindings = resolver
.byType(SERVICE_BINDING_TYPE)
.byInterfaceType(serviceInterfaceType)
.bySharingMode(sharingMode)
.resolve();
if (bindings.isEmpty())
throw new DeveloperException(
String.format(
'Unable to find service binding for {0} with sharing more {1}',
new List<String>
{
serviceInterfaceType.getName(),
sharingMode.name()
}
)
);
return bindings.get(0).newImplInstance();
return this.serviceFactory.newInstance(serviceInterfaceType);
}
public void replaceWith(Type serviceInterfaceType, Type replacementImplType)
{
resolver.byType(SERVICE_BINDING_TYPE)
.byInterfaceType(serviceInterfaceType)
.bySharingMode(sharingMode)
.resolve()
.get(0) // TODO - validate that there are any resolved bindings
.setImplementationType(replacementImplType);
if (serviceFactory == null) loadBindings();
this.serviceFactory.replaceWith(serviceInterfaceType, replacementImplType);
}
public void setMock(Type serviceInterfaceType, Object serviceImpl)
{
super.setMock(serviceInterfaceType, serviceImpl);
if (serviceFactory == null) loadBindings();
this.serviceFactory.setMock(serviceInterfaceType, serviceImpl);
}
public fflib_DynamicServiceFactory setSharingMode(fflib_SharingMode sharingMode)
@@ -87,5 +72,22 @@ public virtual class fflib_DynamicServiceFactory
return this;
}
private void loadBindings()
{
fflib_IAppBindings appBindings = new fflib_AppBindings(resolver.resolve());
// If a package name is provide we should filter on package name
if (String.isNotBlank(this.packageName))
{
appBindings = appBindings.selectByPackageName(this.packageName);
}
Map<Type, Type> implementationByInterface =
appBindings.selectByType(fflib_AppBindingType.Service)
.getImplementationByInterface();
this.serviceFactory = new fflib_ClassicServiceFactory(implementationByInterface);
}
public class DeveloperException extends Exception {}
}