8

I have been looking over the net for an explanation about the injector heirarchy and how/when to use createChildInjector(), but I cannot find a clear and concise explanation.

Here is my use case:

  • I have a base application module which I use to inject certain context items. This module should be included in every injector instance.
  • I have a search module which searches a database
  • I have a search module which searches ElasticSearch. Some of the bindings in this class should override the bindings that are provided in the database search module.

For example, say the database search module contains:

bind(PlaceSearch.class).to(HibernatePlaceSearch.class);
bind(PersonSearch.class).to(HibernatePersonSearch.class);

And the ElasticSearch module contains:

bind(PersonSearch.class).to(PersonElasticSearch.class); 

Is there a way to create an injector that includes the PlaceSearch binding from the database search module and the PersonSearch binding from the ElasticSearch module without creating a separate module that contains

bind(PlaceSearch.class).to(HibernatePlaceSearch.class);
bind(PersonSearch.class).to(PersonElasticSearch.class);

? Is this a case for Modules.override()? A case for createChildInjector? Thanks ahead of time!

Alex
  • 21,273
  • 10
  • 61
  • 73
jcampos8782
  • 3,956
  • 4
  • 22
  • 23

2 Answers2

6

The Modules.override() is not working in Stage.PRODUCTION. You should use PrivateModule where the binding is valid/visible only inside private module, so you can bind different implementation classes to the same interface. Then you can install the Private module to the parent Module, but you have to explicitly expose() all binding you want to make visible for other modules.

Guice - Private Modules

Lets say:

DatabaseSearchModule.java (extends PrivateModule)

bind(PlaceSearch.class).annotatedWith(Names.named("dbSearch")).to(HibernatePlaceSearch.class);
bind(PersonSearch.class).to(HibernatePersonSearch.class);
expose(PlaceSearch.class).annotatedWith(Names.named("dbSearch"));

EleasticSearchModule.java (extends PrivateModule)

bind(PersonSearch.class).annotatedWith(Names.named("elastic")).to(PersonElasticSearch.class);
expose(PersonSearch.class).annotatedWith(Names.named("elastic"));

Well then you can install it in some Parent abstract or servlet module

MainModule.java

install(new DatabaseSearchModule());
install(new EleasticSearchModule());

bind(OtherClass.class);

OtherClass.java

@Inject @Named("elastic")
private PlaceSearch elasticSearch;
@Inject @Named("dbSearch")
private PlaceSearch dbSearch;

You can use Named annotation or you can create very elegant own binding Annotation.

naimdjon
  • 3,162
  • 1
  • 20
  • 41
Milan Baran
  • 4,133
  • 2
  • 32
  • 49
2

This is a perfect case for Modules.override().

Most applications shouldn't use child injectors. They add a lot of configuration complexity and have some surprising behavior for corner cases.

Jesse Wilson
  • 39,078
  • 8
  • 121
  • 128
  • Thanks for the answer. Can you give me an explanation of what exactly a child injector is? Or point me to a good reference? I am not sure I fully understand the child injector concept. – jcampos8782 Aug 31 '13 at 23:27
  • 1
    The child injector concept is explained quite well in this answer: http://stackoverflow.com/a/12774246/205866 – racc Jan 07 '15 at 20:30