PUBLIC OBJECT

Guice Multibinder API proposal

Multibindings is an idea to allow multiple independent modules to contribute elements to a collection. There's lots of proposed APIs to add multibindings to Guice.

Unlike almost all of the existing proposals, this strategy can be used to add multibindings as an extension to Guice. Therefore we don't increase the complexity of the existing Binder API in the much more common non-multibinding case. The API:

public class Multibinder<T> {

  /**
   * Returns a new multibinder that collects instances of {@code type} in a list.
   */
  static <T> Multibinder<T> newListBinder(Binder binder, Class<T> type);  

  /**
   * Returns a new multibinder that collects instances of {@code type} in a set.
   */
  static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type);  

  /**
   * Build a new element in the bound collection.
   */
  AnnotatedBindingBuilder&lt;T&gt; addBinding();
}

... and here's what the client code would look like:

public static void testMultibinder() {
    AbstractModule stanCartmanKennyModule = new AbstractModule() {
      protected void configure() {
        Multibinder<String> stringBinder
            = Multibinder.newSetBinder(binder(), String.class);

        stringBinder.addBinding().toInstance("Stan");
        stringBinder.addBinding()
            .annotatedWith(Names.named("Fatass"))
            .toInstance("Cartman");
        stringBinder.addBinding().toProvider(new Provider<String>() {
          public String get() {
            return "Kenny";
          }
        });
      }
    };

    AbstractModule kyleModule = new AbstractModule() {
      protected void configure() {
        Multibinder.newSetBinder(binder(), String.class)
            .addBinding().toInstance("Kyle");
      }
    };

    Injector injector = Guice.createInjector(stanCartmanKennyModule, kyleModule);

    Set<String> boys = injector.getInstance(Key.get(new TypeLiteral<Set<String>>() {}));
    assertEquals(Sets.newHashSet("Stan", "Cartman", "Kenny", "Kyle"), boys);
    assertEquals("Cartman", Key.get(String.class, Names.named("Fatass"));
  }

Note that I've simplified the code above by omitting some details (annotating the collections, binding collections of parameterized types).

I think this API is both compact and convenient. What's your favourite multibinding API?