blob: 5933dde74cef9e2b69e7c0a97bd8384374220ebe [file] [log] [blame]
/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.inject.internal;
import static com.google.inject.Asserts.asModuleChain;
import static com.google.inject.Asserts.assertContains;
import static com.google.inject.internal.SpiUtils.VisitType.BOTH;
import static com.google.inject.internal.SpiUtils.VisitType.MODULE;
import static com.google.inject.internal.SpiUtils.assertMapVisitor;
import static com.google.inject.internal.SpiUtils.instance;
import static com.google.inject.internal.SpiUtils.providerInstance;
import static com.google.inject.name.Names.named;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.AbstractModule;
import com.google.inject.Asserts;
import com.google.inject.Binding;
import com.google.inject.BindingAnnotation;
import com.google.inject.ConfigurationException;
import com.google.inject.CreationException;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Provides;
import com.google.inject.ProvisionException;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.RealMapBinder.ProviderMapEntry;
import com.google.inject.multibindings.MapBinder;
import com.google.inject.multibindings.MapBinderBinding;
import com.google.inject.name.Names;
import com.google.inject.spi.DefaultElementVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.Elements;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InstanceBinding;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.util.Modules;
import com.google.inject.util.Providers;
import com.google.inject.util.Types;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import junit.framework.TestCase;
/** @author dpb@google.com (David P. Baker) */
public class MapBinderTest extends TestCase {
private static final ImmutableSet<Key<?>> FRAMEWORK_KEYS =
ImmutableSet.of(
Key.get(java.util.logging.Logger.class), Key.get(Stage.class), Key.get(Injector.class));
final TypeLiteral<Map<String, javax.inject.Provider<String>>> mapOfStringJavaxProvider =
new TypeLiteral<Map<String, javax.inject.Provider<String>>>() {};
final TypeLiteral<Map<String, Provider<String>>> mapOfStringProvider =
new TypeLiteral<Map<String, Provider<String>>>() {};
final TypeLiteral<Map<String, String>> mapOfString = new TypeLiteral<Map<String, String>>() {};
final TypeLiteral<Map<Integer, String>> mapOfIntString =
new TypeLiteral<Map<Integer, String>>() {};
final TypeLiteral<Map<String, Integer>> mapOfInteger = new TypeLiteral<Map<String, Integer>>() {};
final TypeLiteral<Map<String, Set<String>>> mapOfSetOfString =
new TypeLiteral<Map<String, Set<String>>>() {};
private final TypeLiteral<String> stringType = TypeLiteral.get(String.class);
private final TypeLiteral<Integer> intType = TypeLiteral.get(Integer.class);
private Type javaxProviderOf(Type type) {
return Types.javaxProviderOf(type);
}
private Type mapEntryOf(Type keyType, Type valueType) {
return Types.newParameterizedTypeWithOwner(Map.class, Map.Entry.class, keyType, valueType);
}
private Type collectionOf(Type type) {
return Types.newParameterizedType(Collection.class, type);
}
public void testAllBindings() {
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, String.class).permitDuplicates();
}
};
Injector injector = Guice.createInjector(module);
Map<Key<?>, Binding<?>> bindings = injector.getBindings();
ImmutableSet<Key<?>> expectedBindings =
ImmutableSet.<Key<?>>builder()
.add(
// Map<K, V>
Key.get(Types.mapOf(String.class, String.class)),
// Map<K, Provider<V>>
Key.get(Types.mapOf(String.class, Types.providerOf(String.class))),
// Map<K, javax.inject.Provider<V>>
Key.get(Types.mapOf(String.class, javaxProviderOf(String.class))),
// Map<K, Set<V>>
Key.get(Types.mapOf(String.class, Types.setOf(String.class))),
// Map<K, Set<Provider<V>>
Key.get(Types.mapOf(String.class, Types.setOf(Types.providerOf(String.class)))),
// Map<K, Set<javax.inject.Provider<V>>
Key.get(
Types.mapOf(String.class, Types.setOf(Types.javaxProviderOf(String.class)))),
// Map<K, Collection<Provider<V>>
Key.get(
Types.mapOf(String.class, Types.collectionOf(Types.providerOf(String.class)))),
// Map<K, Collection<javax.inject.Provider<V>>
Key.get(
Types.mapOf(
String.class, Types.collectionOf(Types.javaxProviderOf(String.class)))),
// Set<Map.Entry<K, Provider<V>>>
Key.get(Types.setOf(mapEntryOf(String.class, Types.providerOf(String.class)))),
// Set<Map.Entry<K, javax.inject.Provider<V>>>
Key.get(Types.setOf(mapEntryOf(String.class, Types.javaxProviderOf(String.class)))),
// Collection<Provider<Map.Entry<K, Provider<V>>>>
Key.get(
collectionOf(
Types.providerOf(
mapEntryOf(String.class, Types.providerOf(String.class))))),
// Collection<javax.inject.Provider<Map.Entry<K, Provider<V>>>>
Key.get(
collectionOf(
Types.javaxProviderOf(
mapEntryOf(String.class, Types.providerOf(String.class))))),
// @Named(...) Boolean
Key.get(
Boolean.class,
named(
"Multibinder<java.util.Map$Entry<java.lang.String, "
+ "com.google.inject.Provider<java.lang.String>>> permits duplicates")))
.addAll(FRAMEWORK_KEYS)
.build();
Set<Key<?>> missingBindings = Sets.difference(expectedBindings, bindings.keySet());
Set<Key<?>> extraBindings = Sets.difference(bindings.keySet(), expectedBindings);
assertTrue(
"There should be no missing bindings. Missing: " + missingBindings,
missingBindings.isEmpty());
assertTrue(
"There should be no extra bindings. Extra: " + extraBindings, extraBindings.isEmpty());
}
public void testMapBinderAggregatesMultipleModules() {
Module abc =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("a").toInstance("A");
multibinder.addBinding("b").toInstance("B");
multibinder.addBinding("c").toInstance("C");
}
};
Module de =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("d").toInstance("D");
multibinder.addBinding("e").toInstance("E");
}
};
Injector injector = Guice.createInjector(abc, de);
Map<String, String> abcde = injector.getInstance(Key.get(mapOfString));
assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E"), abcde);
assertMapVisitor(
Key.get(mapOfString),
stringType,
stringType,
setOf(abc, de),
BOTH,
false,
0,
instance("a", "A"),
instance("b", "B"),
instance("c", "C"),
instance("d", "D"),
instance("e", "E"));
// just make sure these succeed
injector.getInstance(Key.get(mapOfStringProvider));
injector.getInstance(Key.get(mapOfStringJavaxProvider));
}
public void testMapBinderAggregationForAnnotationInstance() {
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class, Names.named("abc"));
multibinder.addBinding("a").toInstance("A");
multibinder.addBinding("b").toInstance("B");
multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class, Names.named("abc"));
multibinder.addBinding("c").toInstance("C");
}
};
Injector injector = Guice.createInjector(module);
Key<Map<String, String>> key = Key.get(mapOfString, Names.named("abc"));
Map<String, String> abc = injector.getInstance(key);
assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
assertMapVisitor(
key,
stringType,
stringType,
setOf(module),
BOTH,
false,
0,
instance("a", "A"),
instance("b", "B"),
instance("c", "C"));
// just make sure these succeed
injector.getInstance(Key.get(mapOfStringProvider, Names.named("abc")));
injector.getInstance(Key.get(mapOfStringJavaxProvider, Names.named("abc")));
}
public void testMapBinderAggregationForAnnotationType() {
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class, Abc.class);
multibinder.addBinding("a").toInstance("A");
multibinder.addBinding("b").toInstance("B");
multibinder = MapBinder.newMapBinder(binder(), String.class, String.class, Abc.class);
multibinder.addBinding("c").toInstance("C");
}
};
Injector injector = Guice.createInjector(module);
Key<Map<String, String>> key = Key.get(mapOfString, Abc.class);
Map<String, String> abc = injector.getInstance(key);
assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
assertMapVisitor(
key,
stringType,
stringType,
setOf(module),
BOTH,
false,
0,
instance("a", "A"),
instance("b", "B"),
instance("c", "C"));
// just make sure these succeed
injector.getInstance(Key.get(mapOfStringProvider, Abc.class));
injector.getInstance(Key.get(mapOfStringJavaxProvider, Abc.class));
}
public void testMapBinderWithMultipleAnnotationValueSets() {
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> abcMapBinder =
MapBinder.newMapBinder(binder(), String.class, String.class, named("abc"));
abcMapBinder.addBinding("a").toInstance("A");
abcMapBinder.addBinding("b").toInstance("B");
abcMapBinder.addBinding("c").toInstance("C");
MapBinder<String, String> deMapBinder =
MapBinder.newMapBinder(binder(), String.class, String.class, named("de"));
deMapBinder.addBinding("d").toInstance("D");
deMapBinder.addBinding("e").toInstance("E");
}
};
Injector injector = Guice.createInjector(module);
Key<Map<String, String>> abcKey = Key.get(mapOfString, named("abc"));
Map<String, String> abc = injector.getInstance(abcKey);
Key<Map<String, String>> deKey = Key.get(mapOfString, named("de"));
Map<String, String> de = injector.getInstance(deKey);
assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
assertEquals(mapOf("d", "D", "e", "E"), de);
assertMapVisitor(
abcKey,
stringType,
stringType,
setOf(module),
BOTH,
false,
1,
instance("a", "A"),
instance("b", "B"),
instance("c", "C"));
assertMapVisitor(
deKey,
stringType,
stringType,
setOf(module),
BOTH,
false,
1,
instance("d", "D"),
instance("e", "E"));
// just make sure these succeed
injector.getInstance(Key.get(mapOfStringProvider, named("abc")));
injector.getInstance(Key.get(mapOfStringJavaxProvider, named("abc")));
injector.getInstance(Key.get(mapOfStringProvider, named("de")));
injector.getInstance(Key.get(mapOfStringJavaxProvider, named("de")));
}
public void testMapBinderWithMultipleAnnotationTypeSets() {
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> abcMapBinder =
MapBinder.newMapBinder(binder(), String.class, String.class, Abc.class);
abcMapBinder.addBinding("a").toInstance("A");
abcMapBinder.addBinding("b").toInstance("B");
abcMapBinder.addBinding("c").toInstance("C");
MapBinder<String, String> deMapBinder =
MapBinder.newMapBinder(binder(), String.class, String.class, De.class);
deMapBinder.addBinding("d").toInstance("D");
deMapBinder.addBinding("e").toInstance("E");
}
};
Injector injector = Guice.createInjector(module);
Key<Map<String, String>> abcKey = Key.get(mapOfString, Abc.class);
Map<String, String> abc = injector.getInstance(abcKey);
Key<Map<String, String>> deKey = Key.get(mapOfString, De.class);
Map<String, String> de = injector.getInstance(deKey);
assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
assertEquals(mapOf("d", "D", "e", "E"), de);
assertMapVisitor(
abcKey,
stringType,
stringType,
setOf(module),
BOTH,
false,
1,
instance("a", "A"),
instance("b", "B"),
instance("c", "C"));
assertMapVisitor(
deKey,
stringType,
stringType,
setOf(module),
BOTH,
false,
1,
instance("d", "D"),
instance("e", "E"));
// just make sure these succeed
injector.getInstance(Key.get(mapOfStringProvider, Abc.class));
injector.getInstance(Key.get(mapOfStringJavaxProvider, Abc.class));
injector.getInstance(Key.get(mapOfStringProvider, De.class));
injector.getInstance(Key.get(mapOfStringJavaxProvider, De.class));
}
public void testMapBinderWithMultipleTypes() {
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, String.class)
.addBinding("a")
.toInstance("A");
MapBinder.newMapBinder(binder(), String.class, Integer.class)
.addBinding("1")
.toInstance(1);
}
};
Injector injector = Guice.createInjector(module);
assertEquals(mapOf("a", "A"), injector.getInstance(Key.get(mapOfString)));
assertEquals(mapOf("1", 1), injector.getInstance(Key.get(mapOfInteger)));
assertMapVisitor(
Key.get(mapOfString),
stringType,
stringType,
setOf(module),
BOTH,
false,
1,
instance("a", "A"));
assertMapVisitor(
Key.get(mapOfInteger),
stringType,
intType,
setOf(module),
BOTH,
false,
1,
instance("1", 1));
}
public void testMapBinderWithEmptyMap() {
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, String.class);
}
};
Injector injector = Guice.createInjector(module);
Map<String, String> map = injector.getInstance(Key.get(mapOfString));
assertEquals(Collections.emptyMap(), map);
assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), BOTH, false, 0);
}
public void testMapBinderMapIsUnmodifiable() {
Injector injector =
Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, String.class)
.addBinding("a")
.toInstance("A");
}
});
Map<String, String> map = injector.getInstance(Key.get(mapOfString));
try {
map.clear();
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void testMapBinderMapIsLazy() {
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, Integer.class)
.addBinding("num")
.toProvider(
new Provider<Integer>() {
int nextValue = 1;
@Override
public Integer get() {
return nextValue++;
}
});
}
};
Injector injector = Guice.createInjector(module);
assertEquals(mapOf("num", 1), injector.getInstance(Key.get(mapOfInteger)));
assertEquals(mapOf("num", 2), injector.getInstance(Key.get(mapOfInteger)));
assertEquals(mapOf("num", 3), injector.getInstance(Key.get(mapOfInteger)));
assertMapVisitor(
Key.get(mapOfInteger),
stringType,
intType,
setOf(module),
BOTH,
false,
0,
providerInstance("num", 1));
}
public void testMapBinderMapForbidsDuplicateKeys() {
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("a").toInstance("A");
multibinder.addBinding("a").toInstance("B");
}
};
try {
Guice.createInjector(module);
fail();
} catch (CreationException expected) {
assertContains(expected.getMessage(), "Map injection failed due to duplicated key \"a\"");
}
assertMapVisitor(
Key.get(mapOfString),
stringType,
stringType,
setOf(module),
MODULE,
false,
0,
instance("a", "A"),
instance("a", "B"));
}
public void testExhaustiveDuplicateErrorMessage() throws Exception {
class Module1 extends AbstractModule {
@Override
protected void configure() {
MapBinder<String, Object> mapbinder =
MapBinder.newMapBinder(binder(), String.class, Object.class);
mapbinder.addBinding("a").to(String.class);
}
}
class Module2 extends AbstractModule {
@Override
protected void configure() {
MapBinder<String, Object> mapbinder =
MapBinder.newMapBinder(binder(), String.class, Object.class);
mapbinder.addBinding("a").to(Integer.class);
mapbinder.addBinding("b").to(String.class);
}
}
class Module3 extends AbstractModule {
@Override
protected void configure() {
MapBinder<String, Object> mapbinder =
MapBinder.newMapBinder(binder(), String.class, Object.class);
mapbinder.addBinding("b").to(Integer.class);
}
}
class Main extends AbstractModule {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, Object.class);
install(new Module1());
install(new Module2());
install(new Module3());
}
@Provides
String provideString() {
return "foo";
}
@Provides
Integer provideInt() {
return 42;
}
}
try {
Guice.createInjector(new Main());
fail();
} catch (CreationException ce) {
assertContains(
ce.getMessage(),
"Map injection failed due to duplicated key \"a\", from bindings:",
asModuleChain(Main.class, Module1.class),
asModuleChain(Main.class, Module2.class),
"and key: \"b\", from bindings:",
asModuleChain(Main.class, Module2.class),
asModuleChain(Main.class, Module3.class),
"at " + Main.class.getName() + ".configure(",
asModuleChain(Main.class, RealMapBinder.class));
assertEquals(1, ce.getErrorMessages().size());
}
}
public void testMapBinderMapPermitDuplicateElements() {
Module ab =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("a").toInstance("A");
multibinder.addBinding("b").toInstance("B");
multibinder.permitDuplicates();
}
};
Module bc =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("b").toInstance("B");
multibinder.addBinding("c").toInstance("C");
multibinder.permitDuplicates();
}
};
Injector injector = Guice.createInjector(ab, bc);
assertEquals(mapOf("a", "A", "b", "B", "c", "C"), injector.getInstance(Key.get(mapOfString)));
assertMapVisitor(
Key.get(mapOfString),
stringType,
stringType,
setOf(ab, bc),
BOTH,
true,
0,
instance("a", "A"),
instance("b", "B"),
instance("c", "C"));
}
public void testMapBinderMapDoesNotDedupeDuplicateValues() {
class ValueType {
int keyPart;
int dataPart;
private ValueType(int keyPart, int dataPart) {
this.keyPart = keyPart;
this.dataPart = dataPart;
}
@Override
public boolean equals(Object obj) {
return (obj instanceof ValueType) && (keyPart == ((ValueType) obj).keyPart);
}
@Override
public int hashCode() {
return keyPart;
}
}
Module m1 =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, ValueType> multibinder =
MapBinder.newMapBinder(binder(), String.class, ValueType.class);
multibinder.addBinding("a").toInstance(new ValueType(1, 2));
}
};
Module m2 =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, ValueType> multibinder =
MapBinder.newMapBinder(binder(), String.class, ValueType.class);
multibinder.addBinding("b").toInstance(new ValueType(1, 3));
}
};
Injector injector = Guice.createInjector(m1, m2);
Map<String, ValueType> map = injector.getInstance(new Key<Map<String, ValueType>>() {});
assertEquals(2, map.get("a").dataPart);
assertEquals(3, map.get("b").dataPart);
}
public void testMapBinderMultimap() {
AbstractModule ab1c =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("a").toInstance("A");
multibinder.addBinding("b").toInstance("B1");
multibinder.addBinding("c").toInstance("C");
}
};
AbstractModule b2c =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("b").toInstance("B2");
multibinder.addBinding("c").toInstance("C");
multibinder.permitDuplicates();
}
};
Injector injector = Guice.createInjector(ab1c, b2c);
assertEquals(
mapOf("a", setOf("A"), "b", setOf("B1", "B2"), "c", setOf("C")),
injector.getInstance(Key.get(mapOfSetOfString)));
assertMapVisitor(
Key.get(mapOfString),
stringType,
stringType,
setOf(ab1c, b2c),
BOTH,
true,
0,
instance("a", "A"),
instance("b", "B1"),
instance("b", "B2"),
instance("c", "C"));
}
public void testMapBinderMultimapWithAnotation() {
AbstractModule ab1 =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class, Abc.class);
multibinder.addBinding("a").toInstance("A");
multibinder.addBinding("b").toInstance("B1");
}
};
AbstractModule b2c =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class, Abc.class);
multibinder.addBinding("b").toInstance("B2");
multibinder.addBinding("c").toInstance("C");
multibinder.permitDuplicates();
}
};
Injector injector = Guice.createInjector(ab1, b2c);
assertEquals(
mapOf("a", setOf("A"), "b", setOf("B1", "B2"), "c", setOf("C")),
injector.getInstance(Key.get(mapOfSetOfString, Abc.class)));
try {
injector.getInstance(Key.get(mapOfSetOfString));
fail();
} catch (ConfigurationException expected) {
}
assertMapVisitor(
Key.get(mapOfString, Abc.class),
stringType,
stringType,
setOf(ab1, b2c),
BOTH,
true,
0,
instance("a", "A"),
instance("b", "B1"),
instance("b", "B2"),
instance("c", "C"));
}
public void testMapBinderMultimapIsUnmodifiable() {
Injector injector =
Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> mapBinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
mapBinder.addBinding("a").toInstance("A");
mapBinder.permitDuplicates();
}
});
Map<String, Set<String>> map = injector.getInstance(Key.get(mapOfSetOfString));
try {
map.clear();
fail();
} catch (UnsupportedOperationException expected) {
}
try {
map.get("a").clear();
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void testMapBinderMapForbidsNullKeys() {
try {
Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, String.class).addBinding(null);
}
});
fail();
} catch (CreationException expected) {
}
}
public void testMapBinderMapForbidsNullValues() {
Module m =
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, String.class)
.addBinding("null")
.toProvider(Providers.<String>of(null));
}
};
Injector injector = Guice.createInjector(m);
try {
injector.getInstance(Key.get(mapOfString));
fail();
} catch (ProvisionException expected) {
assertContains(
expected.getMessage(),
"1) Map injection failed due to null value for key \"null\", bound at: "
+ m.getClass().getName()
+ ".configure(");
}
}
public void testMapBinderProviderIsScoped() {
final Provider<Integer> counter =
new Provider<Integer>() {
int next = 1;
@Override
public Integer get() {
return next++;
}
};
Injector injector =
Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, Integer.class)
.addBinding("one")
.toProvider(counter)
.asEagerSingleton();
}
});
assertEquals(1, (int) injector.getInstance(Key.get(mapOfInteger)).get("one"));
assertEquals(1, (int) injector.getInstance(Key.get(mapOfInteger)).get("one"));
}
public void testSourceLinesInMapBindings() {
try {
Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, Integer.class).addBinding("one");
}
});
fail();
} catch (CreationException expected) {
assertContains(
expected.getMessage(),
"1) No implementation for java.lang.Integer",
"at " + getClass().getName());
}
}
/** Check that the dependencies are correct. */
public void testMultibinderDependencies() {
Injector injector =
Guice.createInjector(
new AbstractModule() {
@Override
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");
}
});
Binding<Map<Integer, String>> binding = injector.getBinding(new Key<Map<Integer, String>>() {});
HasDependencies withDependencies = (HasDependencies) binding;
Set<Dependency<?>> actualDependencies = withDependencies.getDependencies();
// We expect two dependencies, because the dependencies are annotated with
// Element, which has a uniqueId, it's difficult to directly compare them.
// Instead we will manually compare all the fields except the uniqueId
assertEquals(2, actualDependencies.size());
for (Dependency<?> dependency : actualDependencies) {
Key<?> key = dependency.getKey();
assertEquals(new TypeLiteral<String>() {}, key.getTypeLiteral());
Annotation annotation = dependency.getKey().getAnnotation();
assertTrue(annotation instanceof Element);
Element element = (Element) annotation;
assertEquals("", element.setName());
assertEquals(Element.Type.MAPBINDER, element.type());
assertEquals("java.lang.Integer", element.keyType());
}
Set<String> elements = Sets.newHashSet();
elements.addAll(recurseForDependencies(injector, withDependencies));
assertEquals(ImmutableSet.of("A", "B"), elements);
}
private Set<String> recurseForDependencies(Injector injector, HasDependencies hasDependencies) {
Set<String> elements = Sets.newHashSet();
for (Dependency<?> dependency : hasDependencies.getDependencies()) {
Binding<?> binding = injector.getBinding(dependency.getKey());
HasDependencies deps = (HasDependencies) binding;
if (binding instanceof InstanceBinding) {
elements.add((String) ((InstanceBinding<?>) binding).getInstance());
} else {
elements.addAll(recurseForDependencies(injector, deps));
}
}
return elements;
}
/** Check that the dependencies are correct in the Tool Stage. */
public void testMultibinderDependenciesInToolStage() {
Injector injector =
Guice.createInjector(
Stage.TOOL,
new AbstractModule() {
@Override
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");
}
});
Binding<Map<Integer, String>> binding = injector.getBinding(new Key<Map<Integer, String>>() {});
HasDependencies withDependencies = (HasDependencies) binding;
Set<Dependency<?>> actualDependencies = withDependencies.getDependencies();
// We expect two dependencies, because the dependencies are annotated with
// Element, which has a uniqueId, it's difficult to directly compare them.
// Instead we will manually compare all the fields except the uniqueId
assertEquals(2, actualDependencies.size());
for (Dependency<?> dependency : actualDependencies) {
Key<?> key = dependency.getKey();
assertEquals(new TypeLiteral<String>() {}, key.getTypeLiteral());
Annotation annotation = dependency.getKey().getAnnotation();
assertTrue(annotation instanceof Element);
Element element = (Element) annotation;
assertEquals("", element.setName());
assertEquals(Element.Type.MAPBINDER, element.type());
assertEquals("java.lang.Integer", element.keyType());
}
}
/** Our implementation maintains order, but doesn't guarantee it in the API spec. */
// TODO: specify the iteration order
public void testBindOrderEqualsIterationOrder() {
Injector injector =
Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> mapBinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
mapBinder.addBinding("leonardo").toInstance("blue");
mapBinder.addBinding("donatello").toInstance("purple");
install(
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, String.class)
.addBinding("michaelangelo")
.toInstance("orange");
}
});
}
},
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, String.class)
.addBinding("raphael")
.toInstance("red");
}
});
Map<String, String> map = injector.getInstance(new Key<Map<String, String>>() {});
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
assertEquals(Maps.immutableEntry("leonardo", "blue"), iterator.next());
assertEquals(Maps.immutableEntry("donatello", "purple"), iterator.next());
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() {
@Override
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() {
@Override
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() {
@Override
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)));
assertMapVisitor(
Key.get(mapOfString),
stringType,
stringType,
setOf(abcd, ef),
BOTH,
false,
0,
instance("a", "A"),
instance("b", "B"),
instance("c", "C"),
instance("d", "D"),
instance("e", "E"),
instance("f", "F"));
}
public void testDeduplicateMapBindings() {
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> mapbinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
mapbinder.addBinding("a").toInstance("A");
mapbinder.addBinding("a").toInstance("A");
mapbinder.addBinding("b").toInstance("B");
mapbinder.addBinding("b").toInstance("B");
}
};
Injector injector = Guice.createInjector(module);
assertEquals(mapOf("a", "A", "b", "B"), injector.getInstance(Key.get(mapOfString)));
assertMapVisitor(
Key.get(mapOfString),
stringType,
stringType,
setOf(module),
BOTH,
false,
0,
instance("a", "A"),
instance("b", "B"));
}
/** With overrides, we should get the union of all map bindings. */
public void testModuleOverrideAndMapBindingsWithPermitDuplicates() {
Module abc =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("a").toInstance("A");
multibinder.addBinding("b").toInstance("B");
multibinder.addBinding("c").toInstance("C");
multibinder.permitDuplicates();
}
};
Module cd =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("c").toInstance("C");
multibinder.addBinding("d").toInstance("D");
multibinder.permitDuplicates();
}
};
Module ef =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("e").toInstance("E");
multibinder.addBinding("f").toInstance("F");
multibinder.permitDuplicates();
}
};
Module abcd = Modules.override(abc).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)));
assertMapVisitor(
Key.get(mapOfString),
stringType,
stringType,
setOf(abcd, ef),
BOTH,
true,
0,
instance("a", "A"),
instance("b", "B"),
instance("c", "C"),
instance("d", "D"),
instance("e", "E"),
instance("f", "F"));
}
/** Ensure there are no initialization race conditions in basic map injection. */
public void testBasicMapDependencyInjection() {
final AtomicReference<Map<String, String>> injectedMap =
new AtomicReference<Map<String, String>>();
final Object anObject =
new Object() {
@Inject
void initialize(Map<String, String> map) {
injectedMap.set(map);
}
};
Module abc =
new AbstractModule() {
@Override
protected void configure() {
requestInjection(anObject);
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.addBinding("a").toInstance("A");
multibinder.addBinding("b").toInstance("B");
multibinder.addBinding("c").toInstance("C");
}
};
Guice.createInjector(abc);
assertEquals(mapOf("a", "A", "b", "B", "c", "C"), injectedMap.get());
}
/** Ensure there are no initialization race conditions in provider multimap injection. */
public void testProviderMultimapDependencyInjection() {
final AtomicReference<Map<String, Set<Provider<String>>>> injectedMultimap =
new AtomicReference<Map<String, Set<Provider<String>>>>();
final Object anObject =
new Object() {
@Inject
void initialize(Map<String, Set<Provider<String>>> multimap) {
injectedMultimap.set(multimap);
}
};
Module abc =
new AbstractModule() {
@Override
protected void configure() {
requestInjection(anObject);
MapBinder<String, String> multibinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
multibinder.permitDuplicates();
multibinder.addBinding("a").toInstance("A");
multibinder.addBinding("b").toInstance("B");
multibinder.addBinding("c").toInstance("C");
}
};
Guice.createInjector(abc);
Map<String, String> map =
Maps.transformValues(
injectedMultimap.get(),
new Function<Set<Provider<String>>, String>() {
@Override
public String apply(Set<Provider<String>> stringProvidersSet) {
return Iterables.getOnlyElement(stringProvidersSet).get();
}
});
assertEquals(mapOf("a", "A", "b", "B", "c", "C"), map);
}
@Retention(RUNTIME)
@BindingAnnotation
@interface Abc {}
@Retention(RUNTIME)
@BindingAnnotation
@interface De {}
@SuppressWarnings("unchecked")
private <K, V> Map<K, V> mapOf(Object... elements) {
Map<K, V> result = new HashMap<>();
for (int i = 0; i < elements.length; i += 2) {
result.put((K) elements[i], (V) elements[i + 1]);
}
return result;
}
@SuppressWarnings("unchecked")
private <V> Set<V> setOf(V... elements) {
return new HashSet<V>(Arrays.asList(elements));
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
private static @interface Marker {}
@Marker
public void testMapBinderMatching() throws Exception {
Method m = MapBinderTest.class.getDeclaredMethod("testMapBinderMatching");
assertNotNull(m);
final Annotation marker = m.getAnnotation(Marker.class);
Injector injector =
Guice.createInjector(
new AbstractModule() {
@Override
public void configure() {
MapBinder<Integer, Integer> mb1 =
MapBinder.newMapBinder(binder(), Integer.class, Integer.class, Marker.class);
MapBinder<Integer, Integer> mb2 =
MapBinder.newMapBinder(binder(), Integer.class, Integer.class, marker);
mb1.addBinding(1).toInstance(1);
mb2.addBinding(2).toInstance(2);
// This assures us that the two binders are equivalent, so we expect the instance added to
// each to have been added to one set.
assertEquals(mb1, mb2);
}
});
TypeLiteral<Map<Integer, Integer>> t = new TypeLiteral<Map<Integer, Integer>>() {};
Map<Integer, Integer> s1 = injector.getInstance(Key.get(t, Marker.class));
Map<Integer, Integer> s2 = injector.getInstance(Key.get(t, marker));
// This assures us that the two sets are in fact equal. They may not be same set (as in Java
// object identical), but we shouldn't expect that, since probably Guice creates the set each
// time in case the elements are dependent on scope.
assertEquals(s1, s2);
// This ensures that MultiBinder is internally using the correct set name --
// making sure that instances of marker annotations have the same set name as
// MarkerAnnotation.class.
Map<Integer, Integer> expected = new HashMap<>();
expected.put(1, 1);
expected.put(2, 2);
assertEquals(expected, s1);
}
public void testTwoMapBindersAreDistinct() {
Injector injector =
Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
MapBinder.newMapBinder(binder(), String.class, String.class)
.addBinding("A")
.toInstance("a");
MapBinder.newMapBinder(binder(), Integer.class, String.class)
.addBinding(1)
.toInstance("b");
}
});
Collector collector = new Collector();
Binding<Map<String, String>> map1 = injector.getBinding(Key.get(mapOfString));
map1.acceptTargetVisitor(collector);
assertNotNull(collector.mapbinding);
MapBinderBinding<?> map1Binding = collector.mapbinding;
Binding<Map<Integer, String>> map2 = injector.getBinding(Key.get(mapOfIntString));
map2.acceptTargetVisitor(collector);
assertNotNull(collector.mapbinding);
MapBinderBinding<?> map2Binding = collector.mapbinding;
List<Binding<String>> bindings = injector.findBindingsByType(stringType);
assertEquals("should have two elements: " + bindings, 2, bindings.size());
Binding<String> a = bindings.get(0);
Binding<String> b = bindings.get(1);
assertEquals("a", ((InstanceBinding<String>) a).getInstance());
assertEquals("b", ((InstanceBinding<String>) b).getInstance());
// Make sure the correct elements belong to their own sets.
assertTrue(map1Binding.containsElement(a));
assertFalse(map1Binding.containsElement(b));
assertFalse(map2Binding.containsElement(a));
assertTrue(map2Binding.containsElement(b));
}
// Tests for com.google.inject.internal.WeakKeySet not leaking memory.
public void testWeakKeySet_integration_mapbinder() {
Key<Map<String, String>> mapKey = Key.get(new TypeLiteral<Map<String, String>>() {});
Injector parentInjector =
Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
bind(String.class).toInstance("hi");
}
});
WeakKeySetUtils.assertNotBlacklisted(parentInjector, mapKey);
Injector childInjector =
parentInjector.createChildInjector(
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> binder =
MapBinder.newMapBinder(binder(), String.class, String.class);
binder.addBinding("bar").toInstance("foo");
}
});
WeakReference<Injector> weakRef = new WeakReference<>(childInjector);
WeakKeySetUtils.assertBlacklisted(parentInjector, mapKey);
// Clear the ref, GC, and ensure that we are no longer blacklisting.
childInjector = null;
Asserts.awaitClear(weakRef);
WeakKeySetUtils.assertNotBlacklisted(parentInjector, mapKey);
}
@SuppressWarnings("rawtypes")
public void testGetEntries() {
List<com.google.inject.spi.Element> elements =
Elements.getElements(new MapBinderWithTwoEntriesModule());
// Get the MapBinderBinding
MapBinderBinding<?> mapBinderBinding = getMapBinderBinding(elements);
// Execute the call to getEntries
List<Map.Entry<?, Binding<?>>> mapEntries = mapBinderBinding.getEntries(elements);
// Assert on the results
Map.Entry<?, Binding<?>> firstEntry = mapEntries.get(0);
assertEquals("keyOne", firstEntry.getKey());
Binding<?> firstBinding = firstEntry.getValue();
assertEquals("valueOne", ((InstanceBinding) firstBinding).getInstance());
Map.Entry<?, Binding<?>> secondEntry = mapEntries.get(1);
assertEquals("keyTwo", secondEntry.getKey());
Binding<?> secondBinding = secondEntry.getValue();
assertEquals("valueTwo", ((InstanceBinding) secondBinding).getInstance());
}
@SuppressWarnings("rawtypes")
public void testGetEntriesWithDuplicateKeys() {
// Set up the module
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> mapBinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
mapBinder.addBinding("A").toInstance("a1");
mapBinder.addBinding("A").toInstance("a2");
mapBinder.permitDuplicates();
}
};
// Get the MapBinderBinding
List<com.google.inject.spi.Element> elements = Elements.getElements(module);
MapBinderBinding<?> mapBinderBinding = getMapBinderBinding(elements);
// Execute the call to getEntries
List<Map.Entry<?, Binding<?>>> mapEntries = mapBinderBinding.getEntries(elements);
// Assert on the results
Map.Entry<?, Binding<?>> firstEntry = mapEntries.get(0);
assertEquals("A", firstEntry.getKey());
Binding<?> firstBinding = firstEntry.getValue();
assertEquals("a1", ((InstanceBinding) firstBinding).getInstance());
Map.Entry<?, Binding<?>> secondEntry = mapEntries.get(1);
assertEquals("A", secondEntry.getKey());
Binding<?> secondBinding = secondEntry.getValue();
assertEquals("a2", ((InstanceBinding) secondBinding).getInstance());
}
@SuppressWarnings("rawtypes")
public void testGetEntriesWithDuplicateValues() {
// Set up the module
Module module =
new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, String> mapBinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
mapBinder.addBinding("A").toInstance("a");
mapBinder.addBinding("A").toInstance("a");
}
};
// Get the MapBinderBinding
List<com.google.inject.spi.Element> elements = Elements.getElements(module);
MapBinderBinding<?> mapBinderBinding = getMapBinderBinding(elements);
// Execute the call to getEntries
List<Map.Entry<?, Binding<?>>> mapEntries = mapBinderBinding.getEntries(elements);
// Assert on the results
Map.Entry<?, Binding<?>> firstEntry = mapEntries.get(0);
assertEquals("A", firstEntry.getKey());
Binding<?> firstBinding = firstEntry.getValue();
assertEquals("a", ((InstanceBinding) firstBinding).getInstance());
Map.Entry<?, Binding<?>> secondEntry = mapEntries.get(1);
assertEquals("A", secondEntry.getKey());
Binding<?> secondBinding = secondEntry.getValue();
assertEquals("a", ((InstanceBinding) secondBinding).getInstance());
}
@SuppressWarnings("rawtypes")
public void testGetEntriesMissingProviderMapEntry() {
List<com.google.inject.spi.Element> elements =
Lists.newArrayList(Elements.getElements(new MapBinderWithTwoEntriesModule()));
// Get the MapBinderBinding
MapBinderBinding<?> mapBinderBinding = getMapBinderBinding(elements);
// Remove the ProviderMapEntry for "a" from the elements
com.google.inject.spi.Element providerMapEntryForA = getProviderMapEntry("keyOne", elements);
boolean removeSuccessful = elements.remove(providerMapEntryForA);
assertTrue(removeSuccessful);
// Execute the call to getEntries, we expect it to fail
try {
mapBinderBinding.getEntries(elements);
fail();
} catch (IllegalArgumentException expected) {
assertContains(
expected.getMessage(),
"Expected a 1:1 mapping from map keys to values.",
"Found these Bindings that were missing an associated entry:",
"java.lang.String",
"bound at:",
"MapBinderWithTwoEntriesModule");
}
}
/**
* Will find and return the {@link com.google.inject.spi.Element} that is a {@link
* ProviderMapEntry} with a key that matches the one supplied by the user in {@code k}.
*
* <p>Will return {@code null} if it cannot be found.
*/
private static com.google.inject.spi.Element getProviderMapEntry(
Object kToFind, Iterable<com.google.inject.spi.Element> elements) {
for (com.google.inject.spi.Element element : elements) {
if (element instanceof ProviderInstanceBinding) {
javax.inject.Provider<?> usp =
((ProviderInstanceBinding<?>) element).getUserSuppliedProvider();
if (usp instanceof ProviderMapEntry) {
ProviderMapEntry<?, ?> pme = (ProviderMapEntry<?, ?>) usp;
// Check if the key from the ProviderMapEntry matches the one we're looking for
if (kToFind.equals(pme.getKey())) {
return element;
}
}
}
}
// No matching ProviderMapEntry found
return null;
}
@SuppressWarnings("rawtypes")
public void testGetEntriesMissingBindingForValue() {
List<com.google.inject.spi.Element> elements =
Lists.newArrayList(Elements.getElements(new MapBinderWithTwoEntriesModule()));
// Get the MapBinderBinding
MapBinderBinding<?> mapBinderBinding = getMapBinderBinding(elements);
// Remove the ProviderMapEntry for "a" from the elements
com.google.inject.spi.Element bindingForA = getInstanceBindingForValue("valueOne", elements);
boolean removeSuccessful = elements.remove(bindingForA);
assertTrue(removeSuccessful);
// Execute the call to getEntries, we expect it to fail
try {
mapBinderBinding.getEntries(elements);
fail();
} catch (IllegalArgumentException expected) {
assertContains(
expected.getMessage(),
"Expected a 1:1 mapping from map keys to values.",
"Found these map keys without a corresponding value:",
"keyOne",
"bound at:",
"MapBinderWithTwoEntriesModule");
}
}
/**
* Will find and return the {@link com.google.inject.spi.Element} that is an {@link
* InstanceBinding} and binds {@code vToFind}.
*/
private static com.google.inject.spi.Element getInstanceBindingForValue(
Object vToFind, Iterable<com.google.inject.spi.Element> elements) {
for (com.google.inject.spi.Element element : elements) {
if (element instanceof InstanceBinding) {
Object instanceFromBinding = ((InstanceBinding<?>) element).getInstance();
if (vToFind.equals(instanceFromBinding)) {
return element;
}
}
}
// No matching binding found
return null;
}
/** A simple module with a MapBinder with two entries. */
private static final class MapBinderWithTwoEntriesModule extends AbstractModule {
@Override
protected void configure() {
MapBinder<String, String> mapBinder =
MapBinder.newMapBinder(binder(), String.class, String.class);
mapBinder.addBinding("keyOne").toInstance("valueOne");
mapBinder.addBinding("keyTwo").toInstance("valueTwo");
}
}
/**
* Given an {@link Iterable} of elements, return the one that is a {@link MapBinderBinding}, or
* {@code null} if it cannot be found.
*/
private static MapBinderBinding<?> getMapBinderBinding(
Iterable<com.google.inject.spi.Element> elements) {
final Collector collector = new Collector();
for (com.google.inject.spi.Element element : elements) {
element.acceptVisitor(
new DefaultElementVisitor<Void>() {
@Override
public <T> Void visit(Binding<T> binding) {
binding.acceptTargetVisitor(collector);
return null;
}
});
}
return collector.mapbinding;
}
}