PUBLIC OBJECT

Elite Guice 2: Binding de-duplication

In part one, I showed how to initialize a Guice extension using the @Inject tag on a method. In this post I'm going to demonstrate a Guice for deduplicating bindings.

What is binding duplication?

One of the features of the Multibindings Extension is that there's no central coordination. Each module contributes its own bindings, and they all get amalgamated into a single collection. Suppose you have these modules:

public class CandybarModule extends AbstractModule {
  protected void configure() {
    Multibinder<Snack> multibinder = Multibinder.newSetBinder(binder(), Snack.class);
    multibinder.addBinding().toInstance(new Twix());
    multibinder.addBinding().toProvider(SnickersProvider.class);
  }
}
public class ChipsModule extends AbstractModule {
  protected void configure() {
    Multibinder<Snack> multibinder = Multibinder.newSetBinder(binder(), Snack.class);
    multibinder.addBinding().to(Pringles.class);
    multibinder.addBinding().toInstance(new Doritos());
  }
} `</pre>
Out of this API, our `Multibinder` implementation needs to bind `Set&lt;Snack&gt;` exactly once. This is tricky! For example, suppose our `newSetBinder` method was implemented like this:
<pre class="prettyprint">`  public static &lt;T&gt; Multibinder&lt;T&gt; newSetBinder(Binder binder, Type type) {
    binder.bind(getSetKey(type)).toProvider(getSetProvider(type));
    return new Multibinder(type);
  }`</pre>
This won't work. We call `newSetProvider` from both the `CandybarModule` and the `ChipsModule`, and Guice complains because we're binding `Set&lt;Snack&gt;` twice. This is binding duplication.

### If Guice had an duplicate-binding API

Guice doesn't have this API, but what we kind of find ourselves wanting is a way to query the binder for its bindings thus-far:
<pre class="prettyprint">`  public static &lt;T&gt; Multibinder&lt;T&gt; newSetBinder(Binder binder, Type type) {
    if (!binder.getBindings().containsKey(getSetKey(type))) {
      binder.bind(getSetKey(type)).toProvider(getSetProvider(type));
    }
    return new Multibinder(type);
  }`</pre>
This would work, but in general it's a pretty terrible idea. It makes it easy to write fragile modules - modules that depend on the order they are installed in. And it also changes the module from being static configuration (good!) to a dynamic-runtime configuration (bad!). So we're glad this API doesn't exist.

But in this one case, we really wish we could prevent our binding from  being performed twice.

### Modules as value objects

The solution to this problem is a bit surprising, but I think it's quite elegant. Guice conveniently allows the same _module_ to be installed twice. This is necessary so that both your `PizzaServletsModule` and your `PizzaDatabaseModule` can install your `PizzaDomainModule`. 

Rather than binding the `Set&lt;Snack&gt;` directly on the binder, we create special `Module` class whose only job is to create that binding. And then we give that module a proper `equals()` and `hashCode()` methods, so that any two instances that bind the same type are equal.

Our final code looks like this:
<pre class="prettyprint">`  public static &lt;T&gt; Multibinder&lt;T&gt; newSetBinder(Binder binder, Type type) {
    binder.install(new MultibindingModule(getSetType(), getProviderType()));
    return new Multibinder(type);
  }

The Module trick allows us to decentralize the binding. And that means less configuration code, and that means less code. Hooray for Guice.