Dagger 2: how to change provided dependencies at runtime - dependency-injection

In order to learn Dagger 2 i decided to rewrite my application but I'm stuck with finding the proper solution for the following problem.
For the purpose of this example let's assume we have an interface called Mode:
public interface Mode {
Object1 obj1();
//some other methods providing objects for app
}
and two implementations:
NormalMode and DemoMode.
Mode is stored in singleton so it could be accessed from anywhere within application.
public enum ModeManager {
INSTANCE,;
private Mode mode;
public Mode mode() {
if (mode == null)
mode = new NormalMode();
return mode;
}
public void mode(Mode mode) { //to switch modules at runtime
this.mode = mode;
}
}
The NormalMode is switched to DemoMode at runtime (let's say, when user clickcs on background couple of times)
public void backgroundClicked5Times(){
ModeManager.INSTANCE.mode(new DemoMode());
//from now on every object that uses Mode will get Demo implementations, great!
}
So first I got rid of the singleton and defined Modes as Dagger 2 modules:
#Module
public class NormalModeModule {
#Provides
public Object1 provideObject1() {
return new NormalObject1();
}
}
#Module
public class DemoModeModule {
#Provides
public Object1 provideObject1() {
return new DemoObject1();
}
}
Now in the method backgroundClicked5Times instead of dealing with singleton I would like to replace NormalModeModule with DemoModeModule in DAG so the other classes that need Object1 would get a DemoObject1 implementation from now on.
How can I do that in Dagger?
Thanks in advance.

Maybe you can consider using multibindings?
#Module
public class NormalModeModule {
#Provides
#IntoMap
#StringKey("normal")
public Object1 provideObject1() {
return new NormalObject1();
}
}
#Module
public class DemoModeModule {
#Provides
#IntoMap
#StringKey("demo")
public Object1 provideObject1() {
return new DemoObject1();
}
}
and when using Mode:
#Inject
Map<String, Mode> modes;
//or you perfer lazy initialization:
Map<String, Provider<Mode>> modes;
public void backgroundClicked5Times(){
ModeManager.INSTANCE.mode(modes.get("demo"));
//if you are using Provider:
ModeManager.INSTANCE.mode(modes.get("demo").get());
//from now on every object that uses Mode will get Demo implementations, great!
}

Having experimented with dagger for a while I came up with solution that seems to be working well in my use case.
Define class that will hold state information about mode
public class Conf {
public Mode mode;
public Conf(Mode mode) {
this.mode = mode;
}
public enum Mode {
NORMAL, DEMO
}
}
Provide singleton instance of Conf in Module
#Module
public class ConfModule {
#Provides
#Singleton
Conf provideConf() {
return new Conf(Conf.Mode.NORMAL);
}
}
Add module to AppComponent
#Singleton
#Component(modules = {AppModule.class, ConfModule.class})
public interface AppComponent {
//...
}
Define modules that provide different objects based on Mode
#Module
public class Object1Module {
#Provides
Object1 provideObject1(Conf conf) {
if (conf.mode == Conf.Mode.NORMAL)
return new NormalObject1();
else
return new DemoObject1();
}
}
To switch mode at runtime simply inject Conf object and modify it:
public class MyActivity extends Activity {
#Inject Conf conf;
//...
public void backgroundClicked5Times(){
conf.mode = Conf.Mode.DEMO;
//if you have dagger objects in this class that depend on Mode
//execute inject() once more to refresh them
}
}

Related

.NET Core Dependency Injection for multilevel, multiple implementation dependencies

I have come across several posts where a single interface is implemented by multiple classes and the dependency is registered and resolved. One such post is this one.
But how to resolve multiple, multi-level dependencies?
For example:
public enum ShortEnum { Short, Long }
public interface ISomeValidator
{
bool ValidateInputString(string str);
}
public class ConValidator : ISomeValidator
{
public bool ValidateInputString(string str) => true;
}
public class DonValidator : ISomeValidator
{
public bool ValidateInputString(string str) => false;
}
public class ConProvider : ISomeProvider
{
ISomeValidator conValidator; // Expects instance of ConValidator
public ConProvider(ISomeValidator someValidator)
{
conValidator = someValidator;
}
}
public class DonProvider : ISomeProvider
{
ISomeValidator donValidator; // Expects instance of DonValidator
public DonProvider(ISomeValidator someValidator)
{
donValidator = someValidator;
}
}
ShortEnum can be used as key. That means depending upon its value, either ConProvider or DonProvider is returned. Now, the providers have a dependency on ISomeValidator, which, again depending upon the key value of ShortEnum can be resolved as the instance of ConValidator or DonValidator.
In other words, I want to build the following two object graphs:
var provider1 = new ConProvider(new ConValidator());
var provider2 = new DonProvider(new DonValidator());
What is the best way to utilize .NET Core 3.1 in-built dependency injection mechanism?
There are three ways to achieve what you want.
The first option is to fall back to manually wiring the object graphs by registering a delegate that composes the required object graphs completely, for instance:
services.AddTransient<ISomeProvider>(
c => new ConProvider(new ConValidator());
services.AddTransient<ISomeProvider>(
c => new DonProvider(new DonValidator());
This, however, will become quite cumbersome once those classes get other dependencies, because you would very quickly start to circumvent the DI Container completely.
So instead, as a second option, you can configure the container in such way that you only have to new the two providers:
// Note how these validators are -not- registered by their interface!
services.AddTransient<ConValidator>(); // Might have dependencies
services.AddTransient<DonValidator>(); // of its own
services.AddTransient<ISomeProvider>(c =>
new ConProvider(
someValidator: c.GetRequiredService<ConValidator>(),
otherDependency1: c:GetRequiredService<IDependency1>());
services.AddTransient<ISomeProvider>(c =>
new DonProvider(
someValidator: c.GetRequiredService<DonValidator>(),
otherDependency2: c:GetRequiredService<IDependency2>());
This is a more-flexible solution compared to the first. But still, changes to the constructors of ConProvider and DonProvider force you to update their registrations.
To combat this, as a third option, you can use the ActivatorUtilities class. It will help you in achieving Auto-Wiring, where the container figures out which dependencies are required. That might look like this:
services.AddTransient<ConValidator>();
services.AddTransient<DonValidator>();
services.AddTransient<ISomeProvider>(c =>
ActivatorUtilities.CreateInstance<ConProvider>(
c,
c.GetRequiredService<ConValidator>());
services.AddTransient<ISomeProvider>(c =>
ActivatorUtilities.CreateInstance<DonProvider>(
c,
c.GetRequiredService<DonValidator>());
ActivatorUtilities.CreateInstance will create the requested class for you; in this case either ConProvider or DonProvider. It does so by looking at the constructor of the type and resolving all constructor parameters from the supplied c service provider. It resolves all dependencies from the service provider -except- the dependencies you supplied manually to the CreateInstance method. In the example above it will match the ISomeValidator dependency to the supplied DonValidator or ConValidator and inject them instead.
If I understood it correctly, you want ConValidator instance for ConProvider and DonValidator instance for DonProvider and Providers should be resolved on ShortEnum value.
we can modify dependencies like below
public interface ISomeProvider
{
void Method1();
}
public interface ISomeValidator
{
bool ValidateInputString(string str);
}
public class ConValidator : ISomeValidator
{
public bool ValidateInputString(string str) => true;
}
public class DonValidator : ISomeValidator
{
public bool ValidateInputString(string str) => false;
}
public class ConProvider : ISomeProvider
{
ISomeValidator conValidator; // Expects instance of ConValidator
public ConProvider(ValidatorResolver validatorResolver) =>
conValidator = validatorResolver(ShortEnum.Short);
public void Method1() => Console.WriteLine("Method1 COnProvider");
}
public class DonProvider : ISomeProvider
{
ISomeValidator donValidator; // Expects instance of DonValidator
public DonProvider(ValidatorResolver validatorResolver) =>
donValidator = validatorResolver(ShortEnum.Long);
public void Method1() => Console.WriteLine("Method1 DonProvider");
}
public enum ShortEnum { Short, Long }
declare delgates
public delegate ISomeProvider ProviderResolver(ShortEnum shortEnum);
public delegate ISomeValidator ValidatorResolver(ShortEnum shortEnum);
Consumer Service
public class SomeOtherService
{
private readonly ISomeProvider _provider;
public SomeOtherService(ProviderResolver providerResolver)
{
_provider = providerResolver(ShortEnum.Short);
//OR
_provider = providerResolver(ShortEnum.Long);
_provider.Method1();
}
}
In ConfigureServices method of StartUp class
services.AddTransient<ConValidator>();
services.AddTransient<DonValidator>();
services.AddTransient<ConProvider>();
services.AddTransient<DonProvider>();
services.AddTransient<ProviderResolver>(serviceProvider => (shortEnum) =>
{
switch (shortEnum)
{
case ShortEnum.Short:
return serviceProvider.GetService<ConProvider>();
case ShortEnum.Long:
return serviceProvider.GetService<DonProvider>();
default:
throw new KeyNotFoundException();
}
});
services.AddTransient<ValidatorResolver>(serviceProvider => (shortEnum) =>
{
switch(shortEnum)
{
case ShortEnum.Short:
return serviceProvider.GetService<ConValidator>();
case ShortEnum.Long:
return serviceProvider.GetService<DonValidator>();
default:
throw new KeyNotFoundException();
}
});
services.AddTransient<SomeOtherService>();

How to configure ninject to inject different dependency types into the same class?

I've run into what I believe must be a common dependency injection-related problem. I'm having trouble finding relevant examples, and I do not like the best solution I've been able to come up with.
public class WasherDryerFolderSystem : ILaundrySystem
{
private IWasher _washer;
private IDryer _dryer;
private IFolder _folder;
public WasherDryerFolderSystem(IWasher washer, IDryer dryer, IFolder folder)
{...}
public void DoLaundry()
{
_washer.Wash();
_dryer.Dry();
_folder.Fold();
}
}
public class HandWasher : IWasher {...}
public class MachineWasher : IWasher {...}
public class HandDryer : IDryer {...}
public class MachineDryer : IDryer {...}
public class HandFolder : IFolder {...}
public class MachineFolder : IFolder {...}
Now in the main app I have something like
var laundrySystem = _kernel.Get<ILaundrySystem>(someUserInput);
What is a good way to configure the bindings required for something like this? Here's what I've been able to come up with thus far (that I don't like):
Bind<ILaundrySystem>().To<WasherDryerFolderSystem>()
.Named(MACHINEWASH_HANDDRY_HANDFOLD)
.WithConstructorArgument("washer", new MachineWasher())
.WithConstructorArgument("dryer", new HandDryer())
.WithConstructorArgument("folder", new HandFolder());
At first I didn't think this looked too bad, but when Washers and Dryers and Folders all have their own dependencies, this quickly gets ugly.
This feels to me like it should be a common problem, but I'm not finding anything that's much help. Do I have something designed incorrectly?
You could use a factory pattern:
public interface ILaundrySystemFactory
{
ILaundrySystem Create(string someUserInput);
}
public class LaundrySystemFactory : ILaundrySystemFactory
{
private readonly IKernel _kernel;
public LaundrySystemFactory(IKernel kernel){
_kernel = kernel;
}
public ILaundrySystem Create(string someUserInput)
{
if(someUserInput){
var washer = _kernel.Get<MachineWasher>();
var dryer = _kernel.Get<HandDryer>();
var folder = _kernel.Get<HandFolder>();
} else {
var washer = _kernel.Get<DifferentWasher>();
var dryer = _kernel.Get<DifferentDryer>();
var folder = _kernel.Get<DifferentFolder>();
}
return new WasherDryerFolderSystem(washer, dryer, folder);
}
}
and then simply
private readonly ILaundrySystemFactory _laundrySystemFactory;
ctor(ILaundrySystemFactory laundrySystemFactory){
_laundrySystemFactory = laundrySystemFactory;
}
public UserInputMethod(string someUserInput)
{
var loundrySystem = laundrySystemFactory.Create(someUserInput);
var loundry = loundrySystem.DoLaundry();
}
bindings:
Bind<ILaundrySystemFactory>().To<LaundrySystemFactory>();
(some DI containers might also need something like:)
Bind<MachineWasher>().To<MachineWasher>();
Make a concrete classes with concrete parameters you need, put them as dependencies of strategy which will use them based on user input. Next instantiate them all with SINGLE call for a resolution root class. OFC Strategy can be the resolution root itself but it also can be a dependency of different resoultion root. Example:
//DoLaundry based on user input
public class WasherDryerFolderSystemStrategy
{
ctor(MachineWashingHandDringHandFoldingSystem first,
MachineWashingHandDringHandFoldingSystem second,
HandWashingHandDringHandFoldingWithBreakfastSystem third) { ... }
public void DoLaundry(int userInput)
{
if(userInput == 1)
first.DoLaundry();
if(userInput == 2)
second.DoLaundry();
if(userInput == 3)
third.DoLaundry();
}
}
// MACHINEWASH_HANDDRY_HANDFOLD
public class MachineWashingHandDringHandFoldingSystem : WasherDryerFolderSystem
{
public MachineWashingHandDringHandFoldingSystem
(MachineWasher machineWasher, HandDryer handDryer, HandFolder handFolder) :
base(machineWasher, handDryer, handFolder)
{
}
}
// HANDWASH_HANDDRY_HANDNOFOLD
public class HandWashingHandDringHandFoldingSystem : WasherDryerFolderSystem
{
public MachineWashingHandDringHandFoldingSystem
(HandWasher machineWasher, HandDryer handDryer, HandFolder handFolder) :
base(machineWasher, handDryer, handFolder)
{
}
}
// HANDWASH_HANDDRY_HANDNOFOLD_WITHBREAKFAST
public class HandWashingHandDringHandFoldingWithBreakfastSystem : WasherDryerFolderSystem
{
private readonly BreakfastMaker breakfastMaker
public MachineWashingHandDringHandFoldingSystem
(HandWasher machineWasher, HandDryer handDryer, HandFolder handFolder, BreakfastMaker brekfastMaker) :
base(machineWasher, handDryer, handFolder)
{
this.breakfastMaker = breakfastMaker
}
public overide void DoLaundry()
{
base.DoLaundry();
brekfastMaker.AndMakeChipBreakAsWell();
}
}
Please note that the implementation above does not require any Ninject configuration. Ninject will autobind everything ToSelf() with the first use (as long as it is not an interface).
In general as long as you do not need some sort of composite/bulk operations with with multiple implementations, than you should avoid interface bindings (and interfaces at all). Composite like operation example:
// original WasherDryerFolderSystem refactored
public class WasherDryerFolderSystem
{
private IEnumerable<IWasher> washers;
private IEnumerable<IDryer> dryers;
private IEnumerable<IFolder> folders;
public WasherDryerFolderSystem(
IWasher[] washers, IDryer[] dryers, IFolder[] folders)
{
this.washers = washers;
this.dryers = dryers;
this.folders = folders;
}
// all inclusive
public virtual void DoLaundry()
{
foreach (var washer in washers)
washer.Wash();
foreach (var dryer in dryers)
dryer.Dry();
foreach (var folder in folders)
folder.Fold();
}
}
I hope that helps.

MvvmLight unable to create a controller for key

I am designing a cross platform application architecture using Xamarin iOS and Xamarin Android I decided to go with MvvmLight, it looks descent and is not hiding everything from the MVVM pattern, good and flexible.
While everything started to make sense trying to set it up and learn how to use it, I find myself difficult to understand why I get the following error.
Unable to create a controller for key ChartsPage
The setup.
In a PCL I have my ViewModels. I have a ViewModelLocator setup. I use the mvvmlightlibs Nuget Package.
public class ViewModelLocator
{
public static readonly string SchedulerPageKey = #"SchedulerPage";
public static readonly string ChartsPageKey = #"ChartsPage";
[SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public SchedulerViewModel Scheduler
{
get
{
return ServiceLocator.Current.GetInstance<SchedulerViewModel>();
}
}
public BizchartsViewModel Bizcharts
{
get
{
return ServiceLocator.Current.GetInstance<BizchartsViewModel>();
}
}
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
// Haven't declared something yet
}
else
{
// Haven't declared something yet
}
SimpleIoc.Default.Register<SchedulerViewModel>();
SimpleIoc.Default.Register<BizchartsViewModel>();
}
}
The I have a unified iOS application using universal storyboard with size classes which has an initial UINavigationViewController SchedulerViewController and in the ViewDidLoad method I test the navigation to BizchartsViewController with 3 seconds delay. After 3 seconds I get the exceptions.
In the AppDelegate.
private static ViewModelLocator _locator;
public static ViewModelLocator Locator
{
get
{
if (_locator == null)
{
SimpleIoc.Default.Register<IDialogService, DialogService>();
_locator = new ViewModelLocator();
}
return _locator;
}
}
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
var nav = new NavigationService();
nav.Initialize((UINavigationController)Window.RootViewController);
nav.Configure(ViewModelLocator.ChartsPageKey, typeof(BizchartsViewController));
SimpleIoc.Default.Register<INavigationService>(() => nav);
return true;
}
The SchedulerViewController.
partial class SchedulerViewController : UIViewController
{
public SchedulerViewModel Vm {
get;
private set;
}
public SchedulerViewController (IntPtr handle) : base (handle)
{
Vm = AppDelegate.Locator.Scheduler;
}
public async override void ViewDidLoad ()
{
base.ViewDidLoad ();
await Task.Delay (3000);
Vm.NavigateToCharts ();
}
}
The SchedulerViewModel.
public class SchedulerViewModel : ViewModelBase
{
public void NavigateToCharts()
{
var nav = ServiceLocator.Current.GetInstance<INavigationService>();
nav.NavigateTo(ViewModelLocator.ChartsPageKey);
}
}
I definitely miss a detail somewhere!!!
If you follow carefully the blog post here, it says that with Storyboard you should use the string overload and not the typeof() in nav.Configure(Key, ViewController) and always set the storyboardId and restorationId in the Storyboard ViewController.
Note that because we are using a Storyboard, you must make sure to use
the Configure(string, string) overload, and NOT the Configure(string,
Type) one.

Dependency Injection of Primitive Types (Decided at Runtime) With HK2

So basically, I have a situation where I want to inject primitive types into a class (i.e. a String and an Integer). You can think of a URL and port number for an application as example inputs. I have three components:
Now say I have a class, which does take in these params:
public class PrimitiveParamsDIExample {
private String a;
private Integer b;
public PrimitiveParamsDIExample(String a, Integer b) {
this.a = a;
this.b = b;
}
}
So my question here is simple. How do I inject a and b into class PrimitiveParamsDIExample?
In general, this is also asking how to inject parameters that are decided on runtime as well. If I have a and b above, read from STDIN or from an input file, they're obviously going to be different from run to run.
All the more, how do I do the above within the HK2 framework?
EDIT[02/23/15]: #jwells131313, I tried your idea, but I'm getting the following error (this one for the String param; similar one for int):
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=String,parent=PrimitiveParamsDIExample,qualifiers
I set up classes exactly as you did in your answer. I also overrode the toString() method to print both variables a and b in PrimitiveParamsDIExample. Then, I added the following in my Hk2Module class:
public class Hk2Module extends AbstractBinder {
private Properties properties;
public Hk2Module(Properties properties){
this.properties = properties;
}
#Override
protected void configure() {
bindFactory(StringAFactory.class).to(String.class).in(RequestScoped.class);
bindFactory(IntegerBFactory.class).to(Integer.class).in(RequestScoped.class);
bind(PrimitiveParamsDIExample.class).to(PrimitiveParamsDIExample.class).in(Singleton.class);
}
}
So now, I created a test class as follows:
#RunWith(JUnit4.class)
public class TestPrimitiveParamsDIExample extends Hk2Setup {
private PrimitiveParamsDIExample example;
#Before
public void setup() throws IOException {
super.setupHk2();
//example = new PrimitiveParamsDIExample();
example = serviceLocator.getService(PrimitiveParamsDIExample.class);
}
#Test
public void testPrimitiveParamsDI() {
System.out.println(example.toString());
}
}
where, Hk2Setup is as follows:
public class Hk2Setup extends TestCase{
// the name of the resource containing the default configuration properties
private static final String DEFAULT_PROPERTIES = "defaults.properties";
protected Properties config = null;
protected ServiceLocator serviceLocator;
public void setupHk2() throws IOException{
config = new Properties();
Reader defaults = Resources.asCharSource(Resources.getResource(DEFAULT_PROPERTIES), Charsets.UTF_8).openBufferedStream();
load(config, defaults);
ApplicationHandler handler = new ApplicationHandler(new MyMainApplication(config));
final ServiceLocator locator = handler.getServiceLocator();
serviceLocator = locator;
}
private static void load(Properties p, Reader r) throws IOException {
try {
p.load(r);
} finally {
Closeables.close(r, false);
}
}
}
So somewhere, the wiring is messed up for me to get an UnsatisfiedDependencyException. What have I not correctly wired up?
Thanks!
There are two ways to do this, but one isn't documented yet (though it is available... I guess I need to work on documentation again...)
I'll go through the first way here.
Basically, you can use the HK2 Factory.
Generally when you start producing Strings and ints and long and scalars like this you qualify them, so lets start with two qualifiers:
#Retention(RUNTIME)
#Target( { TYPE, METHOD, FIELD, PARAMETER })
#javax.inject.Qualifier
public #interface A {}
and
#Retention(RUNTIME)
#Target( { TYPE, METHOD, FIELD, PARAMETER })
#javax.inject.Qualifier
public #interface B {}
then write your factories:
#Singleton // or whatever scope you want
public class StringAFactory implements Factory<String> {
#PerLookup // or whatever scope, maybe this checks the timestamp?
#A // Your qualifier
public String provide() {
// Write your code to get your value...
return whatever;
}
public void dispose(String instance) {
// Probably do nothing...
}
}
and for the Integer:
#Singleton // or whatever scope you want
public class IntegerBFactory implements Factory<Integer> {
#PerLookup // or whatever scope, maybe this checks the timestamp?
#B // Your qualifier
public Integer provide() {
// Write your code to get your value...
return whatever;
}
public void dispose(String instance) {
// Probably do nothing...
}
}
Now lets re-do your original class to accept these values:
public class PrimitiveParamsDIExample {
private String a;
private int b;
#Inject
public PrimitiveParamsDIExample(#A String a, #B int b) {
this.a = a;
this.b = b;
}
}
Note I changed Integer to int, well... just because I can. You can also just use field injection or method injection in the same way. Here is field injection, method injection is an exercise for the reader:
public class PrimitiveParamsDIExample {
#Inject #A
private String a;
#Inject #B
private int b;
public PrimitiveParamsDIExample() {
}
}
There are several ways to bind factories.
In a binder: bindFactory
Using automatic class analysis: addClasses
An EDSL outside a binder: buildFactory

More than one singleton instance in Guice injector

We got a Jetty/Jersey application. We are converting it to use Guice for DI. The problem: We need more than one instance of a Singleton classes. The catch: The number of instances is determined dynamically from a configuration file. Therefore we cant use annotations for different instances.
final InjectedClass instance = injector.getInstance(InjectedClass.class);
This is the standard syntax of the injector. I need something like
final String key = getKey();
final InjectedClass instance = injector.getInstance(InjectedClass.class, key);
There is a way to get an instance from a Guice Key.class
final InjectedClass instance = injector.getInstance(Key.get(InjectedClass.class, <Annotation>);
but the problem is that I need some dynamic annotation, not predefined one.
You could try to use Provider, or #Provides method that would have map of all instances already created. When the number of instances is reached number defained in config file, you wont create any new instances, instead you return old instance from map.
For example something like this could help you.
public class MyObjectProvider implements Provider<MyObject> {
private final Injector inj;
private int counter;
private final int maxNum = 5;
private List<MyObject> myObjPool = new ArrayList<MyObject>();
#Inject
public MyObjectProvider(Injector inj) {
this.connection = connection;
}
public MyObject get() {
counter = counter+1%maxNum;
if(myObjPool.size()=<maxNum) {
MyObject myobj = inj.getInstance(MyObject.class);
myObjPool.add(myobj);
return myobj;
} else {
return myObjPool.get(counter);
}
}
}
P.S.
I wrote this from my head so maybe it does not compile, this is just an idea.
You can solve this by creating a factory. In my example I have used the guice extension called multibindings
interface InjectedClassFactory {
public InjectedClass get(String key);
}
class InjectedClass {}
class InjectedClassFactoryImpl implements InjectedClassFactory{
private final Map<String, InjectedClass> instances;
#Inject
InjectedClassFactoryImpl(Map<String, InjectedClass> instances) {
this.instances = instances;
}
#Override
public InjectedClass get(String key) {
return instances.get(key);
}
}
class MyModule extends AbstractModule {
#Override
protected void configure() {
MapBinder<String, InjectedClass> mapBinder =
MapBinder.newMapBinder(binder(), String.class, InjectedClass.class);
//read you config file and retrieve the keys
mapBinder.addBinding("key1").to(InjectedClass.class).in(Singleton.class);
mapBinder.addBinding("key2").to(InjectedClass.class).in(Singleton.class);
}
}

Resources