PageRenderTime 47ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://gitlab.com/metamorphiccode/guice
Java | 373 lines | 298 code | 55 blank | 20 comment | 2 complexity | e40e15868bd759d67810995fe6d4460f MD5 | raw file
  1. /**
  2. * Copyright (C) 2015 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.name.Names.named;
  19. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  20. import com.google.common.base.Optional;
  21. import com.google.common.collect.ImmutableMap;
  22. import com.google.common.collect.ImmutableSet;
  23. import com.google.inject.AbstractModule;
  24. import com.google.inject.CreationException;
  25. import com.google.inject.Guice;
  26. import com.google.inject.Injector;
  27. import com.google.inject.Key;
  28. import com.google.inject.Module;
  29. import com.google.inject.multibindings.ProvidesIntoOptional.Type;
  30. import com.google.inject.name.Named;
  31. import junit.framework.TestCase;
  32. import java.lang.annotation.Retention;
  33. import java.lang.reflect.Field;
  34. import java.util.Map;
  35. import java.util.Set;
  36. /**
  37. * Tests the various @ProvidesInto annotations.
  38. *
  39. * @author sameb@google.com (Sam Berlin)
  40. */
  41. public class ProvidesIntoTest extends TestCase {
  42. public void testAnnotation() throws Exception {
  43. Injector injector = Guice.createInjector(MultibindingsScanner.asModule(), new AbstractModule() {
  44. @Override protected void configure() {}
  45. @ProvidesIntoSet
  46. @Named("foo")
  47. String setFoo() { return "foo"; }
  48. @ProvidesIntoSet
  49. @Named("foo")
  50. String setFoo2() { return "foo2"; }
  51. @ProvidesIntoSet
  52. @Named("bar")
  53. String setBar() { return "bar"; }
  54. @ProvidesIntoSet
  55. @Named("bar")
  56. String setBar2() { return "bar2"; }
  57. @ProvidesIntoSet
  58. String setNoAnnotation() { return "na"; }
  59. @ProvidesIntoSet
  60. String setNoAnnotation2() { return "na2"; }
  61. @ProvidesIntoMap
  62. @StringMapKey("fooKey")
  63. @Named("foo")
  64. String mapFoo() { return "foo"; }
  65. @ProvidesIntoMap
  66. @StringMapKey("foo2Key")
  67. @Named("foo")
  68. String mapFoo2() { return "foo2"; }
  69. @ProvidesIntoMap
  70. @ClassMapKey(String.class)
  71. @Named("bar")
  72. String mapBar() { return "bar"; }
  73. @ProvidesIntoMap
  74. @ClassMapKey(Number.class)
  75. @Named("bar")
  76. String mapBar2() { return "bar2"; }
  77. @ProvidesIntoMap
  78. @TestEnumKey(TestEnum.A)
  79. String mapNoAnnotation() { return "na"; }
  80. @ProvidesIntoMap
  81. @TestEnumKey(TestEnum.B)
  82. String mapNoAnnotation2() { return "na2"; }
  83. @ProvidesIntoMap
  84. @WrappedKey(number = 1)
  85. Number wrapped1() { return 11; }
  86. @ProvidesIntoMap
  87. @WrappedKey(number = 2)
  88. Number wrapped2() { return 22; }
  89. @ProvidesIntoOptional(ProvidesIntoOptional.Type.DEFAULT)
  90. @Named("foo")
  91. String optionalDefaultFoo() { return "foo"; }
  92. @ProvidesIntoOptional(ProvidesIntoOptional.Type.ACTUAL)
  93. @Named("foo")
  94. String optionalActualFoo() { return "foo2"; }
  95. @ProvidesIntoOptional(ProvidesIntoOptional.Type.DEFAULT)
  96. @Named("bar")
  97. String optionalDefaultBar() { return "bar"; }
  98. @ProvidesIntoOptional(ProvidesIntoOptional.Type.ACTUAL)
  99. String optionalActualBar() { return "na2"; }
  100. });
  101. Set<String> fooSet = injector.getInstance(new Key<Set<String>>(named("foo")) {});
  102. assertEquals(ImmutableSet.of("foo", "foo2"), fooSet);
  103. Set<String> barSet = injector.getInstance(new Key<Set<String>>(named("bar")) {});
  104. assertEquals(ImmutableSet.of("bar", "bar2"), barSet);
  105. Set<String> noAnnotationSet = injector.getInstance(new Key<Set<String>>() {});
  106. assertEquals(ImmutableSet.of("na", "na2"), noAnnotationSet);
  107. Map<String, String> fooMap =
  108. injector.getInstance(new Key<Map<String, String>>(named("foo")) {});
  109. assertEquals(ImmutableMap.of("fooKey", "foo", "foo2Key", "foo2"), fooMap);
  110. Map<Class<?>, String> barMap =
  111. injector.getInstance(new Key<Map<Class<?>, String>>(named("bar")) {});
  112. assertEquals(ImmutableMap.of(String.class, "bar", Number.class, "bar2"), barMap);
  113. Map<TestEnum, String> noAnnotationMap =
  114. injector.getInstance(new Key<Map<TestEnum, String>>() {});
  115. assertEquals(ImmutableMap.of(TestEnum.A, "na", TestEnum.B, "na2"), noAnnotationMap);
  116. Map<WrappedKey, Number> wrappedMap =
  117. injector.getInstance(new Key<Map<WrappedKey, Number>>() {});
  118. assertEquals(ImmutableMap.of(wrappedKeyFor(1), 11, wrappedKeyFor(2), 22), wrappedMap);
  119. Optional<String> fooOptional =
  120. injector.getInstance(new Key<Optional<String>>(named("foo")) {});
  121. assertEquals("foo2", fooOptional.get());
  122. Optional<String> barOptional =
  123. injector.getInstance(new Key<Optional<String>>(named("bar")) {});
  124. assertEquals("bar", barOptional.get());
  125. Optional<String> noAnnotationOptional =
  126. injector.getInstance(new Key<Optional<String>>() {});
  127. assertEquals("na2", noAnnotationOptional.get());
  128. }
  129. enum TestEnum {
  130. A, B
  131. }
  132. @MapKey(unwrapValue = true)
  133. @Retention(RUNTIME)
  134. @interface TestEnumKey {
  135. TestEnum value();
  136. }
  137. @MapKey(unwrapValue = false)
  138. @Retention(RUNTIME)
  139. @interface WrappedKey {
  140. int number();
  141. }
  142. @SuppressWarnings("unused") @WrappedKey(number=1) private static Object wrappedKey1Holder;
  143. @SuppressWarnings("unused") @WrappedKey(number=2) private static Object wrappedKey2Holder;
  144. WrappedKey wrappedKeyFor(int number) throws Exception {
  145. Field field;
  146. switch (number) {
  147. case 1:
  148. field = ProvidesIntoTest.class.getDeclaredField("wrappedKey1Holder");
  149. break;
  150. case 2:
  151. field = ProvidesIntoTest.class.getDeclaredField("wrappedKey2Holder");
  152. break;
  153. default:
  154. throw new IllegalArgumentException("only 1 or 2 supported");
  155. }
  156. return field.getAnnotation(WrappedKey.class);
  157. }
  158. public void testDoubleScannerIsIgnored() {
  159. Injector injector = Guice.createInjector(
  160. MultibindingsScanner.asModule(),
  161. MultibindingsScanner.asModule(),
  162. new AbstractModule() {
  163. @Override protected void configure() {}
  164. @ProvidesIntoSet String provideFoo() { return "foo"; }
  165. }
  166. );
  167. assertEquals(ImmutableSet.of("foo"), injector.getInstance(new Key<Set<String>>() {}));
  168. }
  169. @MapKey(unwrapValue = true)
  170. @Retention(RUNTIME)
  171. @interface ArrayUnwrappedKey {
  172. int[] value();
  173. }
  174. public void testArrayKeys_unwrapValuesTrue() {
  175. Module m = new AbstractModule() {
  176. @Override protected void configure() {}
  177. @ProvidesIntoMap @ArrayUnwrappedKey({1, 2}) String provideFoo() { return "foo"; }
  178. };
  179. try {
  180. Guice.createInjector(MultibindingsScanner.asModule(), m);
  181. fail();
  182. } catch (CreationException ce) {
  183. assertEquals(1, ce.getErrorMessages().size());
  184. assertContains(ce.getMessage(),
  185. "Array types are not allowed in a MapKey with unwrapValue=true: "
  186. + ArrayUnwrappedKey.class.getName(),
  187. "at " + m.getClass().getName() + ".provideFoo(");
  188. }
  189. }
  190. @MapKey(unwrapValue = false)
  191. @Retention(RUNTIME)
  192. @interface ArrayWrappedKey {
  193. int[] number();
  194. }
  195. @SuppressWarnings("unused") @ArrayWrappedKey(number={1, 2}) private static Object arrayWrappedKeyHolder12;
  196. @SuppressWarnings("unused") @ArrayWrappedKey(number={3, 4}) private static Object arrayWrappedKeyHolder34;
  197. ArrayWrappedKey arrayWrappedKeyFor(int number) throws Exception {
  198. Field field;
  199. switch (number) {
  200. case 12:
  201. field = ProvidesIntoTest.class.getDeclaredField("arrayWrappedKeyHolder12");
  202. break;
  203. case 34:
  204. field = ProvidesIntoTest.class.getDeclaredField("arrayWrappedKeyHolder34");
  205. break;
  206. default:
  207. throw new IllegalArgumentException("only 1 or 2 supported");
  208. }
  209. return field.getAnnotation(ArrayWrappedKey.class);
  210. }
  211. public void testArrayKeys_unwrapValuesFalse() throws Exception {
  212. Module m = new AbstractModule() {
  213. @Override protected void configure() {}
  214. @ProvidesIntoMap @ArrayWrappedKey(number = {1, 2}) String provideFoo() { return "foo"; }
  215. @ProvidesIntoMap @ArrayWrappedKey(number = {3, 4}) String provideBar() { return "bar"; }
  216. };
  217. Injector injector = Guice.createInjector(MultibindingsScanner.asModule(), m);
  218. Map<ArrayWrappedKey, String> map =
  219. injector.getInstance(new Key<Map<ArrayWrappedKey, String>>() {});
  220. ArrayWrappedKey key12 = arrayWrappedKeyFor(12);
  221. ArrayWrappedKey key34 = arrayWrappedKeyFor(34);
  222. assertEquals("foo", map.get(key12));
  223. assertEquals("bar", map.get(key34));
  224. assertEquals(2, map.size());
  225. }
  226. public void testProvidesIntoSetWithMapKey() {
  227. Module m = new AbstractModule() {
  228. @Override protected void configure() {}
  229. @ProvidesIntoSet @TestEnumKey(TestEnum.A) String provideFoo() { return "foo"; }
  230. };
  231. try {
  232. Guice.createInjector(MultibindingsScanner.asModule(), m);
  233. fail();
  234. } catch (CreationException ce) {
  235. assertEquals(1, ce.getErrorMessages().size());
  236. assertContains(ce.getMessage(), "Found a MapKey annotation on non map binding at "
  237. + m.getClass().getName() + ".provideFoo");
  238. }
  239. }
  240. public void testProvidesIntoOptionalWithMapKey() {
  241. Module m = new AbstractModule() {
  242. @Override protected void configure() {}
  243. @ProvidesIntoOptional(Type.ACTUAL)
  244. @TestEnumKey(TestEnum.A)
  245. String provideFoo() {
  246. return "foo";
  247. }
  248. };
  249. try {
  250. Guice.createInjector(MultibindingsScanner.asModule(), m);
  251. fail();
  252. } catch (CreationException ce) {
  253. assertEquals(1, ce.getErrorMessages().size());
  254. assertContains(ce.getMessage(), "Found a MapKey annotation on non map binding at "
  255. + m.getClass().getName() + ".provideFoo");
  256. }
  257. }
  258. public void testProvidesIntoMapWithoutMapKey() {
  259. Module m = new AbstractModule() {
  260. @Override protected void configure() {}
  261. @ProvidesIntoMap String provideFoo() { return "foo"; }
  262. };
  263. try {
  264. Guice.createInjector(MultibindingsScanner.asModule(), m);
  265. fail();
  266. } catch (CreationException ce) {
  267. assertEquals(1, ce.getErrorMessages().size());
  268. assertContains(ce.getMessage(), "No MapKey found for map binding at "
  269. + m.getClass().getName() + ".provideFoo");
  270. }
  271. }
  272. @MapKey(unwrapValue = true)
  273. @Retention(RUNTIME)
  274. @interface TestEnumKey2 {
  275. TestEnum value();
  276. }
  277. public void testMoreThanOneMapKeyAnnotation() {
  278. Module m = new AbstractModule() {
  279. @Override protected void configure() {}
  280. @ProvidesIntoMap
  281. @TestEnumKey(TestEnum.A)
  282. @TestEnumKey2(TestEnum.B)
  283. String provideFoo() {
  284. return "foo";
  285. }
  286. };
  287. try {
  288. Guice.createInjector(MultibindingsScanner.asModule(), m);
  289. fail();
  290. } catch (CreationException ce) {
  291. assertEquals(1, ce.getErrorMessages().size());
  292. assertContains(ce.getMessage(), "Found more than one MapKey annotations on "
  293. + m.getClass().getName() + ".provideFoo");
  294. }
  295. }
  296. @MapKey(unwrapValue = true)
  297. @Retention(RUNTIME)
  298. @interface MissingValueMethod {
  299. }
  300. public void testMapKeyMissingValueMethod() {
  301. Module m = new AbstractModule() {
  302. @Override protected void configure() {}
  303. @ProvidesIntoMap
  304. @MissingValueMethod
  305. String provideFoo() {
  306. return "foo";
  307. }
  308. };
  309. try {
  310. Guice.createInjector(MultibindingsScanner.asModule(), m);
  311. fail();
  312. } catch (CreationException ce) {
  313. assertEquals(1, ce.getErrorMessages().size());
  314. assertContains(ce.getMessage(), "No 'value' method in MapKey with unwrapValue=true: "
  315. + MissingValueMethod.class.getName());
  316. }
  317. }
  318. }