PageRenderTime 1006ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/guice-3.0-rc2-src/core/test/com/google/inject/JitBindingsTest.java

#
Java | 604 lines | 492 code | 55 blank | 57 comment | 11 complexity | 9e052c52b59aab306f161c93fcb9b155 MD5 | raw file
Possible License(s): Apache-2.0
  1. /*
  2. * Copyright (C) 2010 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;
  17. import static com.google.inject.Asserts.assertContains;
  18. import static com.google.inject.JitBindingsTest.GetBindingCheck.ALLOW_BINDING_PROVIDER;
  19. import static com.google.inject.JitBindingsTest.GetBindingCheck.FAIL_ALL;
  20. import static com.google.inject.JitBindingsTest.GetBindingCheck.ALLOW_BINDING;
  21. import static com.google.inject.internal.util.ImmutableSet.of;
  22. import junit.framework.TestCase;
  23. import java.util.Set;
  24. /**
  25. * Some tests for {@link Binder#requireExplicitBindings()}
  26. *
  27. * @author sberlin@gmail.com (Sam Berlin)
  28. */
  29. public class JitBindingsTest extends TestCase {
  30. private String jitFailed(Class<?> clazz) {
  31. return jitFailed(TypeLiteral.get(clazz));
  32. }
  33. private String jitFailed(TypeLiteral<?> clazz) {
  34. return "Explicit bindings are required and " + clazz + " is not explicitly bound.";
  35. }
  36. public void testLinkedBindingWorks() {
  37. Injector injector = Guice.createInjector(new AbstractModule() {
  38. @Override
  39. protected void configure() {
  40. binder().requireExplicitBindings();
  41. bind(Foo.class).to(FooImpl.class);
  42. }
  43. });
  44. // Foo was explicitly bound
  45. ensureWorks(injector, Foo.class);
  46. // FooImpl was implicitly bound, it is an error to call getInstance or getProvider,
  47. // It is OK to call getBinding for introspection, but an error to get the provider
  48. // of the binding
  49. ensureFails(injector, ALLOW_BINDING, FooImpl.class);
  50. }
  51. public void testMoreBasicsWork() {
  52. Injector injector = Guice.createInjector(new AbstractModule() {
  53. @Override
  54. protected void configure() {
  55. binder().requireExplicitBindings();
  56. bind(Foo.class).to(FooImpl.class);
  57. bind(Bar.class);
  58. bind(FooBar.class);
  59. }
  60. });
  61. // Foo, Bar & FooBar was explicitly bound
  62. ensureWorks(injector, FooBar.class, Bar.class, Foo.class);
  63. // FooImpl was implicitly bound, it is an error to call getInstance or getProvider,
  64. // It is OK to call getBinding for introspection, but an error to get the provider
  65. // of the binding
  66. ensureFails(injector, ALLOW_BINDING, FooImpl.class);
  67. }
  68. public void testLinkedEagerSingleton() {
  69. Injector injector = Guice.createInjector(new AbstractModule() {
  70. @Override
  71. protected void configure() {
  72. binder().requireExplicitBindings();
  73. bind(Foo.class).to(FooImpl.class).asEagerSingleton();
  74. }
  75. });
  76. // Foo was explicitly bound
  77. ensureWorks(injector, Foo.class);
  78. // FooImpl was implicitly bound, it is an error to call getInstance or getProvider,
  79. // It is OK to call getBinding for introspection, but an error to get the provider
  80. // of the binding
  81. ensureFails(injector, ALLOW_BINDING, FooImpl.class);
  82. }
  83. public void testBasicsWithEagerSingleton() {
  84. Injector injector = Guice.createInjector(new AbstractModule() {
  85. @Override
  86. protected void configure() {
  87. binder().requireExplicitBindings();
  88. bind(Foo.class).to(FooImpl.class).asEagerSingleton();
  89. bind(Bar.class);
  90. bind(FooBar.class);
  91. }
  92. });
  93. // Foo, Bar & FooBar was explicitly bound
  94. ensureWorks(injector, FooBar.class, Bar.class, Foo.class);
  95. // FooImpl was implicitly bound, it is an error to call getInstance or getProvider,
  96. // It is OK to call getBinding for introspection, but an error to get the provider
  97. // of the binding
  98. ensureFails(injector, ALLOW_BINDING, FooImpl.class);
  99. }
  100. public void testLinkedToScoped() {
  101. Injector injector = Guice.createInjector(new AbstractModule() {
  102. @Override
  103. protected void configure() {
  104. binder.requireExplicitBindings();
  105. bind(Foo.class).to(ScopedFooImpl.class);
  106. }
  107. });
  108. // Foo was explicitly bound
  109. ensureWorks(injector, Foo.class);
  110. // FooSingletonImpl was implicitly bound, it is an error to call getInstance or getProvider,
  111. // It is OK to call getBinding for introspection, but an error to get the provider
  112. // of the binding
  113. ensureFails(injector, ALLOW_BINDING, ScopedFooImpl.class);
  114. }
  115. public void testBasicsWithScoped() {
  116. Injector injector = Guice.createInjector(new AbstractModule() {
  117. @Override
  118. protected void configure() {
  119. binder().requireExplicitBindings();
  120. bind(Foo.class).to(ScopedFooImpl.class);
  121. bind(Bar.class);
  122. bind(FooBar.class);
  123. }
  124. });
  125. // Foo, Bar & FooBar was explicitly bound
  126. ensureWorks(injector, FooBar.class, Bar.class, Foo.class);
  127. // FooSingletonImpl was implicitly bound, it is an error to call getInstance or getProvider,
  128. // It is OK to call getBinding for introspection, but an error to get the provider
  129. // of the binding
  130. ensureFails(injector, ALLOW_BINDING, ScopedFooImpl.class);
  131. }
  132. public void testFailsIfInjectingScopedDirectlyWhenItIsntBound() {
  133. try {
  134. Guice.createInjector(new AbstractModule() {
  135. @Override
  136. protected void configure() {
  137. binder().requireExplicitBindings();
  138. bind(Foo.class).to(ScopedFooImpl.class);
  139. bind(WantsScopedFooImpl.class);
  140. }
  141. });
  142. fail();
  143. } catch(CreationException expected) {
  144. assertContains(expected.getMessage(), "1) " + jitFailed(ScopedFooImpl.class));
  145. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  146. }
  147. }
  148. public void testLinkedProviderBindingWorks() {
  149. Injector injector = Guice.createInjector(new AbstractModule() {
  150. @Override
  151. protected void configure() {
  152. binder().requireExplicitBindings();
  153. bind(Foo.class).toProvider(FooProvider.class);
  154. }
  155. });
  156. // Foo was explicitly bound
  157. ensureWorks(injector, Foo.class);
  158. // FooImpl was not bound at all (even implicitly), it is an error
  159. // to call getInstance, getProvider, or getBinding.
  160. ensureFails(injector, FAIL_ALL, FooImpl.class);
  161. }
  162. public void testJitGetFails() {
  163. try {
  164. Guice.createInjector(new AbstractModule() {
  165. @Override
  166. protected void configure() {
  167. binder().requireExplicitBindings();
  168. }
  169. }).getInstance(Bar.class);
  170. fail("should have failed");
  171. } catch(ConfigurationException expected) {
  172. assertContains(expected.getMessage(), "1) " + jitFailed(Bar.class));
  173. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  174. }
  175. }
  176. public void testJitInjectionFails() {
  177. try {
  178. Guice.createInjector(new AbstractModule() {
  179. @Override
  180. protected void configure() {
  181. binder().requireExplicitBindings();
  182. bind(Foo.class).to(FooImpl.class);
  183. bind(FooBar.class);
  184. }
  185. });
  186. fail("should have failed");
  187. } catch (CreationException expected) {
  188. assertContains(expected.getMessage(), "1) " + jitFailed(Bar.class));
  189. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  190. }
  191. }
  192. public void testJitProviderGetFails() {
  193. try {
  194. Guice.createInjector(new AbstractModule() {
  195. @Override
  196. protected void configure() {
  197. binder().requireExplicitBindings();
  198. }
  199. }).getProvider(Bar.class);
  200. fail("should have failed");
  201. } catch (ConfigurationException expected) {
  202. assertContains(expected.getMessage(), "1) " + jitFailed(Bar.class));
  203. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  204. }
  205. }
  206. public void testJitProviderInjectionFails() {
  207. try {
  208. Guice.createInjector(new AbstractModule() {
  209. @Override
  210. protected void configure() {
  211. binder().requireExplicitBindings();
  212. bind(Foo.class).to(FooImpl.class);
  213. bind(ProviderFooBar.class);
  214. }
  215. });
  216. fail("should have failed");
  217. } catch (CreationException expected) {
  218. assertContains(expected.getMessage(), "1) " + jitFailed(Bar.class));
  219. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  220. }
  221. }
  222. public void testImplementedBy() {
  223. Injector injector = Guice.createInjector(new AbstractModule() {
  224. @Override
  225. protected void configure() {
  226. binder().requireExplicitBindings();
  227. bind(ImplBy.class);
  228. }
  229. });
  230. ensureWorks(injector, ImplBy.class);
  231. ensureFails(injector, ALLOW_BINDING, ImplByImpl.class);
  232. }
  233. public void testImplementedBySomethingThatIsAnnotated() {
  234. Injector injector = Guice.createInjector(new AbstractModule() {
  235. @Override
  236. protected void configure() {
  237. binder().requireExplicitBindings();
  238. bind(ImplByScoped.class);
  239. }
  240. });
  241. ensureWorks(injector, ImplByScoped.class);
  242. ensureFails(injector, ALLOW_BINDING, ImplByScopedImpl.class);
  243. }
  244. public void testProvidedBy() {
  245. Injector injector = Guice.createInjector(new AbstractModule() {
  246. @Override
  247. protected void configure() {
  248. binder().requireExplicitBindings();
  249. bind(ProvBy.class);
  250. }
  251. });
  252. ensureWorks(injector, ProvBy.class);
  253. ensureFails(injector, ALLOW_BINDING, ProvByProvider.class);
  254. }
  255. public void testProviderMethods() {
  256. Injector injector = Guice.createInjector(new AbstractModule() {
  257. @Override protected void configure() {
  258. binder().requireExplicitBindings();
  259. }
  260. @SuppressWarnings("unused") @Provides Foo foo() { return new FooImpl(); }
  261. });
  262. ensureWorks(injector, Foo.class);
  263. }
  264. public void testChildInjectorInheritsOption() {
  265. Injector parent = Guice.createInjector(new AbstractModule() {
  266. @Override
  267. protected void configure() {
  268. binder().requireExplicitBindings();
  269. bind(Bar.class);
  270. }
  271. });
  272. ensureWorks(parent, Bar.class);
  273. ensureFails(parent, FAIL_ALL, FooImpl.class, FooBar.class, Foo.class);
  274. try {
  275. parent.createChildInjector(new AbstractModule() {
  276. @Override
  277. protected void configure() {
  278. bind(FooBar.class);
  279. }
  280. });
  281. fail("should have failed");
  282. } catch(CreationException expected) {
  283. assertContains(expected.getMessage(), "1) " + jitFailed(Foo.class));
  284. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  285. }
  286. Injector child = parent.createChildInjector(new AbstractModule() {
  287. @Override
  288. protected void configure() {
  289. bind(Foo.class).to(FooImpl.class);
  290. }
  291. });
  292. ensureWorks(child, Foo.class, Bar.class);
  293. ensureFails(child, ALLOW_BINDING, FooImpl.class);
  294. ensureFails(parent, FAIL_ALL, FooImpl.class, FooBar.class, Foo.class); // parent still doesn't have these
  295. Injector grandchild = child.createChildInjector(new AbstractModule() {
  296. @Override
  297. protected void configure() {
  298. bind(FooBar.class);
  299. }
  300. });
  301. ensureWorks(grandchild, FooBar.class, Foo.class, Bar.class);
  302. ensureFails(grandchild, ALLOW_BINDING, FooImpl.class);
  303. ensureFails(child, ALLOW_BINDING, FooImpl.class);
  304. ensureFails(parent, FAIL_ALL, FooImpl.class, FooBar.class, Foo.class); // parent still doesn't have these
  305. }
  306. public void testChildInjectorAddsOption() {
  307. Injector parent = Guice.createInjector(new AbstractModule() {
  308. @Override
  309. protected void configure() {
  310. bind(Bar.class);
  311. }
  312. });
  313. int totalParentBindings = parent.getAllBindings().size();
  314. try {
  315. parent.createChildInjector(new AbstractModule() {
  316. @Override
  317. protected void configure() {
  318. binder().requireExplicitBindings();
  319. bind(FooBar.class);
  320. }
  321. });
  322. fail("should have failed");
  323. } catch(CreationException expected) {
  324. assertContains(expected.getMessage(), "1) " + jitFailed(Foo.class));
  325. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  326. }
  327. assertEquals(totalParentBindings, parent.getAllBindings().size());
  328. Injector child = parent.createChildInjector(new AbstractModule() {
  329. @Override
  330. protected void configure() {
  331. binder().requireExplicitBindings();
  332. bind(Foo.class).to(FooImpl.class);
  333. }
  334. });
  335. totalParentBindings++; // creating this child added FooImpl to the parent.
  336. assertEquals(totalParentBindings, parent.getAllBindings().size());
  337. ensureWorks(child, Foo.class, Bar.class);
  338. ensureFails(child, ALLOW_BINDING_PROVIDER, FooImpl.class);
  339. // Make extra certain that if something tries to inject a FooImpl from child
  340. // that it fails, even if calling getBinding().getProvider works.. because
  341. // the binding is built with the parent injector.
  342. try {
  343. child.injectMembers(new Object() {
  344. @SuppressWarnings("unused")
  345. @Inject
  346. void inject(FooImpl fooImpl) {}
  347. });
  348. fail();
  349. } catch(ConfigurationException expected) {
  350. assertContains(expected.getMessage(), "1) " + jitFailed(FooImpl.class));
  351. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  352. }
  353. Injector grandchild = child.createChildInjector(new AbstractModule() {
  354. @Override
  355. protected void configure() {
  356. bind(FooBar.class);
  357. }
  358. });
  359. assertEquals(totalParentBindings, parent.getAllBindings().size());
  360. ensureWorks(grandchild, FooBar.class, Foo.class, Bar.class);
  361. ensureFails(grandchild, ALLOW_BINDING_PROVIDER, FooImpl.class);
  362. ensureFails(child, ALLOW_BINDING_PROVIDER, FooImpl.class);
  363. // Make sure siblings of children don't inherit each others settings...
  364. // a new child should be able to get FooImpl.
  365. child = parent.createChildInjector();
  366. ensureWorks(child, FooImpl.class);
  367. }
  368. public void testPrivateModulesInheritOptions() {
  369. try {
  370. Guice.createInjector(new AbstractModule() {
  371. protected void configure() {
  372. binder().requireExplicitBindings();
  373. bind(Foo.class).to(FooImpl.class);
  374. install(new PrivateModule() {
  375. public void configure() {
  376. bind(FooBar.class);
  377. expose(FooBar.class);
  378. }
  379. });
  380. }
  381. });
  382. fail("should have failed");
  383. } catch(CreationException expected) {
  384. assertContains(expected.getMessage(), "1) " + jitFailed(Bar.class));
  385. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  386. }
  387. }
  388. public void testPrivateModuleAddsOption() {
  389. try {
  390. Guice.createInjector(new AbstractModule() {
  391. protected void configure() {
  392. bind(Foo.class).to(FooImpl.class);
  393. // Fails because FooBar is in the private module,
  394. // and it wants Bar, but Bar would be JIT.
  395. install(new PrivateModule() {
  396. public void configure() {
  397. binder().requireExplicitBindings();
  398. bind(FooBar.class);
  399. expose(FooBar.class);
  400. }
  401. });
  402. }
  403. });
  404. fail("should have failed");
  405. } catch(CreationException expected) {
  406. assertContains(expected.getMessage(), "1) " + jitFailed(Bar.class));
  407. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  408. }
  409. }
  410. public void testPrivateModuleSiblingsDontShareOption() {
  411. Guice.createInjector(new AbstractModule() {
  412. protected void configure() {
  413. bind(Foo.class).to(FooImpl.class);
  414. install(new PrivateModule() {
  415. public void configure() {
  416. binder().requireExplicitBindings();
  417. }
  418. });
  419. // This works, even though Bar is JIT,
  420. // because the requireExplicitBindings isn't shared
  421. // between sibling private modules.
  422. install(new PrivateModule() {
  423. public void configure() {
  424. bind(FooBar.class);
  425. expose(FooBar.class);
  426. }
  427. });
  428. }
  429. });
  430. }
  431. public void testTypeLiteralsCanBeInjected() {
  432. Injector injector = Guice.createInjector(new AbstractModule() {
  433. @Override protected void configure() {
  434. binder().requireExplicitBindings();
  435. bind(new TypeLiteral<WantsTypeLiterals<String>>() {});
  436. bind(new TypeLiteral<Set<String>>() {}).toInstance(of("bar"));
  437. }
  438. });
  439. WantsTypeLiterals<String> foo = injector.getInstance(new Key<WantsTypeLiterals<String>>() {});
  440. assertEquals(foo.literal.getRawType(), String.class);
  441. assertEquals(of("bar"), foo.set);
  442. }
  443. public void testMembersInjectorsCanBeInjected() {
  444. Injector injector = Guice.createInjector(new AbstractModule() {
  445. @Override protected void configure() {
  446. binder().requireExplicitBindings();
  447. }
  448. @Provides String data(MembersInjector<String> mi) {
  449. String data = "foo";
  450. mi.injectMembers(data);
  451. return data;
  452. }
  453. });
  454. String data = injector.getInstance(String.class);
  455. assertEquals("foo", data);
  456. }
  457. private void ensureWorks(Injector injector, Class<?>... classes) {
  458. for(int i = 0; i < classes.length; i++) {
  459. injector.getInstance(classes[i]);
  460. injector.getProvider(classes[i]).get();
  461. injector.getBinding(classes[i]).getProvider().get();
  462. }
  463. }
  464. enum GetBindingCheck { FAIL_ALL, ALLOW_BINDING, ALLOW_BINDING_PROVIDER }
  465. private void ensureFails(Injector injector, GetBindingCheck getBinding, Class<?>... classes) {
  466. for(int i = 0; i < classes.length; i++) {
  467. try {
  468. injector.getInstance(classes[i]);
  469. fail("should have failed tring to retrieve class: " + classes[i]);
  470. } catch(ConfigurationException expected) {
  471. assertContains(expected.getMessage(), "1) " + jitFailed(classes[i]));
  472. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  473. }
  474. try {
  475. injector.getProvider(classes[i]);
  476. fail("should have failed tring to retrieve class: " + classes[i]);
  477. } catch(ConfigurationException expected) {
  478. assertContains(expected.getMessage(), "1) " + jitFailed(classes[i]));
  479. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  480. }
  481. if (getBinding == GetBindingCheck.ALLOW_BINDING
  482. || getBinding == GetBindingCheck.ALLOW_BINDING_PROVIDER) {
  483. Binding<?> binding = injector.getBinding(classes[i]);
  484. try {
  485. binding.getProvider();
  486. if (getBinding != GetBindingCheck.ALLOW_BINDING_PROVIDER) {
  487. fail("should have failed trying to retrieve class: " + classes[i]);
  488. }
  489. } catch(ConfigurationException expected) {
  490. if (getBinding == GetBindingCheck.ALLOW_BINDING_PROVIDER) {
  491. throw expected;
  492. }
  493. assertContains(expected.getMessage(), "1) " + jitFailed(classes[i]));
  494. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  495. }
  496. } else {
  497. try {
  498. injector.getBinding(classes[i]);
  499. fail("should have failed tring to retrieve class: " + classes[i]);
  500. } catch(ConfigurationException expected) {
  501. assertContains(expected.getMessage(), "1) " + jitFailed(classes[i]));
  502. assertTrue(expected.getMessage(), !expected.getMessage().contains("2) "));
  503. }
  504. }
  505. }
  506. }
  507. private static interface Foo {}
  508. private static class FooImpl implements Foo {}
  509. @Singleton private static class ScopedFooImpl implements Foo {}
  510. private static class WantsScopedFooImpl {
  511. @SuppressWarnings("unused") @Inject ScopedFooImpl scopedFoo;
  512. }
  513. private static class Bar {}
  514. private static class FooBar {
  515. @SuppressWarnings("unused") @Inject Foo foo;
  516. @SuppressWarnings("unused") @Inject Bar bar;
  517. }
  518. private static class ProviderFooBar {
  519. @SuppressWarnings("unused") @Inject Provider<Foo> foo;
  520. @SuppressWarnings("unused") @Inject Provider<Bar> bar;
  521. }
  522. private static class FooProvider implements Provider<Foo> {
  523. public Foo get() {
  524. return new FooImpl();
  525. }
  526. }
  527. @ImplementedBy(ImplByImpl.class)
  528. private static interface ImplBy {}
  529. private static class ImplByImpl implements ImplBy {}
  530. @ImplementedBy(ImplByScopedImpl.class)
  531. private static interface ImplByScoped {}
  532. @Singleton
  533. private static class ImplByScopedImpl implements ImplByScoped {}
  534. @ProvidedBy(ProvByProvider.class)
  535. private static interface ProvBy {}
  536. private static class ProvByProvider implements Provider<ProvBy> {
  537. public ProvBy get() {
  538. return new ProvBy() {};
  539. }
  540. }
  541. private static class WantsTypeLiterals<T> {
  542. TypeLiteral<T> literal;
  543. Set<T> set;
  544. @Inject WantsTypeLiterals(TypeLiteral<T> literal, Set<T> set) {
  545. this.literal = literal;
  546. this.set = set;
  547. }
  548. }
  549. }