12

Having to deal with Guice, I wonder how I should handle dependencies in terms of modules.

In Guice every module is provided by an instance. So if I have a module requiring a certain service it creates the module adding a binding to that service and installs it (binder.install(module)).

Now I have two independent modules that make completely sense to be used independently and both install the same database module.

Using both modules independently no problem arise but what happens if both modules are used in the same application? The database module will be loaded by both modules independently and that can not be correct.

Is there a way to ask the binder if a certain type has already a binding? I can not use getProvider to check on that since all that is returned is a LookupProvider regardless if something is already bind or not.

So how one has to deal with this scenario?

Update:

It seams Guice is unable to provide the following feature:

  1. Check if a given module was already loaded.
  2. Check if a given class was already bound.
  3. Use Providers within the configuration to be able to do distributed configuration (modules being able to configure objects being contributed).
Martin Kersten
  • 5,127
  • 8
  • 46
  • 77

3 Answers3

16

Guice has two features to deal with this situation. The first is module de-duplication. This means that if two modules are installed that are equivalent (by equals() and hashCode()), only one's configure() method will run. However, this solution is somewhat brittle because it won't survive SPI transformations, Modules.override(), etc.

The second, and IMO better solution, is binding de-duplication. This means that Guice will accept bindings that are exact duplicates. So if your module does bind(Interface.class).to(Implementation.class), it doesn't even matter if its configure() method runs twice, because Guice will handle the duplicate binding just fine.

Tavian Barnes
  • 12,477
  • 4
  • 45
  • 118
  • So I need my own implementation? Like grouping modules into Dependencies and resolve dependencies in a certain way. From the code I understood that the modules are executed in the order left to right or first to last. – Martin Kersten Dec 23 '13 at 09:08
  • The order Modules are installed in is intended to be unimportant. That's why there's no way to check if a binding has been created "yet". – Tavian Barnes Dec 24 '13 at 03:41
  • Yes but the code simply walks down the given module list this way. In the end I need to add way more to the Guice code in case to overcome this important shortcomming. – Martin Kersten Dec 24 '13 at 08:26
  • I added a second answer that describes what I currently do but since yours is correct in the sense of the question, I will accept yours. Thanks for your help. – Martin Kersten Dec 24 '13 at 08:42
  • 1
    Basically I take issue with this statement: "The database module will be loaded by both modules independently *and that can not be correct*." I think that installing the Module twice is fine, if you design your Modules correctly. – Tavian Barnes Dec 24 '13 at 16:33
0

Since Guice do not support certain needed functionality it must be emulated. The multibinder code provides one idea. Another idea I currently use is using reflection to find the top most binder during the injector build process. Knowing this binder one can easily add required meta information and track certain objects.

Those meta information will be dropped once the build process finished.

Usually one only builds one injector at a time but to be sure we should protect against this.

So take a look at the single most Binder implementation (RecordingBinder). It provides a field parent that we can walk to the root binder element. Usually Guice will use a single most binder but in case of private modules.

Another idea being not so secure but come without reflection is using a thread local if you can ensure that only one Guice injector is build at a time.

Being able to identify the build process and track which builders are used at a time one is able to add any kind of additional logic into guice like preventing to install a dependency twice.

Martin Kersten
  • 5,127
  • 8
  • 46
  • 77
0

Binding deduplication looks to have been added in Guice 4.0

https://github.com/google/guice/commit/c34e0185fcf508a890c6cd13bdafeb505c3e9e8a

user1770475
  • 43
  • 1
  • 5
  • 1
    Binding deduplication has existed since at least Guice 3. The commit you linked just changes how it is implemented for multibindings. – Tavian Barnes Nov 13 '15 at 15:25