PageRenderTime 60ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java

https://gitlab.com/metamorphiccode/guice
Java | 1032 lines | 869 code | 106 blank | 57 comment | 6 complexity | df2b4ead856cc1ae19f31a22adc3037f MD5 | raw file
  1. /**
  2. * Copyright (C) 2008 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.google.inject.multibindings;
  17. import static com.google.inject.Asserts.asModuleChain;
  18. import static com.google.inject.Asserts.assertContains;
  19. import static com.google.inject.multibindings.SpiUtils.VisitType.BOTH;
  20. import static com.google.inject.multibindings.SpiUtils.VisitType.MODULE;
  21. import static com.google.inject.multibindings.SpiUtils.assertMapVisitor;
  22. import static com.google.inject.multibindings.SpiUtils.instance;
  23. import static com.google.inject.multibindings.SpiUtils.providerInstance;
  24. import static com.google.inject.name.Names.named;
  25. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  26. import com.google.common.base.Function;
  27. import com.google.common.collect.ImmutableSet;
  28. import com.google.common.collect.Iterables;
  29. import com.google.common.collect.Maps;
  30. import com.google.common.collect.Sets;
  31. import com.google.inject.AbstractModule;
  32. import com.google.inject.Asserts;
  33. import com.google.inject.Binding;
  34. import com.google.inject.BindingAnnotation;
  35. import com.google.inject.ConfigurationException;
  36. import com.google.inject.CreationException;
  37. import com.google.inject.Guice;
  38. import com.google.inject.Inject;
  39. import com.google.inject.Injector;
  40. import com.google.inject.Key;
  41. import com.google.inject.Module;
  42. import com.google.inject.Provider;
  43. import com.google.inject.Provides;
  44. import com.google.inject.ProvisionException;
  45. import com.google.inject.Stage;
  46. import com.google.inject.TypeLiteral;
  47. import com.google.inject.internal.WeakKeySetUtils;
  48. import com.google.inject.name.Names;
  49. import com.google.inject.spi.Dependency;
  50. import com.google.inject.spi.HasDependencies;
  51. import com.google.inject.spi.InstanceBinding;
  52. import com.google.inject.util.Modules;
  53. import com.google.inject.util.Providers;
  54. import com.google.inject.util.Types;
  55. import junit.framework.TestCase;
  56. import java.lang.annotation.Annotation;
  57. import java.lang.annotation.ElementType;
  58. import java.lang.annotation.Retention;
  59. import java.lang.annotation.RetentionPolicy;
  60. import java.lang.annotation.Target;
  61. import java.lang.ref.WeakReference;
  62. import java.lang.reflect.Method;
  63. import java.lang.reflect.Type;
  64. import java.util.Arrays;
  65. import java.util.Collection;
  66. import java.util.Collections;
  67. import java.util.HashMap;
  68. import java.util.HashSet;
  69. import java.util.Iterator;
  70. import java.util.List;
  71. import java.util.Map;
  72. import java.util.Set;
  73. import java.util.concurrent.atomic.AtomicReference;
  74. /**
  75. * @author dpb@google.com (David P. Baker)
  76. */
  77. public class MapBinderTest extends TestCase {
  78. private static final Set<Key<?>> FRAMEWORK_KEYS = ImmutableSet.of(
  79. Key.get(java.util.logging.Logger.class),
  80. Key.get(Stage.class),
  81. Key.get(Injector.class)
  82. );
  83. final TypeLiteral<Map<String, javax.inject.Provider<String>>> mapOfStringJavaxProvider =
  84. new TypeLiteral<Map<String, javax.inject.Provider<String>>>() {};
  85. final TypeLiteral<Map<String, Provider<String>>> mapOfStringProvider =
  86. new TypeLiteral<Map<String, Provider<String>>>() {};
  87. final TypeLiteral<Map<String, String>> mapOfString = new TypeLiteral<Map<String, String>>() {};
  88. final TypeLiteral<Map<Integer, String>> mapOfIntString =
  89. new TypeLiteral<Map<Integer, String>>() {};
  90. final TypeLiteral<Map<String, Integer>> mapOfInteger = new TypeLiteral<Map<String, Integer>>() {};
  91. final TypeLiteral<Map<String, Set<String>>> mapOfSetOfString =
  92. new TypeLiteral<Map<String, Set<String>>>() {};
  93. private final TypeLiteral<String> stringType = TypeLiteral.get(String.class);
  94. private final TypeLiteral<Integer> intType = TypeLiteral.get(Integer.class);
  95. private Type javaxProviderOf(Type type) {
  96. return Types.newParameterizedType(javax.inject.Provider.class, type);
  97. }
  98. private Type mapEntryOf(Type keyType, Type valueType) {
  99. return Types.newParameterizedTypeWithOwner(Map.class, Map.Entry.class, keyType, valueType);
  100. }
  101. private Type collectionOf(Type type) {
  102. return Types.newParameterizedType(Collection.class, type);
  103. }
  104. public void testAllBindings() {
  105. Module module = new AbstractModule() {
  106. @Override
  107. protected void configure() {
  108. MapBinder.newMapBinder(binder(), String.class, String.class).permitDuplicates();
  109. }
  110. };
  111. Injector injector = Guice.createInjector(module);
  112. Map<Key<?>, Binding<?>> bindings = injector.getBindings();
  113. ImmutableSet<Key<?>> expectedBindings = ImmutableSet.<Key<?>>builder()
  114. .add(
  115. // Map<K, V>
  116. Key.get(Types.mapOf(String.class, String.class)),
  117. // Map<K, Provider<V>>
  118. Key.get(Types.mapOf(String.class, Types.providerOf(String.class))),
  119. // Map<K, javax.inject.Provider<V>>
  120. Key.get(Types.mapOf(String.class, javaxProviderOf(String.class))),
  121. // Map<K, Set<V>>
  122. Key.get(Types.mapOf(String.class, Types.setOf(String.class))),
  123. // Map<K, Set<Provider<V>>
  124. Key.get(Types.mapOf(String.class, Types.setOf(Types.providerOf(String.class)))),
  125. // Set<Map.Entry<K, Provider<V>>>
  126. Key.get(Types.setOf(mapEntryOf(String.class, Types.providerOf(String.class)))),
  127. // Collection<Provider<Map.Entry<K, Provider<V>>>>
  128. Key.get(collectionOf(Types.providerOf(
  129. mapEntryOf(String.class, Types.providerOf(String.class))))),
  130. // Collection<javax.inject.Provider<Map.Entry<K, Provider<V>>>>
  131. Key.get(collectionOf(javaxProviderOf(
  132. mapEntryOf(String.class, Types.providerOf(String.class))))),
  133. // @Named(...) Boolean
  134. Key.get(Boolean.class,
  135. named("Multibinder<java.util.Map$Entry<java.lang.String, "
  136. + "com.google.inject.Provider<java.lang.String>>> permits duplicates"))
  137. )
  138. .addAll(FRAMEWORK_KEYS).build();
  139. Set<Key<?>> missingBindings = Sets.difference(expectedBindings, bindings.keySet());
  140. Set<Key<?>> extraBindings = Sets.difference(bindings.keySet(), expectedBindings);
  141. assertTrue("There should be no missing bindings. Missing: " + missingBindings,
  142. missingBindings.isEmpty());
  143. assertTrue("There should be no extra bindings. Extra: " + extraBindings,
  144. extraBindings.isEmpty());
  145. }
  146. public void testMapBinderAggregatesMultipleModules() {
  147. Module abc = new AbstractModule() {
  148. @Override protected void configure() {
  149. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  150. binder(), String.class, String.class);
  151. multibinder.addBinding("a").toInstance("A");
  152. multibinder.addBinding("b").toInstance("B");
  153. multibinder.addBinding("c").toInstance("C");
  154. }
  155. };
  156. Module de = new AbstractModule() {
  157. @Override protected void configure() {
  158. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  159. binder(), String.class, String.class);
  160. multibinder.addBinding("d").toInstance("D");
  161. multibinder.addBinding("e").toInstance("E");
  162. }
  163. };
  164. Injector injector = Guice.createInjector(abc, de);
  165. Map<String, String> abcde = injector.getInstance(Key.get(mapOfString));
  166. assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E"), abcde);
  167. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(abc, de), BOTH, false, 0,
  168. instance("a", "A"), instance("b", "B"), instance("c", "C"), instance("d", "D"), instance("e", "E"));
  169. // just make sure these succeed
  170. injector.getInstance(Key.get(mapOfStringProvider));
  171. injector.getInstance(Key.get(mapOfStringJavaxProvider));
  172. }
  173. public void testMapBinderAggregationForAnnotationInstance() {
  174. Module module = new AbstractModule() {
  175. @Override protected void configure() {
  176. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  177. binder(), String.class, String.class, Names.named("abc"));
  178. multibinder.addBinding("a").toInstance("A");
  179. multibinder.addBinding("b").toInstance("B");
  180. multibinder = MapBinder.newMapBinder(
  181. binder(), String.class, String.class, Names.named("abc"));
  182. multibinder.addBinding("c").toInstance("C");
  183. }
  184. };
  185. Injector injector = Guice.createInjector(module);
  186. Key<Map<String, String>> key = Key.get(mapOfString, Names.named("abc"));
  187. Map<String, String> abc = injector.getInstance(key);
  188. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
  189. assertMapVisitor(key, stringType, stringType, setOf(module), BOTH, false, 0,
  190. instance("a", "A"), instance("b", "B"), instance("c", "C"));
  191. // just make sure these succeed
  192. injector.getInstance(Key.get(mapOfStringProvider, Names.named("abc")));
  193. injector.getInstance(Key.get(mapOfStringJavaxProvider, Names.named("abc")));
  194. }
  195. public void testMapBinderAggregationForAnnotationType() {
  196. Module module = new AbstractModule() {
  197. @Override protected void configure() {
  198. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  199. binder(), String.class, String.class, Abc.class);
  200. multibinder.addBinding("a").toInstance("A");
  201. multibinder.addBinding("b").toInstance("B");
  202. multibinder = MapBinder.newMapBinder(
  203. binder(), String.class, String.class, Abc.class);
  204. multibinder.addBinding("c").toInstance("C");
  205. }
  206. };
  207. Injector injector = Guice.createInjector(module);
  208. Key<Map<String, String>> key = Key.get(mapOfString, Abc.class);
  209. Map<String, String> abc = injector.getInstance(key);
  210. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
  211. assertMapVisitor(key, stringType, stringType, setOf(module), BOTH, false, 0,
  212. instance("a", "A"), instance("b", "B"), instance("c", "C"));
  213. // just make sure these succeed
  214. injector.getInstance(Key.get(mapOfStringProvider, Abc.class));
  215. injector.getInstance(Key.get(mapOfStringJavaxProvider, Abc.class));
  216. }
  217. public void testMapBinderWithMultipleAnnotationValueSets() {
  218. Module module = new AbstractModule() {
  219. @Override protected void configure() {
  220. MapBinder<String, String> abcMapBinder = MapBinder.newMapBinder(
  221. binder(), String.class, String.class, named("abc"));
  222. abcMapBinder.addBinding("a").toInstance("A");
  223. abcMapBinder.addBinding("b").toInstance("B");
  224. abcMapBinder.addBinding("c").toInstance("C");
  225. MapBinder<String, String> deMapBinder = MapBinder.newMapBinder(
  226. binder(), String.class, String.class, named("de"));
  227. deMapBinder.addBinding("d").toInstance("D");
  228. deMapBinder.addBinding("e").toInstance("E");
  229. }
  230. };
  231. Injector injector = Guice.createInjector(module);
  232. Key<Map<String, String>> abcKey = Key.get(mapOfString, named("abc"));
  233. Map<String, String> abc = injector.getInstance(abcKey);
  234. Key<Map<String, String>> deKey = Key.get(mapOfString, named("de"));
  235. Map<String, String> de = injector.getInstance(deKey);
  236. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
  237. assertEquals(mapOf("d", "D", "e", "E"), de);
  238. assertMapVisitor(abcKey, stringType, stringType, setOf(module), BOTH, false, 1,
  239. instance("a", "A"), instance("b", "B"), instance("c", "C"));
  240. assertMapVisitor(deKey, stringType, stringType, setOf(module), BOTH, false, 1,
  241. instance("d", "D"), instance("e", "E"));
  242. // just make sure these succeed
  243. injector.getInstance(Key.get(mapOfStringProvider, named("abc")));
  244. injector.getInstance(Key.get(mapOfStringJavaxProvider, named("abc")));
  245. injector.getInstance(Key.get(mapOfStringProvider, named("de")));
  246. injector.getInstance(Key.get(mapOfStringJavaxProvider, named("de")));
  247. }
  248. public void testMapBinderWithMultipleAnnotationTypeSets() {
  249. Module module = new AbstractModule() {
  250. @Override protected void configure() {
  251. MapBinder<String, String> abcMapBinder = MapBinder.newMapBinder(
  252. binder(), String.class, String.class, Abc.class);
  253. abcMapBinder.addBinding("a").toInstance("A");
  254. abcMapBinder.addBinding("b").toInstance("B");
  255. abcMapBinder.addBinding("c").toInstance("C");
  256. MapBinder<String, String> deMapBinder = MapBinder.newMapBinder(
  257. binder(), String.class, String.class, De.class);
  258. deMapBinder.addBinding("d").toInstance("D");
  259. deMapBinder.addBinding("e").toInstance("E");
  260. }
  261. };
  262. Injector injector = Guice.createInjector(module);
  263. Key<Map<String, String>> abcKey = Key.get(mapOfString, Abc.class);
  264. Map<String, String> abc = injector.getInstance(abcKey);
  265. Key<Map<String, String>> deKey = Key.get(mapOfString, De.class);
  266. Map<String, String> de = injector.getInstance(deKey);
  267. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
  268. assertEquals(mapOf("d", "D", "e", "E"), de);
  269. assertMapVisitor(abcKey, stringType, stringType, setOf(module), BOTH, false, 1,
  270. instance("a", "A"), instance("b", "B"), instance("c", "C"));
  271. assertMapVisitor(deKey, stringType, stringType, setOf(module), BOTH, false, 1,
  272. instance("d", "D"), instance("e", "E"));
  273. // just make sure these succeed
  274. injector.getInstance(Key.get(mapOfStringProvider, Abc.class));
  275. injector.getInstance(Key.get(mapOfStringJavaxProvider, Abc.class));
  276. injector.getInstance(Key.get(mapOfStringProvider, De.class));
  277. injector.getInstance(Key.get(mapOfStringJavaxProvider, De.class));
  278. }
  279. public void testMapBinderWithMultipleTypes() {
  280. Module module = new AbstractModule() {
  281. @Override protected void configure() {
  282. MapBinder.newMapBinder(binder(), String.class, String.class)
  283. .addBinding("a").toInstance("A");
  284. MapBinder.newMapBinder(binder(), String.class, Integer.class)
  285. .addBinding("1").toInstance(1);
  286. }
  287. };
  288. Injector injector = Guice.createInjector(module);
  289. assertEquals(mapOf("a", "A"), injector.getInstance(Key.get(mapOfString)));
  290. assertEquals(mapOf("1", 1), injector.getInstance(Key.get(mapOfInteger)));
  291. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), BOTH, false, 1,
  292. instance("a", "A"));
  293. assertMapVisitor(Key.get(mapOfInteger), stringType, intType, setOf(module), BOTH, false, 1,
  294. instance("1", 1));
  295. }
  296. public void testMapBinderWithEmptyMap() {
  297. Module module = new AbstractModule() {
  298. @Override protected void configure() {
  299. MapBinder.newMapBinder(binder(), String.class, String.class);
  300. }
  301. };
  302. Injector injector = Guice.createInjector(module);
  303. Map<String, String> map = injector.getInstance(Key.get(mapOfString));
  304. assertEquals(Collections.emptyMap(), map);
  305. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), BOTH, false, 0);
  306. }
  307. public void testMapBinderMapIsUnmodifiable() {
  308. Injector injector = Guice.createInjector(new AbstractModule() {
  309. @Override protected void configure() {
  310. MapBinder.newMapBinder(binder(), String.class, String.class)
  311. .addBinding("a").toInstance("A");
  312. }
  313. });
  314. Map<String, String> map = injector.getInstance(Key.get(mapOfString));
  315. try {
  316. map.clear();
  317. fail();
  318. } catch(UnsupportedOperationException expected) {
  319. }
  320. }
  321. public void testMapBinderMapIsLazy() {
  322. Module module = new AbstractModule() {
  323. @Override protected void configure() {
  324. MapBinder.newMapBinder(binder(), String.class, Integer.class)
  325. .addBinding("num").toProvider(new Provider<Integer>() {
  326. int nextValue = 1;
  327. @Override public Integer get() {
  328. return nextValue++;
  329. }
  330. });
  331. }
  332. };
  333. Injector injector = Guice.createInjector(module);
  334. assertEquals(mapOf("num", 1), injector.getInstance(Key.get(mapOfInteger)));
  335. assertEquals(mapOf("num", 2), injector.getInstance(Key.get(mapOfInteger)));
  336. assertEquals(mapOf("num", 3), injector.getInstance(Key.get(mapOfInteger)));
  337. assertMapVisitor(Key.get(mapOfInteger), stringType, intType, setOf(module), BOTH, false, 0,
  338. providerInstance("num", 1));
  339. }
  340. public void testMapBinderMapForbidsDuplicateKeys() {
  341. Module module = new AbstractModule() {
  342. @Override protected void configure() {
  343. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  344. binder(), String.class, String.class);
  345. multibinder.addBinding("a").toInstance("A");
  346. multibinder.addBinding("a").toInstance("B");
  347. }
  348. };
  349. try {
  350. Guice.createInjector(module);
  351. fail();
  352. } catch(CreationException expected) {
  353. assertContains(expected.getMessage(),
  354. "Map injection failed due to duplicated key \"a\"");
  355. }
  356. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), MODULE, false, 0,
  357. instance("a", "A"), instance("a", "B"));
  358. }
  359. public void testExhaustiveDuplicateErrorMessage() throws Exception {
  360. class Module1 extends AbstractModule {
  361. @Override protected void configure() {
  362. MapBinder<String, Object> mapbinder =
  363. MapBinder.newMapBinder(binder(), String.class, Object.class);
  364. mapbinder.addBinding("a").to(String.class);
  365. }
  366. }
  367. class Module2 extends AbstractModule {
  368. @Override protected void configure() {
  369. MapBinder<String, Object> mapbinder =
  370. MapBinder.newMapBinder(binder(), String.class, Object.class);
  371. mapbinder.addBinding("a").to(Integer.class);
  372. mapbinder.addBinding("b").to(String.class);
  373. }
  374. }
  375. class Module3 extends AbstractModule {
  376. @Override protected void configure() {
  377. MapBinder<String, Object> mapbinder =
  378. MapBinder.newMapBinder(binder(), String.class, Object.class);
  379. mapbinder.addBinding("b").to(Integer.class);
  380. }
  381. }
  382. class Main extends AbstractModule {
  383. @Override protected void configure() {
  384. MapBinder.newMapBinder(binder(), String.class, Object.class);
  385. install(new Module1());
  386. install(new Module2());
  387. install(new Module3());
  388. }
  389. @Provides String provideString() { return "foo"; }
  390. @Provides Integer provideInt() { return 42; }
  391. }
  392. try {
  393. Guice.createInjector(new Main());
  394. fail();
  395. } catch(CreationException ce) {
  396. assertContains(ce.getMessage(),
  397. "Map injection failed due to duplicated key \"a\", from bindings:",
  398. asModuleChain(Main.class, Module1.class),
  399. asModuleChain(Main.class, Module2.class),
  400. "and key: \"b\", from bindings:",
  401. asModuleChain(Main.class, Module2.class),
  402. asModuleChain(Main.class, Module3.class),
  403. "at " + Main.class.getName() + ".configure(",
  404. asModuleChain(Main.class, MapBinder.RealMapBinder.class));
  405. assertEquals(1, ce.getErrorMessages().size());
  406. }
  407. }
  408. public void testMapBinderMapPermitDuplicateElements() {
  409. Module ab = new AbstractModule() {
  410. @Override protected void configure() {
  411. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  412. binder(), String.class, String.class);
  413. multibinder.addBinding("a").toInstance("A");
  414. multibinder.addBinding("b").toInstance("B");
  415. multibinder.permitDuplicates();
  416. }
  417. };
  418. Module bc = new AbstractModule() {
  419. @Override protected void configure() {
  420. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  421. binder(), String.class, String.class);
  422. multibinder.addBinding("b").toInstance("B");
  423. multibinder.addBinding("c").toInstance("C");
  424. multibinder.permitDuplicates();
  425. }
  426. };
  427. Injector injector = Guice.createInjector(ab, bc);
  428. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), injector.getInstance(Key.get(mapOfString)));
  429. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(ab, bc), BOTH, true, 0,
  430. instance("a", "A"), instance("b", "B"), instance("c", "C"));
  431. }
  432. public void testMapBinderMapDoesNotDedupeDuplicateValues() {
  433. class ValueType {
  434. int keyPart;
  435. int dataPart;
  436. private ValueType(int keyPart, int dataPart) {
  437. this.keyPart = keyPart;
  438. this.dataPart = dataPart;
  439. }
  440. @Override
  441. public boolean equals(Object obj) {
  442. return (obj instanceof ValueType) && (keyPart == ((ValueType) obj).keyPart);
  443. }
  444. @Override
  445. public int hashCode() {
  446. return keyPart;
  447. }
  448. }
  449. Module m1 = new AbstractModule() {
  450. @Override protected void configure() {
  451. MapBinder<String, ValueType> multibinder = MapBinder.newMapBinder(
  452. binder(), String.class, ValueType.class);
  453. multibinder.addBinding("a").toInstance(new ValueType(1, 2));
  454. }
  455. };
  456. Module m2 = new AbstractModule() {
  457. @Override protected void configure() {
  458. MapBinder<String, ValueType> multibinder = MapBinder.newMapBinder(
  459. binder(), String.class, ValueType.class);
  460. multibinder.addBinding("b").toInstance(new ValueType(1, 3));
  461. }
  462. };
  463. Injector injector = Guice.createInjector(m1, m2);
  464. Map<String, ValueType> map = injector.getInstance(new Key<Map<String, ValueType>>() {});
  465. assertEquals(2, map.get("a").dataPart);
  466. assertEquals(3, map.get("b").dataPart);
  467. }
  468. public void testMapBinderMultimap() {
  469. AbstractModule ab1c = new AbstractModule() {
  470. @Override protected void configure() {
  471. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  472. binder(), String.class, String.class);
  473. multibinder.addBinding("a").toInstance("A");
  474. multibinder.addBinding("b").toInstance("B1");
  475. multibinder.addBinding("c").toInstance("C");
  476. }
  477. };
  478. AbstractModule b2c = new AbstractModule() {
  479. @Override protected void configure() {
  480. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  481. binder(), String.class, String.class);
  482. multibinder.addBinding("b").toInstance("B2");
  483. multibinder.addBinding("c").toInstance("C");
  484. multibinder.permitDuplicates();
  485. }
  486. };
  487. Injector injector = Guice.createInjector(ab1c, b2c);
  488. assertEquals(mapOf("a", setOf("A"), "b", setOf("B1", "B2"), "c", setOf("C")),
  489. injector.getInstance(Key.get(mapOfSetOfString)));
  490. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(ab1c, b2c), BOTH, true, 0,
  491. instance("a", "A"), instance("b", "B1"), instance("b", "B2"), instance("c", "C"));
  492. }
  493. public void testMapBinderMultimapWithAnotation() {
  494. AbstractModule ab1 = new AbstractModule() {
  495. @Override protected void configure() {
  496. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  497. binder(), String.class, String.class, Abc.class);
  498. multibinder.addBinding("a").toInstance("A");
  499. multibinder.addBinding("b").toInstance("B1");
  500. }
  501. };
  502. AbstractModule b2c = new AbstractModule() {
  503. @Override protected void configure() {
  504. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  505. binder(), String.class, String.class, Abc.class);
  506. multibinder.addBinding("b").toInstance("B2");
  507. multibinder.addBinding("c").toInstance("C");
  508. multibinder.permitDuplicates();
  509. }
  510. };
  511. Injector injector = Guice.createInjector(ab1, b2c);
  512. assertEquals(mapOf("a", setOf("A"), "b", setOf("B1", "B2"), "c", setOf("C")),
  513. injector.getInstance(Key.get(mapOfSetOfString, Abc.class)));
  514. try {
  515. injector.getInstance(Key.get(mapOfSetOfString));
  516. fail();
  517. } catch (ConfigurationException expected) {}
  518. assertMapVisitor(Key.get(mapOfString, Abc.class), stringType, stringType, setOf(ab1, b2c), BOTH, true, 0,
  519. instance("a", "A"), instance("b", "B1"), instance("b", "B2"), instance("c", "C"));
  520. }
  521. public void testMapBinderMultimapIsUnmodifiable() {
  522. Injector injector = Guice.createInjector(new AbstractModule() {
  523. @Override protected void configure() {
  524. MapBinder<String, String> mapBinder = MapBinder.newMapBinder(
  525. binder(), String.class, String.class);
  526. mapBinder.addBinding("a").toInstance("A");
  527. mapBinder.permitDuplicates();
  528. }
  529. });
  530. Map<String, Set<String>> map = injector.getInstance(Key.get(mapOfSetOfString));
  531. try {
  532. map.clear();
  533. fail();
  534. } catch(UnsupportedOperationException expected) {
  535. }
  536. try {
  537. map.get("a").clear();
  538. fail();
  539. } catch(UnsupportedOperationException expected) {
  540. }
  541. }
  542. public void testMapBinderMapForbidsNullKeys() {
  543. try {
  544. Guice.createInjector(new AbstractModule() {
  545. @Override protected void configure() {
  546. MapBinder.newMapBinder(binder(), String.class, String.class).addBinding(null);
  547. }
  548. });
  549. fail();
  550. } catch (CreationException expected) {}
  551. }
  552. public void testMapBinderMapForbidsNullValues() {
  553. Module m = new AbstractModule() {
  554. @Override protected void configure() {
  555. MapBinder.newMapBinder(binder(), String.class, String.class)
  556. .addBinding("null").toProvider(Providers.<String>of(null));
  557. }
  558. };
  559. Injector injector = Guice.createInjector(m);
  560. try {
  561. injector.getInstance(Key.get(mapOfString));
  562. fail();
  563. } catch(ProvisionException expected) {
  564. assertContains(expected.getMessage(),
  565. "1) Map injection failed due to null value for key \"null\", bound at: "
  566. + m.getClass().getName() + ".configure(");
  567. }
  568. }
  569. public void testMapBinderProviderIsScoped() {
  570. final Provider<Integer> counter = new Provider<Integer>() {
  571. int next = 1;
  572. @Override public Integer get() {
  573. return next++;
  574. }
  575. };
  576. Injector injector = Guice.createInjector(new AbstractModule() {
  577. @Override protected void configure() {
  578. MapBinder.newMapBinder(binder(), String.class, Integer.class)
  579. .addBinding("one").toProvider(counter).asEagerSingleton();
  580. }
  581. });
  582. assertEquals(1, (int) injector.getInstance(Key.get(mapOfInteger)).get("one"));
  583. assertEquals(1, (int) injector.getInstance(Key.get(mapOfInteger)).get("one"));
  584. }
  585. public void testSourceLinesInMapBindings() {
  586. try {
  587. Guice.createInjector(new AbstractModule() {
  588. @Override protected void configure() {
  589. MapBinder.newMapBinder(binder(), String.class, Integer.class)
  590. .addBinding("one");
  591. }
  592. });
  593. fail();
  594. } catch (CreationException expected) {
  595. assertContains(expected.getMessage(),
  596. "1) No implementation for java.lang.Integer",
  597. "at " + getClass().getName());
  598. }
  599. }
  600. /** We just want to make sure that mapbinder's binding depends on the underlying multibinder. */
  601. public void testMultibinderDependencies() {
  602. Injector injector = Guice.createInjector(new AbstractModule() {
  603. @Override protected void configure() {
  604. MapBinder<Integer, String> mapBinder
  605. = MapBinder.newMapBinder(binder(), Integer.class, String.class);
  606. mapBinder.addBinding(1).toInstance("A");
  607. mapBinder.addBinding(2).to(Key.get(String.class, Names.named("b")));
  608. bindConstant().annotatedWith(Names.named("b")).to("B");
  609. }
  610. });
  611. Binding<Map<Integer, String>> binding = injector.getBinding(new Key<Map<Integer, String>>() {});
  612. HasDependencies withDependencies = (HasDependencies) binding;
  613. Key<?> setKey = new Key<Set<Map.Entry<Integer, Provider<String>>>>() {};
  614. assertEquals(ImmutableSet.<Dependency<?>>of(Dependency.get(setKey)),
  615. withDependencies.getDependencies());
  616. Set<String> elements = Sets.newHashSet();
  617. elements.addAll(recurseForDependencies(injector, withDependencies));
  618. assertEquals(ImmutableSet.of("A", "B"), elements);
  619. }
  620. private Set<String> recurseForDependencies(Injector injector, HasDependencies hasDependencies) {
  621. Set<String> elements = Sets.newHashSet();
  622. for (Dependency<?> dependency : hasDependencies.getDependencies()) {
  623. Binding<?> binding = injector.getBinding(dependency.getKey());
  624. HasDependencies deps = (HasDependencies) binding;
  625. if (binding instanceof InstanceBinding) {
  626. elements.add((String) ((InstanceBinding<?>) binding).getInstance());
  627. } else {
  628. elements.addAll(recurseForDependencies(injector, deps));
  629. }
  630. }
  631. return elements;
  632. }
  633. /** We just want to make sure that mapbinder's binding depends on the underlying multibinder. */
  634. public void testMultibinderDependenciesInToolStage() {
  635. Injector injector = Guice.createInjector(Stage.TOOL, new AbstractModule() {
  636. @Override protected void configure() {
  637. MapBinder<Integer, String> mapBinder
  638. = MapBinder.newMapBinder(binder(), Integer.class, String.class);
  639. mapBinder.addBinding(1).toInstance("A");
  640. mapBinder.addBinding(2).to(Key.get(String.class, Names.named("b")));
  641. bindConstant().annotatedWith(Names.named("b")).to("B");
  642. }});
  643. Binding<Map<Integer, String>> binding = injector.getBinding(new Key<Map<Integer, String>>() {});
  644. HasDependencies withDependencies = (HasDependencies) binding;
  645. Key<?> setKey = new Key<Set<Map.Entry<Integer, Provider<String>>>>() {};
  646. assertEquals(ImmutableSet.<Dependency<?>>of(Dependency.get(setKey)),
  647. withDependencies.getDependencies());
  648. }
  649. /**
  650. * Our implementation maintains order, but doesn't guarantee it in the API spec.
  651. * TODO: specify the iteration order?
  652. */
  653. public void testBindOrderEqualsIterationOrder() {
  654. Injector injector = Guice.createInjector(
  655. new AbstractModule() {
  656. @Override protected void configure() {
  657. MapBinder<String, String> mapBinder
  658. = MapBinder.newMapBinder(binder(), String.class, String.class);
  659. mapBinder.addBinding("leonardo").toInstance("blue");
  660. mapBinder.addBinding("donatello").toInstance("purple");
  661. install(new AbstractModule() {
  662. @Override protected void configure() {
  663. MapBinder.newMapBinder(binder(), String.class, String.class)
  664. .addBinding("michaelangelo").toInstance("orange");
  665. }
  666. });
  667. }
  668. },
  669. new AbstractModule() {
  670. @Override protected void configure() {
  671. MapBinder.newMapBinder(binder(), String.class, String.class)
  672. .addBinding("raphael").toInstance("red");
  673. }
  674. });
  675. Map<String, String> map = injector.getInstance(new Key<Map<String, String>>() {});
  676. Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
  677. assertEquals(Maps.immutableEntry("leonardo", "blue"), iterator.next());
  678. assertEquals(Maps.immutableEntry("donatello", "purple"), iterator.next());
  679. assertEquals(Maps.immutableEntry("michaelangelo", "orange"), iterator.next());
  680. assertEquals(Maps.immutableEntry("raphael", "red"), iterator.next());
  681. }
  682. /**
  683. * With overrides, we should get the union of all map bindings.
  684. */
  685. public void testModuleOverrideAndMapBindings() {
  686. Module ab = new AbstractModule() {
  687. @Override protected void configure() {
  688. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  689. multibinder.addBinding("a").toInstance("A");
  690. multibinder.addBinding("b").toInstance("B");
  691. }
  692. };
  693. Module cd = new AbstractModule() {
  694. @Override protected void configure() {
  695. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  696. multibinder.addBinding("c").toInstance("C");
  697. multibinder.addBinding("d").toInstance("D");
  698. }
  699. };
  700. Module ef = new AbstractModule() {
  701. @Override protected void configure() {
  702. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  703. multibinder.addBinding("e").toInstance("E");
  704. multibinder.addBinding("f").toInstance("F");
  705. }
  706. };
  707. Module abcd = Modules.override(ab).with(cd);
  708. Injector injector = Guice.createInjector(abcd, ef);
  709. assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E", "f", "F"),
  710. injector.getInstance(Key.get(mapOfString)));
  711. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(abcd, ef), BOTH, false, 0,
  712. instance("a", "A"), instance("b", "B"), instance("c", "C"), instance("d", "D"), instance(
  713. "e", "E"), instance("f", "F"));
  714. }
  715. public void testDeduplicateMapBindings() {
  716. Module module = new AbstractModule() {
  717. @Override protected void configure() {
  718. MapBinder<String, String> mapbinder =
  719. MapBinder.newMapBinder(binder(), String.class, String.class);
  720. mapbinder.addBinding("a").toInstance("A");
  721. mapbinder.addBinding("a").toInstance("A");
  722. mapbinder.addBinding("b").toInstance("B");
  723. mapbinder.addBinding("b").toInstance("B");
  724. }
  725. };
  726. Injector injector = Guice.createInjector(module);
  727. assertEquals(mapOf("a", "A", "b", "B"),
  728. injector.getInstance(Key.get(mapOfString)));
  729. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), BOTH, false, 0,
  730. instance("a", "A"), instance("b", "B"));
  731. }
  732. /**
  733. * With overrides, we should get the union of all map bindings.
  734. */
  735. public void testModuleOverrideAndMapBindingsWithPermitDuplicates() {
  736. Module abc = new AbstractModule() {
  737. @Override protected void configure() {
  738. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  739. multibinder.addBinding("a").toInstance("A");
  740. multibinder.addBinding("b").toInstance("B");
  741. multibinder.addBinding("c").toInstance("C");
  742. multibinder.permitDuplicates();
  743. }
  744. };
  745. Module cd = new AbstractModule() {
  746. @Override protected void configure() {
  747. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  748. multibinder.addBinding("c").toInstance("C");
  749. multibinder.addBinding("d").toInstance("D");
  750. multibinder.permitDuplicates();
  751. }
  752. };
  753. Module ef = new AbstractModule() {
  754. @Override protected void configure() {
  755. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  756. multibinder.addBinding("e").toInstance("E");
  757. multibinder.addBinding("f").toInstance("F");
  758. multibinder.permitDuplicates();
  759. }
  760. };
  761. Module abcd = Modules.override(abc).with(cd);
  762. Injector injector = Guice.createInjector(abcd, ef);
  763. assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E", "f", "F"),
  764. injector.getInstance(Key.get(mapOfString)));
  765. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(abcd, ef), BOTH, true, 0,
  766. instance("a", "A"), instance("b", "B"), instance("c", "C"), instance(
  767. "d", "D"), instance("e", "E"), instance("f", "F"));
  768. }
  769. /** Ensure there are no initialization race conditions in basic map injection. */
  770. public void testBasicMapDependencyInjection() {
  771. final AtomicReference<Map<String, String>> injectedMap =
  772. new AtomicReference<Map<String, String>>();
  773. final Object anObject = new Object() {
  774. @Inject void initialize(Map<String, String> map) {
  775. injectedMap.set(map);
  776. }
  777. };
  778. Module abc = new AbstractModule() {
  779. @Override protected void configure() {
  780. requestInjection(anObject);
  781. MapBinder<String, String> multibinder =
  782. MapBinder.newMapBinder(binder(), String.class, String.class);
  783. multibinder.addBinding("a").toInstance("A");
  784. multibinder.addBinding("b").toInstance("B");
  785. multibinder.addBinding("c").toInstance("C");
  786. }
  787. };
  788. Guice.createInjector(abc);
  789. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), injectedMap.get());
  790. }
  791. /** Ensure there are no initialization race conditions in provider multimap injection. */
  792. public void testProviderMultimapDependencyInjection() {
  793. final AtomicReference<Map<String, Set<Provider<String>>>> injectedMultimap =
  794. new AtomicReference<Map<String, Set<Provider<String>>>>();
  795. final Object anObject = new Object() {
  796. @Inject void initialize(Map<String, Set<Provider<String>>> multimap) {
  797. injectedMultimap.set(multimap);
  798. }
  799. };
  800. Module abc = new AbstractModule() {
  801. @Override protected void configure() {
  802. requestInjection(anObject);
  803. MapBinder<String, String> multibinder =
  804. MapBinder.newMapBinder(binder(), String.class, String.class);
  805. multibinder.permitDuplicates();
  806. multibinder.addBinding("a").toInstance("A");
  807. multibinder.addBinding("b").toInstance("B");
  808. multibinder.addBinding("c").toInstance("C");
  809. }
  810. };
  811. Guice.createInjector(abc);
  812. Map<String, String> map = Maps.transformValues(injectedMultimap.get(),
  813. new Function<Set<Provider<String>>, String>() {
  814. @Override public String apply(Set<Provider<String>> stringProvidersSet) {
  815. return Iterables.getOnlyElement(stringProvidersSet).get();
  816. }
  817. });
  818. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), map);
  819. }
  820. @Retention(RUNTIME) @BindingAnnotation
  821. @interface Abc {}
  822. @Retention(RUNTIME) @BindingAnnotation
  823. @interface De {}
  824. @SuppressWarnings("unchecked")
  825. private <K, V> Map<K, V> mapOf(Object... elements) {
  826. Map<K, V> result = new HashMap<K, V>();
  827. for (int i = 0; i < elements.length; i += 2) {
  828. result.put((K)elements[i], (V)elements[i+1]);
  829. }
  830. return result;
  831. }
  832. @SuppressWarnings("unchecked")
  833. private <V> Set<V> setOf(V... elements) {
  834. return new HashSet<V>(Arrays.asList(elements));
  835. }
  836. @BindingAnnotation
  837. @Retention(RetentionPolicy.RUNTIME)
  838. @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
  839. private static @interface Marker {}
  840. @Marker
  841. public void testMapBinderMatching() throws Exception {
  842. Method m = MapBinderTest.class.getDeclaredMethod("testMapBinderMatching");
  843. assertNotNull(m);
  844. final Annotation marker = m.getAnnotation(Marker.class);
  845. Injector injector = Guice.createInjector(new AbstractModule() {
  846. @Override public void configure() {
  847. MapBinder<Integer, Integer> mb1 =
  848. MapBinder.newMapBinder(binder(), Integer.class, Integer.class, Marker.class);
  849. MapBinder<Integer, Integer> mb2 =
  850. MapBinder.newMapBinder(binder(), Integer.class, Integer.class, marker);
  851. mb1.addBinding(1).toInstance(1);
  852. mb2.addBinding(2).toInstance(2);
  853. // This assures us that the two binders are equivalent, so we expect the instance added to
  854. // each to have been added to one set.
  855. assertEquals(mb1, mb2);
  856. }
  857. });
  858. TypeLiteral<Map<Integer, Integer>> t = new TypeLiteral<Map<Integer, Integer>>() {};
  859. Map<Integer, Integer> s1 = injector.getInstance(Key.get(t, Marker.class));
  860. Map<Integer, Integer> s2 = injector.getInstance(Key.get(t, marker));
  861. // This assures us that the two sets are in fact equal. They may not be same set (as in Java
  862. // object identical), but we shouldn't expect that, since probably Guice creates the set each
  863. // time in case the elements are dependent on scope.
  864. assertEquals(s1, s2);
  865. // This ensures that MultiBinder is internally using the correct set name --
  866. // making sure that instances of marker annotations have the same set name as
  867. // MarkerAnnotation.class.
  868. Map<Integer, Integer> expected = new HashMap<Integer, Integer>();
  869. expected.put(1, 1);
  870. expected.put(2, 2);
  871. assertEquals(expected, s1);
  872. }
  873. public void testTwoMapBindersAreDistinct() {
  874. Injector injector = Guice.createInjector(new AbstractModule() {
  875. @Override protected void configure() {
  876. MapBinder.newMapBinder(binder(), String.class, String.class)
  877. .addBinding("A").toInstance("a");
  878. MapBinder.newMapBinder(binder(), Integer.class, String.class)
  879. .addBinding(1).toInstance("b");
  880. }
  881. });
  882. Collector collector = new Collector();
  883. Binding<Map<String, String>> map1 = injector.getBinding(Key.get(mapOfString));
  884. map1.acceptTargetVisitor(collector);
  885. assertNotNull(collector.mapbinding);
  886. MapBinderBinding<?> map1Binding = collector.mapbinding;
  887. Binding<Map<Integer, String>> map2 = injector.getBinding(Key.get(mapOfIntString));
  888. map2.acceptTargetVisitor(collector);
  889. assertNotNull(collector.mapbinding);
  890. MapBinderBinding<?> map2Binding = collector.mapbinding;
  891. List<Binding<String>> bindings = injector.findBindingsByType(stringType);
  892. assertEquals("should have two elements: " + bindings, 2, bindings.size());
  893. Binding<String> a = bindings.get(0);
  894. Binding<String> b = bindings.get(1);
  895. assertEquals("a", ((InstanceBinding<String>) a).getInstance());
  896. assertEquals("b", ((InstanceBinding<String>) b).getInstance());
  897. // Make sure the correct elements belong to their own sets.
  898. assertTrue(map1Binding.containsElement(a));
  899. assertFalse(map1Binding.containsElement(b));
  900. assertFalse(map2Binding.containsElement(a));
  901. assertTrue(map2Binding.containsElement(b));
  902. }
  903. // Tests for com.google.inject.internal.WeakKeySet not leaking memory.
  904. public void testWeakKeySet_integration_mapbinder() {
  905. Key<Map<String, String>> mapKey = Key.get(new TypeLiteral<Map<String, String>>() {});
  906. Injector parentInjector = Guice.createInjector(new AbstractModule() {
  907. @Override protected void configure() {
  908. bind(String.class).toInstance("hi");
  909. }
  910. });
  911. WeakKeySetUtils.assertNotBlacklisted(parentInjector, mapKey);
  912. Injector childInjector = parentInjector.createChildInjector(new AbstractModule() {
  913. @Override protected void configure() {
  914. MapBinder<String, String> binder =
  915. MapBinder.newMapBinder(binder(), String.class, String.class);
  916. binder.addBinding("bar").toInstance("foo");
  917. }
  918. });
  919. WeakReference<Injector> weakRef = new WeakReference<Injector>(childInjector);
  920. WeakKeySetUtils.assertBlacklisted(parentInjector, mapKey);
  921. // Clear the ref, GC, and ensure that we are no longer blacklisting.
  922. childInjector = null;
  923. Asserts.awaitClear(weakRef);
  924. WeakKeySetUtils.assertNotBlacklisted(parentInjector, mapKey);
  925. }
  926. }