I had a similar idea as Jesse when solving the problem of having
multiple EntityManagers bound to one Injector by using annotated
bindings. The requirements are
1. having multiple object graphs with slightly different bindings
(e.g. the EntityManagerFactory is different for each PerstenceUnit),
but
2. reuse the classes that have @Inject dependencies
3. bound them all to one Injector with different binding annotations.
This requirements were discussed on this mailing list several times
often using the term "robot-leg-problem". My idea was to create a
fully usable (Sub-)Injector for each PersistenceUnit by binding all
necessary types without any annotations. This ensures I can reuse my
types, providers, etc. without using any fancy logic to be able to
Inject annotated bindings (this solves point 2). I have introduced the
term SubInjector, because after creating all SubInjectors I create a
root Injector that is visible to the application by iterating over all
SubInjector's bindings and bind them to the root Injector using one
binding annotation for each SubInjector (solves point 3). This looks
like:
class SubInjector {
interface AnnotatedSubModule {
Module annotatedWith(Class<? extends Annotation>);
Module annotatedWith(Annotation);
}
static AnnotatedSubModule bind(Module...) {
// create injector from modules and
// return a module with annotated bindings
// to this injector.getBindings().getProvider()
}
}
with the concrete usage for binding different PerstenceUnits:
Injector applicationInjector = Guice.createInjector(
SubInjector.bind(JpaModule.createModuleForUnitName("crm"))
.annotatedWith(CustomerRelationManagement.class),
SubInjector.bind(JpaModule.createModuleForUnitName("business"))
.annotatedWith(BusinessTasks.class)
)
class JpaModule {
static Module createModuleForUnitName(final String unitName) {
return new AbstractModule() {
bind(EntityManagerFactory.class)
.toInstance(javax.persistence.Persistence
.createEntityManagerFactory(unitName));
bind(EntityManager.class).toProvider(new
Provider<EntityManager>() {
@Inject EntityManagerFactory factory;
public EntityManager get() {
return factory.createEntityManager();
}
}
});
}
}
class Application {
@Inject @CustomerRelationManagement EntityManager crmEntityManager;
@Inject @BusinessTasks EntityManager taskEntityManager;
}
Back to discussion: My current wish/problem is, I am not able to
reference bindings of the root Injector from the SubInjectors. I would
love to see the each Subinjector created as an child Injector of the
parent/root Injector, but the problem is that the parent Injector
actually has to be fully initialized before you can use it to create
child Injectors. Because I am creating modules for each child/sub
injector which are used to configure the parent/root injector
afterwards, I am not able to also use the parent injector as a place
of common bindings, that are available for each child injector (sounds
a bit like the chicken-or-egg question to me).
I know a can deal with this problem by simply using multiple child
injectors as it is stated by the current implementations of
"hierarchical injectors", but I do not like the idea of handling
multiple injectors in the application like Jesse said before.
Best regards,
Sven