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.