TL DR: isolate the Blue and Red modules with their own injectors and create providers in your App's module that call the getInstance() method on the injectors to get the applications you need.
Now, as I came to the solution:
Private modules can get most of the way from you, see my experiments .
But...
Let's say I'm developing an application that uses a service to do something completely amazing.
public class MyAppModule extends PrivateModule { bind(AwesomeService.class).to(AwesomeServiceImpl.class); expose(AwesomeService.class); }
Now for a specific implementation of my AwesomeService you need a few things to be as awesome as this:
class AwesomeServiceImpl implements AwesomeService { @Inject AwesomeServiceImpl(BlueService blue, RedService red, ExecutorService executor) { ... } }
It so happened that some kind of stable Internet denizen created an autonomous bank with Guice modules that provide Red and Blue services. Therefore, I will add jar to my classpath and MyAppModule so that my AwesomeService can use third-party Red and Blue Services:
public class MyAppModule extends PrivateModule { install(new RedModule()); install(new BlueModule()); bind(AwesomeService.class).to(AwesomeServiceImpl.class); expose(AwesomeService.class); }
I also need an ExecutorService for my AwesomeService , so I will continue and bind to an explicit instance:
public class MyAppModule extends PrivateModule { install(new RedModule()); install(new BlueModule()); bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); bind(AwesomeService.class).to(AwesomeServiceImpl.class); expose(AwesomeService.class); }
Oh, but hell, apparently my good friend on the Internet decided to expose not only the RedService and BlueService that I need AwesomeService , but also the ExecutorService that I don't want:
public final class BlueModule extends PrivateModule { bind(ExecutorService.class).toInstance(Executors.newCachedThreadPool()); bind(BlueService.class).to(BlueServiceImpl.class); expose(ExecutorService.class); expose(BlueService.class); } public final class RedModule extends PrivateModule { bind(ExecutorService.class).toInstance(Executors.newCachedThreadPool()); bind(RedService.class).to(RedServiceImpl.class); expose(ExecutorService.class); expose(RedService.class); }
No problem, I just close its modules in the private module and expose only those services that concern me:
public class MyAppModule extends PrivateModule { install(new PrivateModule() { install(new RedModule()); expose(RedService.class); }); install(new PrivateModule() { install(new BlueModule()); expose(BlueService.class); }); bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); bind(AwesomeService.class).to(AwesomeServiceImpl.class); expose(AwesomeService.class); }
Ahh, but to hell, my ExecutorService binding is inherited by my private wrapper modules and contradicts the internal relationships defined in RedModule and BlueModule . I assume that I could annotate or call my ExecutorService in my AwesomeService constructor, but what if I want the ExecutorService be singleton, common to my entire application, on 20, 30, or 40 different services. I will have to foul all my ExecutorService injections with this annotation.
Or, I suppose, I could do some tricks by stunning the bindings and hiding the ExecutorService , so it doesn't conflict with the ExecutorService that RedModule and BlueModule creates, but that just seems to be wrong:
public class MyAppModule extends PrivateModule { install(new PrivateModule() { install(new RedModule()); expose(RedService.class); }); install(new PrivateModule() { install(new BlueModule()); expose(BlueService.class); }); final Module myAppExecutorService = new PrivateModule() { bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); expose(ExecutorService.class); }; install(new PrivateModule() { install(myAppExecutorService); bind(AwesomeService.class).to(AwesomeServiceImpl.class); expose(AwesomeService.class); }); expose(AwesomeService.class); }
There must be a better way ... and there are ... Injectors!
public class MyAppModule extends PrivateModule { private static final Injector blueInjector = Guice.createInjector(new BlueModule()); private static final Injector redInjector = Guice.createInjector(new RedModule()); @Override protected void configure() { bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); bind(MyService.class).to(MyServiceImpl.class); bind(MyOtherService.class).to(MyOtherServiceImpl.class); expose(MyService.class); expose(MyOtherService.class); } @Provides RedService getRedService() { return redInjector.getInstance(RedService.class); } @Provides BlueService getBlueService() { return blueInjector.getInstance(BlueService.class); } }
Now, the ExecutorService , linked and exposed in both BlueModule and RedModule , will not pollute my AwesomeService's ExecutorService , but I can still use these juicy BlueService and RedService classes that I so desperately want.
Hope this saves someone else in the future!