PageRenderTime 102ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/core/test/com/google/inject/spi/ModuleAnnotatedMethodScannerTest.java

https://gitlab.com/metamorphiccode/guice
Java | 394 lines | 318 code | 55 blank | 21 comment | 0 complexity | 191393f6d48db4b7837d9b14aa45b7a8 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.spi;
  17. import static com.google.inject.Asserts.assertContains;
  18. import static com.google.inject.name.Names.named;
  19. import static java.lang.annotation.ElementType.METHOD;
  20. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  21. import com.google.common.collect.ImmutableSet;
  22. import com.google.common.collect.Iterables;
  23. import com.google.inject.AbstractModule;
  24. import com.google.inject.Binder;
  25. import com.google.inject.Binding;
  26. import com.google.inject.CreationException;
  27. import com.google.inject.Exposed;
  28. import com.google.inject.Guice;
  29. import com.google.inject.Injector;
  30. import com.google.inject.Key;
  31. import com.google.inject.Module;
  32. import com.google.inject.PrivateModule;
  33. import com.google.inject.internal.util.StackTraceElements;
  34. import com.google.inject.name.Named;
  35. import com.google.inject.name.Names;
  36. import junit.framework.TestCase;
  37. import java.lang.annotation.Annotation;
  38. import java.lang.annotation.Documented;
  39. import java.lang.annotation.Retention;
  40. import java.lang.annotation.Target;
  41. import java.util.Set;
  42. /** Tests for {@link ModuleAnnotatedMethodScanner} usage. */
  43. public class ModuleAnnotatedMethodScannerTest extends TestCase {
  44. public void testScanning() throws Exception {
  45. Module module = new AbstractModule() {
  46. @Override protected void configure() {}
  47. @TestProvides @Named("foo") String foo() {
  48. return "foo";
  49. }
  50. @TestProvides @Named("foo2") String foo2() {
  51. return "foo2";
  52. }
  53. };
  54. Injector injector = Guice.createInjector(module, NamedMunger.module());
  55. // assert no bindings named "foo" or "foo2" exist -- they were munged.
  56. assertMungedBinding(injector, String.class, "foo", "foo");
  57. assertMungedBinding(injector, String.class, "foo2", "foo2");
  58. Binding<String> fooBinding = injector.getBinding(Key.get(String.class, named("foo-munged")));
  59. Binding<String> foo2Binding = injector.getBinding(Key.get(String.class, named("foo2-munged")));
  60. // Validate the provider has a sane toString
  61. assertEquals(methodName(TestProvides.class, "foo", module),
  62. fooBinding.getProvider().toString());
  63. assertEquals(methodName(TestProvides.class, "foo2", module),
  64. foo2Binding.getProvider().toString());
  65. }
  66. public void testSkipSources() throws Exception {
  67. Module module = new AbstractModule() {
  68. @Override protected void configure() {
  69. binder().skipSources(getClass()).install(new AbstractModule() {
  70. @Override protected void configure() {}
  71. @TestProvides @Named("foo") String foo() { return "foo"; }
  72. });
  73. }
  74. };
  75. Injector injector = Guice.createInjector(module, NamedMunger.module());
  76. assertMungedBinding(injector, String.class, "foo", "foo");
  77. }
  78. public void testWithSource() throws Exception {
  79. Module module = new AbstractModule() {
  80. @Override protected void configure() {
  81. binder().withSource("source").install(new AbstractModule() {
  82. @Override protected void configure() {}
  83. @TestProvides @Named("foo") String foo() { return "foo"; }
  84. });
  85. }
  86. };
  87. Injector injector = Guice.createInjector(module, NamedMunger.module());
  88. assertMungedBinding(injector, String.class, "foo", "foo");
  89. }
  90. public void testMoreThanOneClaimedAnnotationFails() throws Exception {
  91. Module module = new AbstractModule() {
  92. @Override protected void configure() {}
  93. @TestProvides @TestProvides2 String foo() {
  94. return "foo";
  95. }
  96. };
  97. try {
  98. Guice.createInjector(module, NamedMunger.module());
  99. fail();
  100. } catch(CreationException expected) {
  101. assertEquals(1, expected.getErrorMessages().size());
  102. assertContains(expected.getMessage(),
  103. "More than one annotation claimed by NamedMunger on method "
  104. + module.getClass().getName() + ".foo(). Methods can only have "
  105. + "one annotation claimed per scanner.");
  106. }
  107. }
  108. private String methodName(Class<? extends Annotation> annotation, String method, Object container)
  109. throws Exception {
  110. return "@" + annotation.getName() + " "
  111. + StackTraceElements.forMember(container.getClass().getDeclaredMethod(method));
  112. }
  113. @Documented @Target(METHOD) @Retention(RUNTIME)
  114. private @interface TestProvides {}
  115. @Documented @Target(METHOD) @Retention(RUNTIME)
  116. private @interface TestProvides2 {}
  117. private static class NamedMunger extends ModuleAnnotatedMethodScanner {
  118. static Module module() {
  119. return new AbstractModule() {
  120. @Override protected void configure() {
  121. binder().scanModulesForAnnotatedMethods(new NamedMunger());
  122. }
  123. };
  124. }
  125. @Override
  126. public String toString() {
  127. return "NamedMunger";
  128. }
  129. @Override
  130. public Set<? extends Class<? extends Annotation>> annotationClasses() {
  131. return ImmutableSet.of(TestProvides.class, TestProvides2.class);
  132. }
  133. @Override
  134. public <T> Key<T> prepareMethod(Binder binder, Annotation annotation, Key<T> key,
  135. InjectionPoint injectionPoint) {
  136. return Key.get(key.getTypeLiteral(),
  137. Names.named(((Named) key.getAnnotation()).value() + "-munged"));
  138. }
  139. }
  140. private void assertMungedBinding(Injector injector, Class<?> clazz, String originalName,
  141. Object expectedValue) {
  142. assertNull(injector.getExistingBinding(Key.get(clazz, named(originalName))));
  143. Binding<?> fooBinding = injector.getBinding(Key.get(clazz, named(originalName + "-munged")));
  144. assertEquals(expectedValue, fooBinding.getProvider().get());
  145. }
  146. public void testFailingScanner() {
  147. try {
  148. Guice.createInjector(new SomeModule(), FailingScanner.module());
  149. fail();
  150. } catch (CreationException expected) {
  151. Message m = Iterables.getOnlyElement(expected.getErrorMessages());
  152. assertEquals(
  153. "An exception was caught and reported. Message: Failing in the scanner.",
  154. m.getMessage());
  155. assertEquals(IllegalStateException.class, m.getCause().getClass());
  156. ElementSource source = (ElementSource) Iterables.getOnlyElement(m.getSources());
  157. assertEquals(SomeModule.class.getName(),
  158. Iterables.getOnlyElement(source.getModuleClassNames()));
  159. assertEquals(String.class.getName() + " " + SomeModule.class.getName() + ".aString()",
  160. source.toString());
  161. }
  162. }
  163. public static class FailingScanner extends ModuleAnnotatedMethodScanner {
  164. static Module module() {
  165. return new AbstractModule() {
  166. @Override protected void configure() {
  167. binder().scanModulesForAnnotatedMethods(new FailingScanner());
  168. }
  169. };
  170. }
  171. @Override public Set<? extends Class<? extends Annotation>> annotationClasses() {
  172. return ImmutableSet.of(TestProvides.class);
  173. }
  174. @Override public <T> Key<T> prepareMethod(
  175. Binder binder, Annotation rawAnnotation, Key<T> key, InjectionPoint injectionPoint) {
  176. throw new IllegalStateException("Failing in the scanner.");
  177. }
  178. }
  179. static class SomeModule extends AbstractModule {
  180. @TestProvides String aString() {
  181. return "Foo";
  182. }
  183. @Override protected void configure() {}
  184. }
  185. public void testChildInjectorInheritsScanner() {
  186. Injector parent = Guice.createInjector(NamedMunger.module());
  187. Injector child = parent.createChildInjector(new AbstractModule() {
  188. @Override protected void configure() {}
  189. @TestProvides @Named("foo") String foo() {
  190. return "foo";
  191. }
  192. });
  193. assertMungedBinding(child, String.class, "foo", "foo");
  194. }
  195. public void testChildInjectorScannersDontImpactSiblings() {
  196. Module module = new AbstractModule() {
  197. @Override
  198. protected void configure() {}
  199. @TestProvides @Named("foo") String foo() {
  200. return "foo";
  201. }
  202. };
  203. Injector parent = Guice.createInjector();
  204. Injector child = parent.createChildInjector(NamedMunger.module(), module);
  205. assertMungedBinding(child, String.class, "foo", "foo");
  206. // no foo nor foo-munged in sibling, since scanner never saw it.
  207. Injector sibling = parent.createChildInjector(module);
  208. assertNull(sibling.getExistingBinding(Key.get(String.class, named("foo"))));
  209. assertNull(sibling.getExistingBinding(Key.get(String.class, named("foo-munged"))));
  210. }
  211. public void testPrivateModuleInheritScanner_usingPrivateModule() {
  212. Injector injector = Guice.createInjector(NamedMunger.module(), new PrivateModule() {
  213. @Override protected void configure() {}
  214. @Exposed @TestProvides @Named("foo") String foo() {
  215. return "foo";
  216. }
  217. });
  218. assertMungedBinding(injector, String.class, "foo", "foo");
  219. }
  220. public void testPrivateModule_skipSourcesWithinPrivateModule() {
  221. Injector injector = Guice.createInjector(NamedMunger.module(), new PrivateModule() {
  222. @Override protected void configure() {
  223. binder().skipSources(getClass()).install(new AbstractModule() {
  224. @Override protected void configure() {}
  225. @Exposed @TestProvides @Named("foo") String foo() {
  226. return "foo";
  227. }
  228. });
  229. }
  230. });
  231. assertMungedBinding(injector, String.class, "foo", "foo");
  232. }
  233. public void testPrivateModule_skipSourcesForPrivateModule() {
  234. Injector injector = Guice.createInjector(NamedMunger.module(), new AbstractModule() {
  235. @Override protected void configure() {
  236. binder().skipSources(getClass()).install(new PrivateModule() {
  237. @Override protected void configure() {}
  238. @Exposed @TestProvides @Named("foo") String foo() {
  239. return "foo";
  240. }
  241. });
  242. }});
  243. assertMungedBinding(injector, String.class, "foo", "foo");
  244. }
  245. public void testPrivateModuleInheritScanner_usingPrivateBinder() {
  246. Injector injector = Guice.createInjector(NamedMunger.module(), new AbstractModule() {
  247. @Override protected void configure() {
  248. binder().newPrivateBinder().install(new AbstractModule() {
  249. @Override protected void configure() {}
  250. @Exposed @TestProvides @Named("foo") String foo() {
  251. return "foo";
  252. }
  253. });
  254. }
  255. });
  256. assertMungedBinding(injector, String.class, "foo", "foo");
  257. }
  258. public void testPrivateModuleInheritScanner_skipSourcesFromPrivateBinder() {
  259. Injector injector = Guice.createInjector(NamedMunger.module(), new AbstractModule() {
  260. @Override protected void configure() {
  261. binder().newPrivateBinder().skipSources(getClass()).install(new AbstractModule() {
  262. @Override protected void configure() {}
  263. @Exposed @TestProvides @Named("foo") String foo() {
  264. return "foo";
  265. }
  266. });
  267. }
  268. });
  269. assertMungedBinding(injector, String.class, "foo", "foo");
  270. }
  271. public void testPrivateModuleInheritScanner_skipSourcesFromPrivateBinder2() {
  272. Injector injector = Guice.createInjector(NamedMunger.module(), new AbstractModule() {
  273. @Override protected void configure() {
  274. binder().skipSources(getClass()).newPrivateBinder().install(new AbstractModule() {
  275. @Override protected void configure() {}
  276. @Exposed @TestProvides @Named("foo") String foo() {
  277. return "foo";
  278. }
  279. });
  280. }
  281. });
  282. assertMungedBinding(injector, String.class, "foo", "foo");
  283. }
  284. public void testPrivateModuleScannersDontImpactSiblings_usingPrivateModule() {
  285. Injector injector = Guice.createInjector(new PrivateModule() {
  286. @Override protected void configure() {
  287. install(NamedMunger.module());
  288. }
  289. @Exposed @TestProvides @Named("foo") String foo() {
  290. return "foo";
  291. }
  292. }, new PrivateModule() {
  293. @Override protected void configure() {}
  294. // ignored! (because the scanner doesn't run over this module)
  295. @Exposed @TestProvides @Named("foo") String foo() {
  296. return "foo";
  297. }
  298. });
  299. assertMungedBinding(injector, String.class, "foo", "foo");
  300. }
  301. public void testPrivateModuleScannersDontImpactSiblings_usingPrivateBinder() {
  302. Injector injector = Guice.createInjector(new AbstractModule() {
  303. @Override protected void configure() {
  304. binder().newPrivateBinder().install(new AbstractModule() {
  305. @Override protected void configure() {
  306. install(NamedMunger.module());
  307. }
  308. @Exposed @TestProvides @Named("foo") String foo() {
  309. return "foo";
  310. }
  311. });
  312. }
  313. }, new AbstractModule() {
  314. @Override protected void configure() {
  315. binder().newPrivateBinder().install(new AbstractModule() {
  316. @Override protected void configure() {}
  317. // ignored! (because the scanner doesn't run over this module)
  318. @Exposed @TestProvides @Named("foo") String foo() {
  319. return "foo";
  320. }
  321. });
  322. }});
  323. assertMungedBinding(injector, String.class, "foo", "foo");
  324. }
  325. public void testPrivateModuleWithinPrivateModule() {
  326. Injector injector = Guice.createInjector(NamedMunger.module(), new PrivateModule() {
  327. @Override protected void configure() {
  328. expose(Key.get(String.class, named("foo-munged")));
  329. install(new PrivateModule() {
  330. @Override protected void configure() {}
  331. @Exposed @TestProvides @Named("foo") String foo() {
  332. return "foo";
  333. }
  334. });
  335. }
  336. });
  337. assertMungedBinding(injector, String.class, "foo", "foo");
  338. }
  339. }