PageRenderTime 494ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/guice-3.0-rc2-src/extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java

#
Java | 678 lines | 568 code | 72 blank | 38 comment | 1 complexity | 620f22f8846805c378647c54d8cca993 MD5 | raw file
Possible License(s): Apache-2.0
  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.assertContains;
  18. import static com.google.inject.multibindings.SpiUtils.assertMapVisitor;
  19. import static com.google.inject.multibindings.SpiUtils.instance;
  20. import static com.google.inject.multibindings.SpiUtils.providerInstance;
  21. import static com.google.inject.multibindings.SpiUtils.VisitType.BOTH;
  22. import static com.google.inject.multibindings.SpiUtils.VisitType.MODULE;
  23. import static com.google.inject.name.Names.named;
  24. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  25. import com.google.inject.AbstractModule;
  26. import com.google.inject.Binding;
  27. import com.google.inject.BindingAnnotation;
  28. import com.google.inject.ConfigurationException;
  29. import com.google.inject.CreationException;
  30. import com.google.inject.Guice;
  31. import com.google.inject.Injector;
  32. import com.google.inject.Key;
  33. import com.google.inject.Module;
  34. import com.google.inject.Provider;
  35. import com.google.inject.ProvisionException;
  36. import com.google.inject.Stage;
  37. import com.google.inject.TypeLiteral;
  38. import com.google.inject.internal.util.ImmutableSet;
  39. import com.google.inject.internal.util.Maps;
  40. import com.google.inject.name.Names;
  41. import com.google.inject.spi.Dependency;
  42. import com.google.inject.spi.HasDependencies;
  43. import com.google.inject.util.Modules;
  44. import com.google.inject.util.Providers;
  45. import junit.framework.TestCase;
  46. import java.lang.annotation.Annotation;
  47. import java.lang.annotation.ElementType;
  48. import java.lang.annotation.Retention;
  49. import java.lang.annotation.RetentionPolicy;
  50. import java.lang.annotation.Target;
  51. import java.lang.reflect.Method;
  52. import java.util.Arrays;
  53. import java.util.Collections;
  54. import java.util.HashMap;
  55. import java.util.HashSet;
  56. import java.util.Iterator;
  57. import java.util.Map;
  58. import java.util.Set;
  59. /**
  60. * @author dpb@google.com (David P. Baker)
  61. */
  62. public class MapBinderTest extends TestCase {
  63. final TypeLiteral<Map<String, String>> mapOfString = new TypeLiteral<Map<String, String>>() {};
  64. final TypeLiteral<Map<String, Integer>> mapOfInteger = new TypeLiteral<Map<String, Integer>>() {};
  65. final TypeLiteral<Map<String, Set<String>>> mapOfSetOfString =
  66. new TypeLiteral<Map<String, Set<String>>>() {};
  67. private final TypeLiteral<String> stringType = TypeLiteral.get(String.class);
  68. private final TypeLiteral<Integer> intType = TypeLiteral.get(Integer.class);
  69. private final TypeLiteral<Set<String>> stringSetType = new TypeLiteral<Set<String>>() {};
  70. public void testMapBinderAggregatesMultipleModules() {
  71. Module abc = new AbstractModule() {
  72. @Override protected void configure() {
  73. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  74. binder(), String.class, String.class);
  75. multibinder.addBinding("a").toInstance("A");
  76. multibinder.addBinding("b").toInstance("B");
  77. multibinder.addBinding("c").toInstance("C");
  78. }
  79. };
  80. Module de = new AbstractModule() {
  81. @Override protected void configure() {
  82. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  83. binder(), String.class, String.class);
  84. multibinder.addBinding("d").toInstance("D");
  85. multibinder.addBinding("e").toInstance("E");
  86. }
  87. };
  88. Injector injector = Guice.createInjector(abc, de);
  89. Map<String, String> abcde = injector.getInstance(Key.get(mapOfString));
  90. assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E"), abcde);
  91. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(abc, de), BOTH, false, 0,
  92. instance("a", "A"), instance("b", "B"), instance("c", "C"), instance("d", "D"), instance("e", "E"));
  93. }
  94. public void testMapBinderAggregationForAnnotationInstance() {
  95. Module module = new AbstractModule() {
  96. @Override protected void configure() {
  97. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  98. binder(), String.class, String.class, Names.named("abc"));
  99. multibinder.addBinding("a").toInstance("A");
  100. multibinder.addBinding("b").toInstance("B");
  101. multibinder = MapBinder.newMapBinder(
  102. binder(), String.class, String.class, Names.named("abc"));
  103. multibinder.addBinding("c").toInstance("C");
  104. }
  105. };
  106. Injector injector = Guice.createInjector(module);
  107. Key<Map<String, String>> key = Key.get(mapOfString, Names.named("abc"));
  108. Map<String, String> abc = injector.getInstance(key);
  109. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
  110. assertMapVisitor(key, stringType, stringType, setOf(module), BOTH, false, 0,
  111. instance("a", "A"), instance("b", "B"), instance("c", "C"));
  112. }
  113. public void testMapBinderAggregationForAnnotationType() {
  114. Module module = new AbstractModule() {
  115. @Override protected void configure() {
  116. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  117. binder(), String.class, String.class, Abc.class);
  118. multibinder.addBinding("a").toInstance("A");
  119. multibinder.addBinding("b").toInstance("B");
  120. multibinder = MapBinder.newMapBinder(
  121. binder(), String.class, String.class, Abc.class);
  122. multibinder.addBinding("c").toInstance("C");
  123. }
  124. };
  125. Injector injector = Guice.createInjector(module);
  126. Key<Map<String, String>> key = Key.get(mapOfString, Abc.class);
  127. Map<String, String> abc = injector.getInstance(key);
  128. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
  129. assertMapVisitor(key, stringType, stringType, setOf(module), BOTH, false, 0,
  130. instance("a", "A"), instance("b", "B"), instance("c", "C"));
  131. }
  132. public void testMapBinderWithMultipleAnnotationValueSets() {
  133. Module module = new AbstractModule() {
  134. @Override protected void configure() {
  135. MapBinder<String, String> abcMapBinder = MapBinder.newMapBinder(
  136. binder(), String.class, String.class, named("abc"));
  137. abcMapBinder.addBinding("a").toInstance("A");
  138. abcMapBinder.addBinding("b").toInstance("B");
  139. abcMapBinder.addBinding("c").toInstance("C");
  140. MapBinder<String, String> deMapBinder = MapBinder.newMapBinder(
  141. binder(), String.class, String.class, named("de"));
  142. deMapBinder.addBinding("d").toInstance("D");
  143. deMapBinder.addBinding("e").toInstance("E");
  144. }
  145. };
  146. Injector injector = Guice.createInjector(module);
  147. Key<Map<String, String>> abcKey = Key.get(mapOfString, named("abc"));
  148. Map<String, String> abc = injector.getInstance(abcKey);
  149. Key<Map<String, String>> deKey = Key.get(mapOfString, named("de"));
  150. Map<String, String> de = injector.getInstance(deKey);
  151. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
  152. assertEquals(mapOf("d", "D", "e", "E"), de);
  153. assertMapVisitor(abcKey, stringType, stringType, setOf(module), BOTH, false, 1,
  154. instance("a", "A"), instance("b", "B"), instance("c", "C"));
  155. assertMapVisitor(deKey, stringType, stringType, setOf(module), BOTH, false, 1,
  156. instance("d", "D"), instance("e", "E"));
  157. }
  158. public void testMapBinderWithMultipleAnnotationTypeSets() {
  159. Module module = new AbstractModule() {
  160. @Override protected void configure() {
  161. MapBinder<String, String> abcMapBinder = MapBinder.newMapBinder(
  162. binder(), String.class, String.class, Abc.class);
  163. abcMapBinder.addBinding("a").toInstance("A");
  164. abcMapBinder.addBinding("b").toInstance("B");
  165. abcMapBinder.addBinding("c").toInstance("C");
  166. MapBinder<String, String> deMapBinder = MapBinder.newMapBinder(
  167. binder(), String.class, String.class, De.class);
  168. deMapBinder.addBinding("d").toInstance("D");
  169. deMapBinder.addBinding("e").toInstance("E");
  170. }
  171. };
  172. Injector injector = Guice.createInjector(module);
  173. Key<Map<String, String>> abcKey = Key.get(mapOfString, Abc.class);
  174. Map<String, String> abc = injector.getInstance(abcKey);
  175. Key<Map<String, String>> deKey = Key.get(mapOfString, De.class);
  176. Map<String, String> de = injector.getInstance(deKey);
  177. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
  178. assertEquals(mapOf("d", "D", "e", "E"), de);
  179. assertMapVisitor(abcKey, stringType, stringType, setOf(module), BOTH, false, 1,
  180. instance("a", "A"), instance("b", "B"), instance("c", "C"));
  181. assertMapVisitor(deKey, stringType, stringType, setOf(module), BOTH, false, 1,
  182. instance("d", "D"), instance("e", "E"));
  183. }
  184. public void testMapBinderWithMultipleTypes() {
  185. Module module = new AbstractModule() {
  186. @Override protected void configure() {
  187. MapBinder.newMapBinder(binder(), String.class, String.class)
  188. .addBinding("a").toInstance("A");
  189. MapBinder.newMapBinder(binder(), String.class, Integer.class)
  190. .addBinding("1").toInstance(1);
  191. }
  192. };
  193. Injector injector = Guice.createInjector(module);
  194. assertEquals(mapOf("a", "A"), injector.getInstance(Key.get(mapOfString)));
  195. assertEquals(mapOf("1", 1), injector.getInstance(Key.get(mapOfInteger)));
  196. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), BOTH, false, 1,
  197. instance("a", "A"));
  198. assertMapVisitor(Key.get(mapOfInteger), stringType, intType, setOf(module), BOTH, false, 1,
  199. instance("1", 1));
  200. }
  201. public void testMapBinderWithEmptyMap() {
  202. Module module = new AbstractModule() {
  203. @Override protected void configure() {
  204. MapBinder.newMapBinder(binder(), String.class, String.class);
  205. }
  206. };
  207. Injector injector = Guice.createInjector(module);
  208. Map<String, String> map = injector.getInstance(Key.get(mapOfString));
  209. assertEquals(Collections.emptyMap(), map);
  210. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), BOTH, false, 0);
  211. }
  212. public void testMapBinderMapIsUnmodifiable() {
  213. Injector injector = Guice.createInjector(new AbstractModule() {
  214. @Override protected void configure() {
  215. MapBinder.newMapBinder(binder(), String.class, String.class)
  216. .addBinding("a").toInstance("A");
  217. }
  218. });
  219. Map<String, String> map = injector.getInstance(Key.get(mapOfString));
  220. try {
  221. map.clear();
  222. fail();
  223. } catch(UnsupportedOperationException expected) {
  224. }
  225. }
  226. public void testMapBinderMapIsLazy() {
  227. Module module = new AbstractModule() {
  228. @Override protected void configure() {
  229. MapBinder.newMapBinder(binder(), String.class, Integer.class)
  230. .addBinding("num").toProvider(new Provider<Integer>() {
  231. int nextValue = 1;
  232. public Integer get() {
  233. return nextValue++;
  234. }
  235. });
  236. }
  237. };
  238. Injector injector = Guice.createInjector(module);
  239. assertEquals(mapOf("num", 1), injector.getInstance(Key.get(mapOfInteger)));
  240. assertEquals(mapOf("num", 2), injector.getInstance(Key.get(mapOfInteger)));
  241. assertEquals(mapOf("num", 3), injector.getInstance(Key.get(mapOfInteger)));
  242. assertMapVisitor(Key.get(mapOfInteger), stringType, intType, setOf(module), BOTH, false, 0,
  243. providerInstance("num", 1));
  244. }
  245. public void testMapBinderMapForbidsDuplicateKeys() {
  246. Module module = new AbstractModule() {
  247. @Override protected void configure() {
  248. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  249. binder(), String.class, String.class);
  250. multibinder.addBinding("a").toInstance("A");
  251. multibinder.addBinding("a").toInstance("B");
  252. }
  253. };
  254. try {
  255. Guice.createInjector(module);
  256. fail();
  257. } catch(CreationException expected) {
  258. assertContains(expected.getMessage(),
  259. "Map injection failed due to duplicated key \"a\"");
  260. }
  261. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), MODULE, false, 0,
  262. instance("a", "A"), instance("a", "B"));
  263. }
  264. public void testMapBinderMapPermitDuplicateElements() {
  265. Module ab = new AbstractModule() {
  266. @Override protected void configure() {
  267. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  268. binder(), String.class, String.class);
  269. multibinder.addBinding("a").toInstance("A");
  270. multibinder.addBinding("b").toInstance("B");
  271. }
  272. };
  273. Module bc = new AbstractModule() {
  274. @Override protected void configure() {
  275. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  276. binder(), String.class, String.class);
  277. multibinder.addBinding("b").toInstance("B");
  278. multibinder.addBinding("c").toInstance("C");
  279. multibinder.permitDuplicates();
  280. }
  281. };
  282. Injector injector = Guice.createInjector(ab, bc);
  283. assertEquals(mapOf("a", "A", "b", "B", "c", "C"), injector.getInstance(Key.get(mapOfString)));
  284. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(ab, bc), BOTH, true, 0,
  285. instance("a", "A"), instance("b", "B"), instance("b", "B"), instance("c", "C"));
  286. }
  287. public void testMapBinderMultimap() {
  288. AbstractModule ab1c = new AbstractModule() {
  289. @Override protected void configure() {
  290. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  291. binder(), String.class, String.class);
  292. multibinder.addBinding("a").toInstance("A");
  293. multibinder.addBinding("b").toInstance("B1");
  294. multibinder.addBinding("c").toInstance("C");
  295. }
  296. };
  297. AbstractModule b2c = new AbstractModule() {
  298. @Override protected void configure() {
  299. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  300. binder(), String.class, String.class);
  301. multibinder.addBinding("b").toInstance("B2");
  302. multibinder.addBinding("c").toInstance("C");
  303. multibinder.permitDuplicates();
  304. }
  305. };
  306. Injector injector = Guice.createInjector(ab1c, b2c);
  307. assertEquals(mapOf("a", setOf("A"), "b", setOf("B1", "B2"), "c", setOf("C")),
  308. injector.getInstance(Key.get(mapOfSetOfString)));
  309. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(ab1c, b2c), BOTH, true, 0,
  310. instance("a", "A"), instance("b", "B1"), instance("b", "B2"), instance("c", "C"), instance("c", "C"));
  311. }
  312. public void testMapBinderMultimapWithAnotation() {
  313. AbstractModule ab1 = new AbstractModule() {
  314. @Override protected void configure() {
  315. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  316. binder(), String.class, String.class, Abc.class);
  317. multibinder.addBinding("a").toInstance("A");
  318. multibinder.addBinding("b").toInstance("B1");
  319. }
  320. };
  321. AbstractModule b2c = new AbstractModule() {
  322. @Override protected void configure() {
  323. MapBinder<String, String> multibinder = MapBinder.newMapBinder(
  324. binder(), String.class, String.class, Abc.class);
  325. multibinder.addBinding("b").toInstance("B2");
  326. multibinder.addBinding("c").toInstance("C");
  327. multibinder.permitDuplicates();
  328. }
  329. };
  330. Injector injector = Guice.createInjector(ab1, b2c);
  331. assertEquals(mapOf("a", setOf("A"), "b", setOf("B1", "B2"), "c", setOf("C")),
  332. injector.getInstance(Key.get(mapOfSetOfString, Abc.class)));
  333. try {
  334. injector.getInstance(Key.get(mapOfSetOfString));
  335. fail();
  336. } catch (ConfigurationException expected) {}
  337. assertMapVisitor(Key.get(mapOfString, Abc.class), stringType, stringType, setOf(ab1, b2c), BOTH, true, 0,
  338. instance("a", "A"), instance("b", "B1"), instance("b", "B2"), instance("c", "C"));
  339. }
  340. public void testMapBinderMultimapIsUnmodifiable() {
  341. Injector injector = Guice.createInjector(new AbstractModule() {
  342. @Override protected void configure() {
  343. MapBinder<String, String> mapBinder = MapBinder.newMapBinder(
  344. binder(), String.class, String.class);
  345. mapBinder.addBinding("a").toInstance("A");
  346. mapBinder.permitDuplicates();
  347. }
  348. });
  349. Map<String, Set<String>> map = injector.getInstance(Key.get(mapOfSetOfString));
  350. try {
  351. map.clear();
  352. fail();
  353. } catch(UnsupportedOperationException expected) {
  354. }
  355. try {
  356. map.get("a").clear();
  357. fail();
  358. } catch(UnsupportedOperationException expected) {
  359. }
  360. }
  361. public void testMapBinderMapForbidsNullKeys() {
  362. try {
  363. Guice.createInjector(new AbstractModule() {
  364. @Override protected void configure() {
  365. MapBinder.newMapBinder(binder(), String.class, String.class).addBinding(null);
  366. }
  367. });
  368. fail();
  369. } catch (CreationException expected) {}
  370. }
  371. public void testMapBinderMapForbidsNullValues() {
  372. Injector injector = Guice.createInjector(new AbstractModule() {
  373. @Override protected void configure() {
  374. MapBinder.newMapBinder(binder(), String.class, String.class)
  375. .addBinding("null").toProvider(Providers.<String>of(null));
  376. }
  377. });
  378. try {
  379. injector.getInstance(Key.get(mapOfString));
  380. fail();
  381. } catch(ProvisionException expected) {
  382. assertContains(expected.getMessage(),
  383. "1) Map injection failed due to null value for key \"null\"");
  384. }
  385. }
  386. public void testMapBinderProviderIsScoped() {
  387. final Provider<Integer> counter = new Provider<Integer>() {
  388. int next = 1;
  389. public Integer get() {
  390. return next++;
  391. }
  392. };
  393. Injector injector = Guice.createInjector(new AbstractModule() {
  394. @Override protected void configure() {
  395. MapBinder.newMapBinder(binder(), String.class, Integer.class)
  396. .addBinding("one").toProvider(counter).asEagerSingleton();
  397. }
  398. });
  399. assertEquals(1, (int) injector.getInstance(Key.get(mapOfInteger)).get("one"));
  400. assertEquals(1, (int) injector.getInstance(Key.get(mapOfInteger)).get("one"));
  401. }
  402. public void testSourceLinesInMapBindings() {
  403. try {
  404. Guice.createInjector(new AbstractModule() {
  405. @Override protected void configure() {
  406. MapBinder.newMapBinder(binder(), String.class, Integer.class)
  407. .addBinding("one");
  408. }
  409. });
  410. fail();
  411. } catch (CreationException expected) {
  412. assertContains(expected.getMessage(),
  413. "1) No implementation for java.lang.Integer",
  414. "at " + getClass().getName());
  415. }
  416. }
  417. /** We just want to make sure that mapbinder's binding depends on the underlying multibinder. */
  418. public void testMultibinderDependencies() {
  419. Injector injector = Guice.createInjector(new AbstractModule() {
  420. protected void configure() {
  421. MapBinder<Integer, String> mapBinder
  422. = MapBinder.newMapBinder(binder(), Integer.class, String.class);
  423. mapBinder.addBinding(1).toInstance("A");
  424. mapBinder.addBinding(2).to(Key.get(String.class, Names.named("b")));
  425. bindConstant().annotatedWith(Names.named("b")).to("B");
  426. }
  427. });
  428. Binding<Map<Integer, String>> binding = injector.getBinding(new Key<Map<Integer, String>>() {});
  429. HasDependencies withDependencies = (HasDependencies) binding;
  430. Key<?> setKey = new Key<Set<Map.Entry<Integer, Provider<String>>>>() {};
  431. assertEquals(ImmutableSet.<Dependency<?>>of(Dependency.get(setKey)),
  432. withDependencies.getDependencies());
  433. }
  434. /** We just want to make sure that mapbinder's binding depends on the underlying multibinder. */
  435. public void testMultibinderDependenciesInToolStage() {
  436. Injector injector = Guice.createInjector(Stage.TOOL, new AbstractModule() {
  437. protected void configure() {
  438. MapBinder<Integer, String> mapBinder
  439. = MapBinder.newMapBinder(binder(), Integer.class, String.class);
  440. mapBinder.addBinding(1).toInstance("A");
  441. mapBinder.addBinding(2).to(Key.get(String.class, Names.named("b")));
  442. bindConstant().annotatedWith(Names.named("b")).to("B");
  443. }});
  444. Binding<Map<Integer, String>> binding = injector.getBinding(new Key<Map<Integer, String>>() {});
  445. HasDependencies withDependencies = (HasDependencies) binding;
  446. Key<?> setKey = new Key<Set<Map.Entry<Integer, Provider<String>>>>() {};
  447. assertEquals(ImmutableSet.<Dependency<?>>of(Dependency.get(setKey)),
  448. withDependencies.getDependencies());
  449. }
  450. /**
  451. * Our implementation maintains order, but doesn't guarantee it in the API spec.
  452. * TODO: specify the iteration order?
  453. */
  454. public void testBindOrderEqualsIterationOrder() {
  455. Injector injector = Guice.createInjector(
  456. new AbstractModule() {
  457. protected void configure() {
  458. MapBinder<String, String> mapBinder
  459. = MapBinder.newMapBinder(binder(), String.class, String.class);
  460. mapBinder.addBinding("leonardo").toInstance("blue");
  461. mapBinder.addBinding("donatello").toInstance("purple");
  462. install(new AbstractModule() {
  463. protected void configure() {
  464. MapBinder.newMapBinder(binder(), String.class, String.class)
  465. .addBinding("michaelangelo").toInstance("orange");
  466. }
  467. });
  468. }
  469. },
  470. new AbstractModule() {
  471. protected void configure() {
  472. MapBinder.newMapBinder(binder(), String.class, String.class)
  473. .addBinding("raphael").toInstance("red");
  474. }
  475. });
  476. Map<String, String> map = injector.getInstance(new Key<Map<String, String>>() {});
  477. Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
  478. assertEquals(Maps.immutableEntry("leonardo", "blue"), iterator.next());
  479. assertEquals(Maps.immutableEntry("donatello", "purple"), iterator.next());
  480. assertEquals(Maps.immutableEntry("michaelangelo", "orange"), iterator.next());
  481. assertEquals(Maps.immutableEntry("raphael", "red"), iterator.next());
  482. }
  483. /**
  484. * With overrides, we should get the union of all map bindings.
  485. */
  486. public void testModuleOverrideAndMapBindings() {
  487. Module ab = new AbstractModule() {
  488. protected void configure() {
  489. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  490. multibinder.addBinding("a").toInstance("A");
  491. multibinder.addBinding("b").toInstance("B");
  492. }
  493. };
  494. Module cd = new AbstractModule() {
  495. protected void configure() {
  496. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  497. multibinder.addBinding("c").toInstance("C");
  498. multibinder.addBinding("d").toInstance("D");
  499. }
  500. };
  501. Module ef = new AbstractModule() {
  502. protected void configure() {
  503. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  504. multibinder.addBinding("e").toInstance("E");
  505. multibinder.addBinding("f").toInstance("F");
  506. }
  507. };
  508. Module abcd = Modules.override(ab).with(cd);
  509. Injector injector = Guice.createInjector(abcd, ef);
  510. assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E", "f", "F"),
  511. injector.getInstance(Key.get(mapOfString)));
  512. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(abcd, ef), BOTH, false, 0,
  513. instance("a", "A"), instance("b", "B"), instance("c", "C"), instance("d", "D"), instance(
  514. "e", "E"), instance("f", "F"));
  515. }
  516. /**
  517. * With overrides, we should get the union of all map bindings.
  518. */
  519. public void testModuleOverrideAndMapBindingsWithPermitDuplicates() {
  520. Module abc = new AbstractModule() {
  521. protected void configure() {
  522. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  523. multibinder.addBinding("a").toInstance("A");
  524. multibinder.addBinding("b").toInstance("B");
  525. multibinder.addBinding("c").toInstance("C");
  526. multibinder.permitDuplicates();
  527. }
  528. };
  529. Module cd = new AbstractModule() {
  530. protected void configure() {
  531. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  532. multibinder.addBinding("c").toInstance("C");
  533. multibinder.addBinding("d").toInstance("D");
  534. multibinder.permitDuplicates();
  535. }
  536. };
  537. Module ef = new AbstractModule() {
  538. protected void configure() {
  539. MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
  540. multibinder.addBinding("e").toInstance("E");
  541. multibinder.addBinding("f").toInstance("F");
  542. multibinder.permitDuplicates();
  543. }
  544. };
  545. Module abcd = Modules.override(abc).with(cd);
  546. Injector injector = Guice.createInjector(abcd, ef);
  547. assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E", "f", "F"),
  548. injector.getInstance(Key.get(mapOfString)));
  549. assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(abcd, ef), BOTH, true, 0,
  550. instance("a", "A"), instance("b", "B"), instance("c", "C"), instance("c", "C"), instance(
  551. "d", "D"), instance("e", "E"), instance("f", "F"));
  552. }
  553. @Retention(RUNTIME) @BindingAnnotation
  554. @interface Abc {}
  555. @Retention(RUNTIME) @BindingAnnotation
  556. @interface De {}
  557. @SuppressWarnings("unchecked")
  558. private <K, V> Map<K, V> mapOf(Object... elements) {
  559. Map<K, V> result = new HashMap<K, V>();
  560. for (int i = 0; i < elements.length; i += 2) {
  561. result.put((K)elements[i], (V)elements[i+1]);
  562. }
  563. return result;
  564. }
  565. @SuppressWarnings("unchecked")
  566. private <V> Set<V> setOf(V... elements) {
  567. return new HashSet(Arrays.asList(elements));
  568. }
  569. @BindingAnnotation
  570. @Retention(RetentionPolicy.RUNTIME)
  571. @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
  572. private static @interface Marker {}
  573. @Marker
  574. public void testMapBinderMatching() throws Exception {
  575. Method m = MapBinderTest.class.getDeclaredMethod("testMapBinderMatching");
  576. assertNotNull(m);
  577. final Annotation marker = m.getAnnotation(Marker.class);
  578. Injector injector = Guice.createInjector(new AbstractModule() {
  579. @Override public void configure() {
  580. MapBinder<Integer, Integer> mb1 =
  581. MapBinder.newMapBinder(binder(), Integer.class, Integer.class, Marker.class);
  582. MapBinder<Integer, Integer> mb2 =
  583. MapBinder.newMapBinder(binder(), Integer.class, Integer.class, marker);
  584. mb1.addBinding(1).toInstance(1);
  585. mb2.addBinding(2).toInstance(2);
  586. // This assures us that the two binders are equivalent, so we expect the instance added to
  587. // each to have been added to one set.
  588. assertEquals(mb1, mb2);
  589. }
  590. });
  591. TypeLiteral<Map<Integer, Integer>> t = new TypeLiteral<Map<Integer, Integer>>() {};
  592. Map<Integer, Integer> s1 = injector.getInstance(Key.get(t, Marker.class));
  593. Map<Integer, Integer> s2 = injector.getInstance(Key.get(t, marker));
  594. // This assures us that the two sets are in fact equal. They may not be same set (as in Java
  595. // object identical), but we shouldn't expect that, since probably Guice creates the set each
  596. // time in case the elements are dependent on scope.
  597. assertEquals(s1, s2);
  598. // This ensures that MultiBinder is internally using the correct set name --
  599. // making sure that instances of marker annotations have the same set name as
  600. // MarkerAnnotation.class.
  601. Map<Integer, Integer> expected = new HashMap<Integer, Integer>();
  602. expected.put(1, 1);
  603. expected.put(2, 2);
  604. assertEquals(expected, s1);
  605. }
  606. }