issue 297 -- allow Multibinder's dependencies to be retrieved in Stage.TOOL.  also added a failing test for MapBinder & Modules.override (analog to existing failing test in MultibinderTest).

git-svn-id: https://google-guice.googlecode.com/svn/trunk@1154 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/extensions/multibindings/src/com/google/inject/multibindings/Multibinder.java b/extensions/multibindings/src/com/google/inject/multibindings/Multibinder.java
index e9654b1..1ad9b3d 100644
--- a/extensions/multibindings/src/com/google/inject/multibindings/Multibinder.java
+++ b/extensions/multibindings/src/com/google/inject/multibindings/Multibinder.java
@@ -35,6 +35,7 @@
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.HasDependencies;
 import com.google.inject.spi.Message;
+import com.google.inject.spi.Toolable;
 import com.google.inject.util.Types;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
@@ -259,7 +260,7 @@
      * element in this set. At this time the set's size is known, but its
      * contents are only evaluated when get() is invoked.
      */
-    @Inject void initialize(Injector injector) {
+    @Toolable @Inject void initialize(Injector injector) {
       providers = Lists.newArrayList();
       List<Dependency<?>> dependencies = Lists.newArrayList();
       for (Binding<?> entry : injector.findBindingsByType(elementType)) {
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java b/extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java
index a7eeedc..5ed5034 100644
--- a/extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java
+++ b/extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java
@@ -24,10 +24,12 @@
 import com.google.inject.CreationException;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
+import com.google.inject.InjectorBuilder;
 import com.google.inject.Key;
 import com.google.inject.Module;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
+import com.google.inject.Stage;
 import com.google.inject.TypeLiteral;
 import com.google.inject.internal.ImmutableSet;
 import com.google.inject.internal.Maps;
@@ -35,6 +37,7 @@
 import static com.google.inject.name.Names.named;
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.HasDependencies;
+import com.google.inject.util.Modules;
 import com.google.inject.util.Providers;
 import java.lang.annotation.Retention;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -420,6 +423,28 @@
         withDependencies.getDependencies());
   }
 
+  /** We just want to make sure that mapbinder's binding depends on the underlying multibinder. */
+  public void testMultibinderDependenciesInToolStage() {
+    Injector injector = new InjectorBuilder()
+      .stage(Stage.TOOL)
+      .addModules(new AbstractModule() {
+        protected void configure() {
+          MapBinder<Integer, String> mapBinder
+              = MapBinder.newMapBinder(binder(), Integer.class, String.class);
+          mapBinder.addBinding(1).toInstance("A");
+          mapBinder.addBinding(2).to(Key.get(String.class, Names.named("b")));
+  
+          bindConstant().annotatedWith(Names.named("b")).to("B");
+        }})
+      .build();
+
+    Binding<Map<Integer, String>> binding = injector.getBinding(new Key<Map<Integer, String>>() {});
+    HasDependencies withDependencies = (HasDependencies) binding;
+    Key<?> setKey = new Key<Set<Map.Entry<Integer, Provider<String>>>>() {};
+    assertEquals(ImmutableSet.<Dependency<?>>of(Dependency.get(setKey)),
+        withDependencies.getDependencies());
+  }
+  
 
   /**
    * Our implementation maintains order, but doesn't guarantee it in the API spec.
@@ -455,6 +480,39 @@
     assertEquals(Maps.immutableEntry("michaelangelo", "orange"), iterator.next());
     assertEquals(Maps.immutableEntry("raphael", "red"), iterator.next());
   }
+  
+  /**
+   * With overrides, we should get the union of all map bindings.
+   */
+  public void testModuleOverrideAndMapBindings() {
+    Module ab = new AbstractModule() {
+      protected void configure() {
+        MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
+        multibinder.addBinding("a").toInstance("A");
+        multibinder.addBinding("b").toInstance("B");
+      }
+    };
+    Module cd = new AbstractModule() {
+      protected void configure() {
+        MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
+        multibinder.addBinding("c").toInstance("C");
+        multibinder.addBinding("d").toInstance("D");
+      }
+    };
+    Module ef = new AbstractModule() {
+      protected void configure() {
+        MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
+        multibinder.addBinding("e").toInstance("E");
+        multibinder.addBinding("f").toInstance("F");
+      }
+    };
+
+    Module abcd = Modules.override(ab).with(cd);
+    Injector injector = Guice.createInjector(abcd, ef);
+    assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E", "f", "F"),
+        injector.getInstance(Key.get(mapOfString)));
+
+  }
 
   @Retention(RUNTIME) @BindingAnnotation
   @interface Abc {}
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/MultibinderTest.java b/extensions/multibindings/test/com/google/inject/multibindings/MultibinderTest.java
index 4f65852..2f5e9d7 100644
--- a/extensions/multibindings/test/com/google/inject/multibindings/MultibinderTest.java
+++ b/extensions/multibindings/test/com/google/inject/multibindings/MultibinderTest.java
@@ -23,10 +23,12 @@
 import com.google.inject.CreationException;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
