PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/core/test/com/google/inject/ProvisionListenerTest.java

https://gitlab.com/metamorphiccode/guice
Java | 796 lines | 673 code | 79 blank | 44 comment | 8 complexity | ab80c13d5a88bd93394caed7d2a97d26 MD5 | raw file
  1. /**
  2. * Copyright (C) 2011 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.common.collect.ImmutableList.of;
  18. import static com.google.inject.Asserts.assertContains;
  19. import static com.google.inject.name.Names.named;
  20. import com.google.common.collect.ImmutableList;
  21. import com.google.common.collect.ImmutableSet;
  22. import com.google.common.collect.Lists;
  23. import com.google.inject.matcher.AbstractMatcher;
  24. import com.google.inject.matcher.Matcher;
  25. import com.google.inject.matcher.Matchers;
  26. import com.google.inject.name.Named;
  27. import com.google.inject.spi.DependencyAndSource;
  28. import com.google.inject.spi.InstanceBinding;
  29. import com.google.inject.spi.ProvisionListener;
  30. import com.google.inject.util.Providers;
  31. import junit.framework.TestCase;
  32. import java.util.List;
  33. import java.util.Set;
  34. import java.util.concurrent.atomic.AtomicBoolean;
  35. import java.util.concurrent.atomic.AtomicInteger;
  36. import java.util.concurrent.atomic.AtomicReference;
  37. /**
  38. * Tests for {@link Binder#bindListener(Matcher, ProvisionListener...)}
  39. *
  40. * @author sameb@google.com (Sam Berlin)
  41. */
  42. // TODO(sameb): Add some tests for private modules & child injectors.
  43. public class ProvisionListenerTest extends TestCase {
  44. public void testExceptionInListenerBeforeProvisioning() {
  45. Injector injector = Guice.createInjector(new AbstractModule() {
  46. @Override
  47. protected void configure() {
  48. bindListener(Matchers.any(), new FailBeforeProvision());
  49. }
  50. });
  51. try {
  52. injector.getInstance(Foo.class);
  53. fail();
  54. } catch(ProvisionException pe) {
  55. assertEquals(1, pe.getErrorMessages().size());
  56. assertContains(pe.getMessage(),
  57. "1) Error notifying ProvisionListener " + FailBeforeProvision.class.getName()
  58. + " of " + Foo.class.getName(),
  59. "Reason: java.lang.RuntimeException: boo",
  60. "while locating " + Foo.class.getName());
  61. assertEquals("boo", pe.getCause().getMessage());
  62. }
  63. }
  64. public void testExceptionInListenerAfterProvisioning() {
  65. Injector injector = Guice.createInjector(new AbstractModule() {
  66. @Override
  67. protected void configure() {
  68. bindListener(Matchers.any(), new FailAfterProvision());
  69. }
  70. });
  71. try {
  72. injector.getInstance(Foo.class);
  73. fail();
  74. } catch(ProvisionException pe) {
  75. assertEquals(1, pe.getErrorMessages().size());
  76. assertContains(pe.getMessage(),
  77. "1) Error notifying ProvisionListener " + FailAfterProvision.class.getName()
  78. + " of " + Foo.class.getName(),
  79. "Reason: java.lang.RuntimeException: boo",
  80. "while locating " + Foo.class.getName());
  81. assertEquals("boo", pe.getCause().getMessage());
  82. }
  83. }
  84. public void testExceptionInProvisionExplicitlyCalled() {
  85. Injector injector = Guice.createInjector(new AbstractModule() {
  86. @Override
  87. protected void configure() {
  88. bindListener(Matchers.any(), new JustProvision());
  89. }
  90. });
  91. try {
  92. injector.getInstance(FooBomb.class);
  93. fail();
  94. } catch(ProvisionException pe) {
  95. assertEquals(1, pe.getErrorMessages().size());
  96. assertContains(pe.getMessage(),
  97. "1) Error injecting constructor, java.lang.RuntimeException: Retry, Abort, Fail",
  98. " at " + FooBomb.class.getName(),
  99. " while locating " + FooBomb.class.getName());
  100. assertEquals("Retry, Abort, Fail", pe.getCause().getMessage());
  101. }
  102. }
  103. public void testExceptionInProvisionAutomaticallyCalled() {
  104. Injector injector = Guice.createInjector(new AbstractModule() {
  105. @Override
  106. protected void configure() {
  107. bindListener(Matchers.any(), new NoProvision());
  108. }
  109. });
  110. try {
  111. injector.getInstance(FooBomb.class);
  112. fail();
  113. } catch(ProvisionException pe) {
  114. assertEquals(1, pe.getErrorMessages().size());
  115. assertContains(pe.getMessage(),
  116. "1) Error injecting constructor, java.lang.RuntimeException: Retry, Abort, Fail",
  117. " at " + FooBomb.class.getName(),
  118. " while locating " + FooBomb.class.getName());
  119. assertEquals("Retry, Abort, Fail", pe.getCause().getMessage());
  120. }
  121. }
  122. public void testExceptionInFieldProvision() throws Exception {
  123. final CountAndCaptureExceptionListener listener = new CountAndCaptureExceptionListener();
  124. Injector injector = Guice.createInjector(new AbstractModule() {
  125. @Override protected void configure() {
  126. bindListener(new AbstractMatcher<Binding<?>>() {
  127. @Override public boolean matches(Binding<?> binding) {
  128. return binding.getKey().getRawType().equals(DependsOnFooBombInField.class);
  129. }
  130. }, listener);
  131. }
  132. });
  133. assertEquals(0, listener.beforeProvision);
  134. String expectedMsg = null;
  135. try {
  136. injector.getInstance(DependsOnFooBombInField.class);
  137. fail();
  138. } catch (ProvisionException expected) {
  139. assertEquals(1, expected.getErrorMessages().size());
  140. expectedMsg = expected.getMessage();
  141. assertContains(listener.capture.get().getMessage(),
  142. "1) Error injecting constructor, java.lang.RuntimeException: Retry, Abort, Fail",
  143. " at " + FooBomb.class.getName(),
  144. " while locating " + FooBomb.class.getName(),
  145. " while locating " + DependsOnFooBombInField.class.getName());
  146. }
  147. assertEquals(1, listener.beforeProvision);
  148. assertEquals(expectedMsg, listener.capture.get().getMessage());
  149. assertEquals(0, listener.afterProvision);
  150. }
  151. public void testExceptionInCxtorProvision() throws Exception {
  152. final CountAndCaptureExceptionListener listener = new CountAndCaptureExceptionListener();
  153. Injector injector = Guice.createInjector(new AbstractModule() {
  154. @Override protected void configure() {
  155. bindListener(new AbstractMatcher<Binding<?>>() {
  156. @Override public boolean matches(Binding<?> binding) {
  157. return binding.getKey().getRawType().equals(DependsOnFooBombInCxtor.class);
  158. }
  159. }, listener);
  160. }
  161. });
  162. assertEquals(0, listener.beforeProvision);
  163. String expectedMsg = null;
  164. try {
  165. injector.getInstance(DependsOnFooBombInCxtor.class);
  166. fail();
  167. } catch (ProvisionException expected) {
  168. assertEquals(1, expected.getErrorMessages().size());
  169. expectedMsg = expected.getMessage();
  170. assertContains(listener.capture.get().getMessage(),
  171. "1) Error injecting constructor, java.lang.RuntimeException: Retry, Abort, Fail",
  172. " at " + FooBomb.class.getName(),
  173. " while locating " + FooBomb.class.getName(),
  174. " while locating " + DependsOnFooBombInCxtor.class.getName());
  175. }
  176. assertEquals(1, listener.beforeProvision);
  177. assertEquals(expectedMsg, listener.capture.get().getMessage());
  178. assertEquals(0, listener.afterProvision);
  179. }
  180. public void testListenerCallsProvisionTwice() {
  181. Injector injector = Guice.createInjector(new AbstractModule() {
  182. @Override
  183. protected void configure() {
  184. bindListener(Matchers.any(), new ProvisionTwice());
  185. }
  186. });
  187. try {
  188. injector.getInstance(Foo.class);
  189. fail();
  190. } catch(ProvisionException pe) {
  191. assertEquals(1, pe.getErrorMessages().size());
  192. assertContains(pe.getMessage(),
  193. "1) Error notifying ProvisionListener " + ProvisionTwice.class.getName()
  194. + " of " + Foo.class.getName(),
  195. "Reason: java.lang.IllegalStateException: Already provisioned in this listener.",
  196. "while locating " + Foo.class.getName());
  197. assertEquals("Already provisioned in this listener.", pe.getCause().getMessage());
  198. }
  199. }
  200. public void testCachedInScopePreventsProvisionNotify() {
  201. final Counter count1 = new Counter();
  202. Injector injector = Guice.createInjector(new AbstractModule() {
  203. @Override
  204. protected void configure() {
  205. bindListener(Matchers.any(), count1);
  206. bind(Foo.class).in(Scopes.SINGLETON);
  207. }
  208. });
  209. Foo foo = injector.getInstance(Foo.class);
  210. assertNotNull(foo);
  211. assertEquals(1, count1.count);
  212. // not notified the second time because nothing is provisioned
  213. // (it's cached in the scope)
  214. count1.count = 0;
  215. assertSame(foo, injector.getInstance(Foo.class));
  216. assertEquals(0, count1.count);
  217. }
  218. public void testCombineAllBindListenerCalls() {
  219. final Counter count1 = new Counter();
  220. final Counter count2 = new Counter();
  221. Injector injector = Guice.createInjector(new AbstractModule() {
  222. @Override
  223. protected void configure() {
  224. bindListener(Matchers.any(), count1);
  225. bindListener(Matchers.any(), count2);
  226. }
  227. });
  228. assertNotNull(injector.getInstance(Foo.class));
  229. assertEquals(1, count1.count);
  230. assertEquals(1, count2.count);
  231. }
  232. public void testNotifyEarlyListenersIfFailBeforeProvision() {
  233. final Counter count1 = new Counter();
  234. final Counter count2 = new Counter();
  235. Injector injector = Guice.createInjector(new AbstractModule() {
  236. @Override
  237. protected void configure() {
  238. bindListener(Matchers.any(), count1, new FailBeforeProvision(), count2);
  239. }
  240. });
  241. try {
  242. injector.getInstance(Foo.class);
  243. fail();
  244. } catch(ProvisionException pe) {
  245. assertEquals(1, pe.getErrorMessages().size());
  246. assertContains(pe.getMessage(),
  247. "1) Error notifying ProvisionListener " + FailBeforeProvision.class.getName()
  248. + " of " + Foo.class.getName(),
  249. "Reason: java.lang.RuntimeException: boo",
  250. "while locating " + Foo.class.getName());
  251. assertEquals("boo", pe.getCause().getMessage());
  252. assertEquals(1, count1.count);
  253. assertEquals(0, count2.count);
  254. }
  255. }
  256. public void testNotifyLaterListenersIfFailAfterProvision() {
  257. final Counter count1 = new Counter();
  258. final Counter count2 = new Counter();
  259. Injector injector = Guice.createInjector(new AbstractModule() {
  260. @Override
  261. protected void configure() {
  262. bindListener(Matchers.any(), count1, new FailAfterProvision(), count2);
  263. }
  264. });
  265. try {
  266. injector.getInstance(Foo.class);
  267. fail();
  268. } catch(ProvisionException pe) {
  269. assertEquals(1, pe.getErrorMessages().size());
  270. assertContains(pe.getMessage(),
  271. "1) Error notifying ProvisionListener " + FailAfterProvision.class.getName()
  272. + " of " + Foo.class.getName(),
  273. "Reason: java.lang.RuntimeException: boo",
  274. "while locating " + Foo.class.getName());
  275. assertEquals("boo", pe.getCause().getMessage());
  276. assertEquals(1, count1.count);
  277. assertEquals(1, count2.count);
  278. }
  279. }
  280. public void testNotifiedKeysOfAllBindTypes() {
  281. final Capturer capturer = new Capturer();
  282. Injector injector = Guice.createInjector(new AbstractModule() {
  283. @Override
  284. protected void configure() {
  285. bindListener(Matchers.any(), capturer);
  286. bind(Foo.class).annotatedWith(named("pk")).toProvider(FooP.class);
  287. try {
  288. bind(Foo.class).annotatedWith(named("cxtr")).toConstructor(Foo.class.getDeclaredConstructor());
  289. } catch (Exception ex) {
  290. throw new RuntimeException(ex);
  291. }
  292. bind(LinkedFoo.class).to(Foo.class);
  293. bind(Interface.class).toInstance(new Implementation());
  294. bindConstant().annotatedWith(named("constant")).to("MyConstant");
  295. }
  296. @Provides @Named("pi") Foo provideFooBar() {
  297. return new Foo();
  298. }
  299. });
  300. // toInstance & constant bindings are notified in random order, at the very beginning.
  301. assertEquals(
  302. ImmutableSet.of(Key.get(Interface.class), Key.get(String.class, named("constant"))),
  303. capturer.getAsSetAndClear());
  304. // simple binding
  305. assertNotNull(injector.getInstance(Foo.class));
  306. assertEquals(of(Key.get(Foo.class)), capturer.getAndClear());
  307. // provider key binding -- notifies about provider & the object, always
  308. assertNotNull(injector.getInstance(Key.get(Foo.class, named("pk"))));
  309. assertEquals(of(Key.get(FooP.class), Key.get(Foo.class, named("pk"))), capturer.getAndClear());
  310. assertNotNull(injector.getInstance(Key.get(Foo.class, named("pk"))));
  311. assertEquals(of(Key.get(FooP.class), Key.get(Foo.class, named("pk"))), capturer.getAndClear());
  312. // JIT provider key binding -- notifies about provider & the object, always
  313. assertNotNull(injector.getInstance(JitFoo2.class));
  314. assertEquals(of(Key.get(JitFoo2P.class), Key.get(JitFoo2.class)), capturer.getAndClear());
  315. assertNotNull(injector.getInstance(JitFoo2.class));
  316. assertEquals(of(Key.get(JitFoo2P.class), Key.get(JitFoo2.class)), capturer.getAndClear());
  317. // provider instance binding -- just the object (not the provider)
  318. assertNotNull(injector.getInstance(Key.get(Foo.class, named("pi"))));
  319. assertEquals(of(Key.get(Foo.class, named("pi"))), capturer.getAndClear());
  320. // toConstructor binding
  321. assertNotNull(injector.getInstance(Key.get(Foo.class, named("cxtr"))));
  322. assertEquals(of(Key.get(Foo.class, named("cxtr"))), capturer.getAndClear());
  323. // linked binding -- notifies about the target (that's what's provisioned), not the link
  324. assertNotNull(injector.getInstance(LinkedFoo.class));
  325. assertEquals(of(Key.get(Foo.class)), capturer.getAndClear());
  326. // JIT linked binding -- notifies about the target (that's what's provisioned), not the link
  327. assertNotNull(injector.getInstance(JitFoo.class));
  328. assertEquals(of(Key.get(Foo.class)), capturer.getAndClear());
  329. }
  330. public void testSingletonMatcher() {
  331. final Counter counter = new Counter();
  332. Injector injector = Guice.createInjector(new AbstractModule() {
  333. @Override
  334. protected void configure() {
  335. bindListener(new AbstractMatcher<Binding<?>>() {
  336. @Override
  337. public boolean matches(Binding<?> t) {
  338. return Scopes.isSingleton(t);
  339. }
  340. }, counter);
  341. }
  342. });
  343. assertEquals(0, counter.count);
  344. // no increment for getting Many.
  345. injector.getInstance(Many.class);
  346. assertEquals(0, counter.count);
  347. // but an increment for getting Sole, since it's a singleton.
  348. injector.getInstance(Sole.class);
  349. assertEquals(1, counter.count);
  350. }
  351. public void testCallingBindingDotGetProviderDotGet() {
  352. Injector injector = Guice.createInjector(new AbstractModule() {
  353. @Override
  354. protected void configure() {
  355. bindListener(Matchers.any(), new ProvisionListener() {
  356. @Override
  357. public <T> void onProvision(ProvisionInvocation<T> provision) {
  358. provision.getBinding().getProvider().get(); // AGH!
  359. }
  360. });
  361. }
  362. });
  363. try {
  364. injector.getInstance(Sole.class);
  365. fail();
  366. } catch(ProvisionException expected) {
  367. // We don't really care what kind of error you get, we only care you get an error.
  368. }
  369. try {
  370. injector.getInstance(Many.class);
  371. fail();
  372. } catch(ProvisionException expected) {
  373. // We don't really care what kind of error you get, we only care you get an error.
  374. }
  375. }
  376. interface Interface {}
  377. class Implementation implements Interface {}
  378. @Singleton static class Sole {}
  379. static class Many {}
  380. @ImplementedBy(Foo.class) static interface JitFoo {}
  381. @ProvidedBy(JitFoo2P.class) static class JitFoo2 {}
  382. static interface LinkedFoo {}
  383. static class Foo implements JitFoo, LinkedFoo {}
  384. static class FooP implements Provider<Foo> {
  385. public Foo get() {
  386. return new Foo();
  387. }
  388. }
  389. static class JitFoo2P implements Provider<JitFoo2> {
  390. public JitFoo2 get() {
  391. return new JitFoo2();
  392. }
  393. }
  394. static class FooBomb {
  395. FooBomb() {
  396. throw new RuntimeException("Retry, Abort, Fail");
  397. }
  398. }
  399. static class DependsOnFooBombInField {
  400. @Inject FooBomb fooBomb;
  401. }
  402. static class DependsOnFooBombInCxtor {
  403. @Inject DependsOnFooBombInCxtor(FooBomb fooBomb) {}
  404. }
  405. private static class Counter implements ProvisionListener {
  406. int count = 0;
  407. public <T> void onProvision(ProvisionInvocation<T> provision) {
  408. count++;
  409. }
  410. }
  411. private static class CountAndCaptureExceptionListener implements ProvisionListener {
  412. int beforeProvision = 0;
  413. int afterProvision = 0;
  414. AtomicReference<RuntimeException> capture = new AtomicReference<RuntimeException>();
  415. public <T> void onProvision(ProvisionInvocation<T> provision) {
  416. beforeProvision++;
  417. try {
  418. provision.provision();
  419. } catch (RuntimeException re) {
  420. capture.set(re);
  421. throw re;
  422. }
  423. afterProvision++;
  424. }
  425. }
  426. private static class Capturer implements ProvisionListener {
  427. List<Key> keys = Lists.newArrayList();
  428. public <T> void onProvision(ProvisionInvocation<T> provision) {
  429. keys.add(provision.getBinding().getKey());
  430. T provisioned = provision.provision();
  431. // InstanceBindings are the only kind of binding where the key can
  432. // be an instanceof the provisioned, because it isn't linked to any
  433. // direct implementation. I guess maybe it'd also be possible
  434. // with a toConstructor binding... but we don't use that in our tests.
  435. if (provision.getBinding() instanceof InstanceBinding) {
  436. Class<? super T> expected = provision.getBinding().getKey().getRawType();
  437. assertTrue("expected instanceof: " + expected + ", but was: " + provisioned,
  438. expected.isInstance(provisioned));
  439. } else {
  440. assertEquals(provision.getBinding().getKey().getRawType(), provisioned.getClass());
  441. }
  442. }
  443. Set<Key> getAsSetAndClear() {
  444. Set<Key> copy = ImmutableSet.copyOf(keys);
  445. keys.clear();
  446. return copy;
  447. }
  448. List<Key> getAndClear() {
  449. List<Key> copy = ImmutableList.copyOf(keys);
  450. keys.clear();
  451. return copy;
  452. }
  453. }
  454. private static class FailBeforeProvision implements ProvisionListener {
  455. public <T> void onProvision(ProvisionInvocation<T> provision) {
  456. throw new RuntimeException("boo");
  457. }
  458. }
  459. private static class FailAfterProvision implements ProvisionListener {
  460. public <T> void onProvision(ProvisionInvocation<T> provision) {
  461. provision.provision();
  462. throw new RuntimeException("boo");
  463. }
  464. }
  465. private static class JustProvision implements ProvisionListener {
  466. public <T> void onProvision(ProvisionInvocation<T> provision) {
  467. provision.provision();
  468. }
  469. }
  470. private static class NoProvision implements ProvisionListener {
  471. public <T> void onProvision(ProvisionInvocation<T> provision) {
  472. }
  473. }
  474. private static class ProvisionTwice implements ProvisionListener {
  475. public <T> void onProvision(ProvisionInvocation<T> provision) {
  476. provision.provision();
  477. provision.provision();
  478. }
  479. }
  480. private static class ChainAsserter implements ProvisionListener {
  481. private final List<Class<?>> provisionList;
  482. private final List<Class<?>> expected;
  483. public ChainAsserter(List<Class<?>> provisionList, Iterable<Class<?>> expected) {
  484. this.provisionList = provisionList;
  485. this.expected = ImmutableList.copyOf(expected);
  486. }
  487. public <T> void onProvision(ProvisionInvocation<T> provision) {
  488. List<Class<?>> actual = Lists.newArrayList();
  489. for (DependencyAndSource dep : provision.getDependencyChain()) {
  490. actual.add(dep.getDependency().getKey().getRawType());
  491. }
  492. assertEquals(expected, actual);
  493. provisionList.add(provision.getBinding().getKey().getRawType());
  494. }
  495. }
  496. private static Matcher<Binding<?>> keyMatcher(final Class<?> clazz) {
  497. return new AbstractMatcher<Binding<?>>() {
  498. @Override
  499. public boolean matches(Binding<?> t) {
  500. return t.getKey().equals(Key.get(clazz));
  501. }
  502. };
  503. }
  504. @SuppressWarnings("unchecked")
  505. public void testDependencyChain() {
  506. final List<Class<?>> pList = Lists.newArrayList();
  507. final List<Class<?>> totalList = Lists.newArrayList();
  508. Injector injector = Guice.createInjector(new AbstractModule() {
  509. @Override
  510. protected void configure() {
  511. bind(Instance.class).toInstance(new Instance());
  512. bind(B.class).to(BImpl.class);
  513. bind(D.class).toProvider(DP.class);
  514. bindListener(Matchers.any(), new ProvisionListener() {
  515. public <T> void onProvision(ProvisionInvocation<T> provision) {
  516. totalList.add(provision.getBinding().getKey().getRawType());
  517. }
  518. });
  519. // Build up a list of asserters for our dependency chains.
  520. ImmutableList.Builder<Class<?>> chain = ImmutableList.builder();
  521. chain.add(Instance.class);
  522. bindListener(keyMatcher(Instance.class), new ChainAsserter(pList, chain.build()));
  523. chain.add(A.class);
  524. bindListener(keyMatcher(A.class), new ChainAsserter(pList, chain.build()));
  525. chain.add(B.class).add(BImpl.class);
  526. bindListener(keyMatcher(BImpl.class), new ChainAsserter(pList, chain.build()));
  527. chain.add(C.class);
  528. bindListener(keyMatcher(C.class), new ChainAsserter(pList, chain.build()));
  529. // the chain has D before DP even though DP is provisioned & notified first
  530. // because we do DP because of D, and need DP to provision D.
  531. chain.add(D.class).add(DP.class);
  532. bindListener(keyMatcher(D.class), new ChainAsserter(pList, chain.build()));
  533. bindListener(keyMatcher(DP.class), new ChainAsserter(pList, chain.build()));
  534. chain.add(E.class);
  535. bindListener(keyMatcher(E.class), new ChainAsserter(pList, chain.build()));
  536. chain.add(F.class);
  537. bindListener(keyMatcher(F.class), new ChainAsserter(pList, chain.build()));
  538. }
  539. @Provides C c(D d) {
  540. return new C() {};
  541. }
  542. });
  543. Instance instance = injector.getInstance(Instance.class);
  544. // make sure we're checking all of the chain asserters..
  545. assertEquals(
  546. of(Instance.class, A.class, BImpl.class, C.class, DP.class, D.class, E.class, F.class),
  547. pList);
  548. // and make sure that nothing else was notified that we didn't expect.
  549. assertEquals(totalList, pList);
  550. }
  551. public void testModuleRequestInjection() {
  552. final AtomicBoolean notified = new AtomicBoolean();
  553. Guice.createInjector(new AbstractModule() {
  554. @Override
  555. protected void configure() {
  556. requestInjection(new Object() {
  557. @Inject Foo foo;
  558. });
  559. bindListener(Matchers.any(),
  560. new SpecialChecker(Foo.class, getClass().getName() + ".configure(", notified));
  561. }
  562. });
  563. assertTrue(notified.get());
  564. }
  565. public void testToProviderInstance() {
  566. final AtomicBoolean notified = new AtomicBoolean();
  567. Guice.createInjector(new AbstractModule() {
  568. @Override
  569. protected void configure() {
  570. bind(Object.class).toProvider(new Provider<Object>() {
  571. @Inject Foo foo;
  572. public Object get() {
  573. return null;
  574. }
  575. });
  576. bindListener(Matchers.any(),
  577. new SpecialChecker(Foo.class, getClass().getName() + ".configure(", notified));
  578. }
  579. });
  580. assertTrue(notified.get());
  581. }
  582. public void testInjectorInjectMembers() {
  583. final Object object = new Object() {
  584. @Inject Foo foo;
  585. };
  586. final AtomicBoolean notified = new AtomicBoolean();
  587. Guice.createInjector(new AbstractModule() {
  588. @Override
  589. protected void configure() {
  590. bindListener(Matchers.any(),
  591. new SpecialChecker(Foo.class, object.getClass().getName(), notified));
  592. }
  593. }).injectMembers(object);
  594. assertTrue(notified.get());
  595. }
  596. private static class SpecialChecker implements ProvisionListener {
  597. private final Class<?> notifyType;
  598. private final String firstSource;
  599. private final AtomicBoolean notified;
  600. public SpecialChecker(Class<?> notifyType, String firstSource, AtomicBoolean notified) {
  601. this.notifyType = notifyType;
  602. this.firstSource = firstSource;
  603. this.notified = notified;
  604. }
  605. public <T> void onProvision(ProvisionInvocation<T> provision) {
  606. notified.set(true);
  607. assertEquals(notifyType, provision.getBinding().getKey().getRawType());
  608. assertEquals(2, provision.getDependencyChain().size());
  609. assertNull(provision.getDependencyChain().get(0).getDependency());
  610. assertContains(provision.getDependencyChain().get(0).getBindingSource(), firstSource);
  611. assertEquals(notifyType,
  612. provision.getDependencyChain().get(1).getDependency().getKey().getRawType());
  613. assertContains(provision.getDependencyChain().get(1).getBindingSource(),
  614. notifyType.getName() + ".class(");
  615. }
  616. }
  617. private static class Instance {
  618. @Inject A a;
  619. }
  620. private static class A {
  621. @Inject A(B b) {}
  622. }
  623. private interface B {}
  624. private static class BImpl implements B {
  625. @Inject void inject(C c) {}
  626. }
  627. private interface C {}
  628. private interface D {}
  629. private static class DP implements Provider<D> {
  630. @Inject Provider<E> ep;
  631. public D get() {
  632. ep.get();
  633. return new D() {};
  634. }
  635. }
  636. private static class E {
  637. @SuppressWarnings("unused")
  638. @Inject F f;
  639. }
  640. private static class F {
  641. }
  642. public void testBindToInjectorWithListeningGivesSaneException() {
  643. try {
  644. Guice.createInjector(new AbstractModule() {
  645. @Override
  646. protected void configure() {
  647. bindListener(Matchers.any(), new Counter());
  648. bind(Injector.class).toProvider(Providers.<Injector>of(null));
  649. }
  650. });
  651. fail();
  652. } catch (CreationException ce) {
  653. assertContains(
  654. ce.getMessage(), "Binding to core guice framework type is not allowed: Injector.");
  655. }
  656. }
  657. public void testProvisionIsNotifiedAfterContextsClear() {
  658. Injector injector = Guice.createInjector(new AbstractModule() {
  659. @Override
  660. protected void configure() {
  661. bindListener(Matchers.any(), new ProvisionListener() {
  662. @Override
  663. public <T> void onProvision(ProvisionInvocation<T> provision) {
  664. Object provisioned = provision.provision();
  665. if (provisioned instanceof X) {
  666. ((X)provisioned).init();
  667. } else if (provisioned instanceof Y) {
  668. X.createY = false;
  669. ((Y)provisioned).init();
  670. }
  671. }
  672. });
  673. }
  674. });
  675. X.createY = true;
  676. X x = injector.getInstance(X.class);
  677. assertNotSame(x, x.y.x);
  678. assertFalse("x.ID: " + x.ID + ", x.y.x.iD: " + x.y.x.ID, x.ID == x.y.x.ID);
  679. }
  680. private static class X {
  681. final static AtomicInteger COUNTER = new AtomicInteger();
  682. static boolean createY;
  683. final int ID = COUNTER.getAndIncrement();
  684. final Provider<Y> yProvider;
  685. Y y;
  686. @Inject X(Provider<Y> yProvider) {
  687. this.yProvider = yProvider;
  688. }
  689. void init() {
  690. if (createY) {
  691. this.y = yProvider.get();
  692. }
  693. }
  694. }
  695. private static class Y {
  696. final Provider<X> xProvider;
  697. X x;
  698. @Inject Y(Provider<X> xProvider) {
  699. this.xProvider = xProvider;
  700. }
  701. void init() {
  702. this.x = xProvider.get();
  703. }
  704. }
  705. public void testDeDuplicateProvisionListeners() {
  706. final Counter counter = new Counter();
  707. Injector injector = Guice.createInjector(new AbstractModule() {
  708. @Override
  709. protected void configure() {
  710. bindListener(Matchers.any(), counter);
  711. bindListener(Matchers.any(), counter);
  712. }
  713. });
  714. injector.getInstance(Many.class);
  715. assertEquals("ProvisionListener not de-duplicated", 1, counter.count);
  716. }
  717. }