+import com.google.inject.InjectorBuilder;
 import com.google.inject.Key;
 import com.google.inject.Module;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
+import com.google.inject.Stage;
 import com.google.inject.TypeLiteral;
 import com.google.inject.internal.ImmutableList;
 import com.google.inject.internal.ImmutableSet;
@@ -35,6 +37,8 @@
 import static com.google.inject.name.Names.named;
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.HasDependencies;
+import com.google.inject.spi.InstanceBinding;
+import com.google.inject.spi.LinkedKeyBinding;
 import com.google.inject.util.Modules;
 import com.google.inject.util.Providers;
 import java.lang.annotation.Retention;
@@ -328,6 +332,60 @@
     }
     assertEquals(ImmutableSet.of("A", "B"), elements);
   }
+  
+  /**
+   * We just want to make sure that multibinder's binding depends on each of its values. We don't
+   * really care about the underlying structure of those bindings, which are implementation details.
+   */
+  public void testMultibinderDependenciesInToolStage() {
+    Injector injector = new InjectorBuilder()
+      .stage(Stage.TOOL)
+      .addModules(new AbstractModule() {
+        protected void configure() {
+          Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
+          multibinder.addBinding().toInstance("A");
+          multibinder.addBinding().to(Key.get(String.class, Names.named("b")));
+  
+          bindConstant().annotatedWith(Names.named("b")).to("B");
+        }})
+      .build();
+
+    Binding<Set<String>> binding = injector.getBinding(new Key<Set<String>>() {});
+    HasDependencies withDependencies = (HasDependencies) binding;
+    InstanceBinding<?> instanceBinding = null;
+    LinkedKeyBinding<?> linkedBinding = null;
+    // The non-tool stage test can test this by calling injector.getInstance to ensure
+    // the right values are returned -- in tool stage we can't do that.  It's also a
+    // little difficult to validate the dependencies & bindings, because they're
+    // bindings created internally within Multibinder.
+    // To workaround this, we just validate that the dependencies lookup to a single 
+    // InstanceBinding whose value is "A" and another LinkedBinding whose target is 
+    // the Key of @Named("b") String=B
+    for (Dependency<?> dependency : withDependencies.getDependencies()) {
+      Binding<?> b = injector.getBinding(dependency.getKey());
+      if(b instanceof InstanceBinding) {
+        if(instanceBinding != null) {
+          fail("Already have an instance binding of: " + instanceBinding + ", and now want to add: " + b);
+        } else {
+          instanceBinding = (InstanceBinding)b;
+        }
+      } else if(b instanceof LinkedKeyBinding) {
+        if(linkedBinding != null) {
+          fail("Already have a linked binding of: " + linkedBinding + ", and now want to add: " + b);
+        } else {
+          linkedBinding = (LinkedKeyBinding)b;
+        }
+      } else {
+        fail("Unexpected dependency of: " + dependency);
+      }
+    }
+    
+    assertNotNull(instanceBinding);
+    assertNotNull(linkedBinding);
+    
+    assertEquals("A", instanceBinding.getInstance());
+    assertEquals(Key.get(String.class, Names.named("b")), linkedBinding.getLinkedKey());
+  }
 
   /**
    * Our implementation maintains order, but doesn't guarantee it in the API spec.