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

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

https://gitlab.com/metamorphiccode/guice
Java | 769 lines | 646 code | 102 blank | 21 comment | 21 complexity | 4700ecd1bd8c88e70e8e39e21224fdcd MD5 | raw file
  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;
  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.ElementType.TYPE;
  21. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  22. import com.google.common.collect.ImmutableList;
  23. import com.google.common.collect.Lists;
  24. import com.google.inject.binder.AnnotatedBindingBuilder;
  25. import com.google.inject.binder.ScopedBindingBuilder;
  26. import com.google.inject.name.Named;
  27. import com.google.inject.util.Providers;
  28. import junit.framework.Test;
  29. import junit.framework.TestCase;
  30. import junit.framework.TestSuite;
  31. import java.lang.annotation.Retention;
  32. import java.lang.annotation.Target;
  33. import java.util.Collections;
  34. import java.util.List;
  35. import java.util.concurrent.atomic.AtomicInteger;
  36. /**
  37. * @author jessewilson@google.com (Jesse Wilson)
  38. */
  39. public class BinderTestSuite extends TestCase {
  40. public static Test suite() {
  41. TestSuite suite = new TestSuite();
  42. new Builder()
  43. .name("bind A")
  44. .module(new AbstractModule() {
  45. protected void configure() {
  46. bind(A.class);
  47. }
  48. })
  49. .creationException("No implementation for %s was bound", A.class.getName())
  50. .addToSuite(suite);
  51. new Builder()
  52. .name("bind PlainA named apple")
  53. .module(new AbstractModule() {
  54. protected void configure() {
  55. bind(PlainA.class).annotatedWith(named("apple"));
  56. }
  57. })
  58. .creationException("No implementation for %s annotated with %s was bound",
  59. PlainA.class.getName(), named("apple"))
  60. .addToSuite(suite);
  61. new Builder()
  62. .name("bind A to new PlainA(1)")
  63. .module(new AbstractModule() {
  64. protected void configure() {
  65. bind(A.class).toInstance(new PlainA(1));
  66. }
  67. })
  68. .creationTime(CreationTime.NONE)
  69. .expectedValues(new PlainA(1), new PlainA(1), new PlainA(1))
  70. .addToSuite(suite);
  71. new Builder()
  72. .name("no binding, AWithProvidedBy")
  73. .key(Key.get(AWithProvidedBy.class), InjectsAWithProvidedBy.class)
  74. .addToSuite(suite);
  75. new Builder()
  76. .name("no binding, AWithImplementedBy")
  77. .key(Key.get(AWithImplementedBy.class), InjectsAWithImplementedBy.class)
  78. .addToSuite(suite);
  79. new Builder()
  80. .name("no binding, ScopedA")
  81. .key(Key.get(ScopedA.class), InjectsScopedA.class)
  82. .expectedValues(new PlainA(201), new PlainA(201), new PlainA(202), new PlainA(202))
  83. .addToSuite(suite);
  84. new Builder()
  85. .name("no binding, AWithProvidedBy named apple")
  86. .key(Key.get(AWithProvidedBy.class, named("apple")),
  87. InjectsAWithProvidedByNamedApple.class)
  88. .configurationException("No implementation for %s annotated with %s was bound",
  89. AWithProvidedBy.class.getName(), named("apple"))
  90. .addToSuite(suite);
  91. new Builder()
  92. .name("no binding, AWithImplementedBy named apple")
  93. .key(Key.get(AWithImplementedBy.class, named("apple")),
  94. InjectsAWithImplementedByNamedApple.class)
  95. .configurationException("No implementation for %s annotated with %s was bound",
  96. AWithImplementedBy.class.getName(), named("apple"))
  97. .addToSuite(suite);
  98. new Builder()
  99. .name("no binding, ScopedA named apple")
  100. .key(Key.get(ScopedA.class, named("apple")), InjectsScopedANamedApple.class)
  101. .configurationException("No implementation for %s annotated with %s was bound",
  102. ScopedA.class.getName(), named("apple"))
  103. .addToSuite(suite);
  104. for (final Scoper scoper : Scoper.values()) {
  105. new Builder()
  106. .name("bind PlainA")
  107. .key(Key.get(PlainA.class), InjectsPlainA.class)
  108. .module(new AbstractModule() {
  109. protected void configure() {
  110. AnnotatedBindingBuilder<PlainA> abb = bind(PlainA.class);
  111. scoper.configure(abb);
  112. }
  113. })
  114. .scoper(scoper)
  115. .addToSuite(suite);
  116. new Builder()
  117. .name("bind A to PlainA")
  118. .module(new AbstractModule() {
  119. protected void configure() {
  120. ScopedBindingBuilder sbb = bind(A.class).to(PlainA.class);
  121. scoper.configure(sbb);
  122. }
  123. })
  124. .scoper(scoper)
  125. .addToSuite(suite);
  126. new Builder()
  127. .name("bind A to PlainAProvider.class")
  128. .module(new AbstractModule() {
  129. protected void configure() {
  130. ScopedBindingBuilder sbb = bind(A.class).toProvider(PlainAProvider.class);
  131. scoper.configure(sbb);
  132. }
  133. })
  134. .scoper(scoper)
  135. .addToSuite(suite);
  136. new Builder()
  137. .name("bind A to new PlainAProvider()")
  138. .module(new AbstractModule() {
  139. protected void configure() {
  140. ScopedBindingBuilder sbb = bind(A.class).toProvider(new PlainAProvider());
  141. scoper.configure(sbb);
  142. }
  143. })
  144. .scoper(scoper)
  145. .addToSuite(suite);
  146. new Builder()
  147. .name("bind AWithProvidedBy")
  148. .key(Key.get(AWithProvidedBy.class), InjectsAWithProvidedBy.class)
  149. .module(new AbstractModule() {
  150. protected void configure() {
  151. ScopedBindingBuilder sbb = bind(AWithProvidedBy.class);
  152. scoper.configure(sbb);
  153. }
  154. })
  155. .scoper(scoper)
  156. .addToSuite(suite);
  157. new Builder()
  158. .name("bind AWithImplementedBy")
  159. .key(Key.get(AWithImplementedBy.class), InjectsAWithImplementedBy.class)
  160. .module(new AbstractModule() {
  161. protected void configure() {
  162. ScopedBindingBuilder sbb = bind(AWithImplementedBy.class);
  163. scoper.configure(sbb);
  164. }
  165. })
  166. .scoper(scoper)
  167. .addToSuite(suite);
  168. new Builder()
  169. .name("bind ScopedA")
  170. .key(Key.get(ScopedA.class), InjectsScopedA.class)
  171. .module(new AbstractModule() {
  172. protected void configure() {
  173. ScopedBindingBuilder sbb = bind(ScopedA.class);
  174. scoper.configure(sbb);
  175. }
  176. })
  177. .expectedValues(new PlainA(201), new PlainA(201), new PlainA(202), new PlainA(202))
  178. .scoper(scoper)
  179. .addToSuite(suite);
  180. new Builder()
  181. .name("bind AWithProvidedBy named apple")
  182. .module(new AbstractModule() {
  183. protected void configure() {
  184. scoper.configure(bind(AWithProvidedBy.class).annotatedWith(named("apple")));
  185. }
  186. })
  187. .creationException("No implementation for %s annotated with %s was bound",
  188. AWithProvidedBy.class.getName(), named("apple"))
  189. .addToSuite(suite);
  190. new Builder()
  191. .name("bind AWithImplementedBy named apple")
  192. .module(new AbstractModule() {
  193. protected void configure() {
  194. scoper.configure(bind(AWithImplementedBy.class).annotatedWith(named("apple")));
  195. }
  196. })
  197. .creationException("No implementation for %s annotated with %s was bound",
  198. AWithImplementedBy.class.getName(), named("apple"))
  199. .addToSuite(suite);
  200. new Builder()
  201. .name("bind ScopedA named apple")
  202. .module(new AbstractModule() {
  203. protected void configure() {
  204. scoper.configure(bind(ScopedA.class).annotatedWith(named("apple")));
  205. }
  206. })
  207. .creationException("No implementation for %s annotated with %s was bound",
  208. ScopedA.class.getName(), named("apple"))
  209. .addToSuite(suite);
  210. }
  211. return suite;
  212. }
  213. enum Scoper {
  214. UNSCOPED {
  215. void configure(ScopedBindingBuilder sbb) {}
  216. void apply(Builder builder) {}
  217. },
  218. EAGER_SINGLETON {
  219. void configure(ScopedBindingBuilder sbb) {
  220. sbb.asEagerSingleton();
  221. }
  222. void apply(Builder builder) {
  223. builder.expectedValues(new PlainA(101), new PlainA(101), new PlainA(101));
  224. builder.creationTime(CreationTime.EAGER);
  225. }
  226. },
  227. SCOPES_SINGLETON {
  228. void configure(ScopedBindingBuilder sbb) {
  229. sbb.in(Scopes.SINGLETON);
  230. }
  231. void apply(Builder builder) {
  232. builder.expectedValues(new PlainA(201), new PlainA(201), new PlainA(201));
  233. }
  234. },
  235. SINGLETON_DOT_CLASS {
  236. void configure(ScopedBindingBuilder sbb) {
  237. sbb.in(Singleton.class);
  238. }
  239. void apply(Builder builder) {
  240. builder.expectedValues(new PlainA(201), new PlainA(201), new PlainA(201));
  241. }
  242. },
  243. TWO_AT_A_TIME_SCOPED_DOT_CLASS {
  244. void configure(ScopedBindingBuilder sbb) {
  245. sbb.in(TwoAtATimeScoped.class);
  246. }
  247. void apply(Builder builder) {
  248. builder.expectedValues(new PlainA(201), new PlainA(201), new PlainA(202), new PlainA(202));
  249. }
  250. },
  251. TWO_AT_A_TIME_SCOPE {
  252. void configure(ScopedBindingBuilder sbb) {
  253. sbb.in(new TwoAtATimeScope());
  254. }
  255. void apply(Builder builder) {
  256. builder.expectedValues(new PlainA(201), new PlainA(201), new PlainA(202), new PlainA(202));
  257. }
  258. };
  259. abstract void configure(ScopedBindingBuilder sbb);
  260. abstract void apply(Builder builder);
  261. }
  262. /** When Guice creates a value, directly or via a provider */
  263. enum CreationTime {
  264. NONE, EAGER, LAZY
  265. }
  266. public static class Builder {
  267. private String name = "test";
  268. private Key<?> key = Key.get(A.class);
  269. private Class<? extends Injectable> injectsKey = InjectsA.class;
  270. private List<Module> modules = Lists.<Module>newArrayList(new AbstractModule() {
  271. protected void configure() {
  272. bindScope(TwoAtATimeScoped.class, new TwoAtATimeScope());
  273. }
  274. });
  275. private List<Object> expectedValues = Lists.<Object>newArrayList(
  276. new PlainA(201), new PlainA(202), new PlainA(203));
  277. private CreationTime creationTime = CreationTime.LAZY;
  278. private String creationException;
  279. private String configurationException;
  280. public Builder module(Module module) {
  281. this.modules.add(module);
  282. return this;
  283. }
  284. public Builder creationTime(CreationTime creationTime) {
  285. this.creationTime = creationTime;
  286. return this;
  287. }
  288. public Builder name(String name) {
  289. this.name = name;
  290. return this;
  291. }
  292. public Builder key(Key<?> key, Class<? extends Injectable> injectsKey) {
  293. this.key = key;
  294. this.injectsKey = injectsKey;
  295. return this;
  296. }
  297. private Builder creationException(String message, Object... args) {
  298. this.creationException = String.format(message, args);
  299. return this;
  300. }
  301. private Builder configurationException(String message, Object... args) {
  302. configurationException = String.format(message, args);
  303. return this;
  304. }
  305. private Builder scoper(Scoper scoper) {
  306. name(name + " in " + scoper);
  307. scoper.apply(this);
  308. return this;
  309. }
  310. private <T> Builder expectedValues(T... values) {
  311. this.expectedValues.clear();
  312. Collections.addAll(this.expectedValues, values);
  313. return this;
  314. }
  315. public void addToSuite(TestSuite suite) {
  316. if (creationException != null) {
  317. suite.addTest(new CreationExceptionTest(this));
  318. } else if (configurationException != null) {
  319. suite.addTest(new ConfigurationExceptionTest(this));
  320. } else {
  321. suite.addTest(new SuccessTest(this));
  322. if (creationTime != CreationTime.NONE) {
  323. suite.addTest(new UserExceptionsTest(this));
  324. }
  325. }
  326. }
  327. }
  328. public static class SuccessTest extends TestCase {
  329. final String name;
  330. final Key<?> key;
  331. final Class<? extends Injectable> injectsKey;
  332. final ImmutableList<Module> modules;
  333. final ImmutableList<Object> expectedValues;
  334. public SuccessTest(Builder builder) {
  335. super("test");
  336. name = builder.name;
  337. key = builder.key;
  338. injectsKey = builder.injectsKey;
  339. modules = ImmutableList.copyOf(builder.modules);
  340. expectedValues = ImmutableList.copyOf(builder.expectedValues);
  341. }
  342. public String getName() {
  343. return name;
  344. }
  345. Injector newInjector() {
  346. nextId.set(101);
  347. return Guice.createInjector(modules);
  348. }
  349. public void test() throws IllegalAccessException, InstantiationException {
  350. Injector injector = newInjector();
  351. nextId.set(201);
  352. for (Object value : expectedValues) {
  353. assertEquals(value, injector.getInstance(key));
  354. }
  355. Provider<?> provider = newInjector().getProvider(key);
  356. nextId.set(201);
  357. for (Object value : expectedValues) {
  358. assertEquals(value, provider.get());
  359. }
  360. Provider<?> bindingProvider = newInjector().getBinding(key).getProvider();
  361. nextId.set(201);
  362. for (Object value : expectedValues) {
  363. assertEquals(value, bindingProvider.get());
  364. }
  365. injector = newInjector();
  366. nextId.set(201);
  367. for (Object value : expectedValues) {
  368. Injectable instance = injector.getInstance(injectsKey);
  369. assertEquals(value, instance.value);
  370. }
  371. injector = newInjector();
  372. nextId.set(201);
  373. for (Object value : expectedValues) {
  374. Injectable injectable = injectsKey.newInstance();
  375. injector.injectMembers(injectable);
  376. assertEquals(value, injectable.value);
  377. }
  378. Injector injector1 = newInjector();
  379. nextId.set(201);
  380. Injectable hasProvider = injector1.getInstance(injectsKey);
  381. hasProvider.provider.get();
  382. nextId.set(201);
  383. for (Object value : expectedValues) {
  384. assertEquals(value, hasProvider.provider.get());
  385. }
  386. }
  387. }
  388. public static class CreationExceptionTest extends TestCase {
  389. final String name;
  390. final Key<?> key;
  391. final ImmutableList<Module> modules;
  392. final String creationException;
  393. public CreationExceptionTest(Builder builder) {
  394. super("test");
  395. name = builder.name;
  396. key = builder.key;
  397. modules = ImmutableList.copyOf(builder.modules);
  398. creationException = builder.creationException;
  399. }
  400. public String getName() {
  401. return "creation errors:" + name;
  402. }
  403. public void test() {
  404. try {
  405. Guice.createInjector(modules);
  406. fail();
  407. } catch (CreationException expected) {
  408. assertContains(expected.getMessage(), creationException);
  409. }
  410. }
  411. }
  412. public static class ConfigurationExceptionTest extends TestCase {
  413. final String name;
  414. final Key<?> key;
  415. final Class<? extends Injectable> injectsKey;
  416. final ImmutableList<Module> modules;
  417. final String configurationException;
  418. public ConfigurationExceptionTest(Builder builder) {
  419. super("test");
  420. name = builder.name;
  421. key = builder.key;
  422. injectsKey = builder.injectsKey;
  423. modules = ImmutableList.copyOf(builder.modules);
  424. configurationException = builder.configurationException;
  425. }
  426. public String getName() {
  427. return "provision errors:" + name;
  428. }
  429. Injector newInjector() {
  430. return Guice.createInjector(modules);
  431. }
  432. public void test() throws IllegalAccessException, InstantiationException {
  433. try {
  434. newInjector().getProvider(key);
  435. fail();
  436. } catch (ConfigurationException expected) {
  437. assertContains(expected.getMessage(), configurationException);
  438. }
  439. try {
  440. newInjector().getBinding(key).getProvider();
  441. fail();
  442. } catch (ConfigurationException expected) {
  443. assertContains(expected.getMessage(), configurationException);
  444. }
  445. try {
  446. newInjector().getInstance(key);
  447. fail();
  448. } catch (ConfigurationException expected) {
  449. assertContains(expected.getMessage(), configurationException);
  450. }
  451. try {
  452. newInjector().getInstance(injectsKey);
  453. fail();
  454. } catch (ConfigurationException expected) {
  455. assertContains(expected.getMessage(),
  456. configurationException, injectsKey.getName() + ".inject",
  457. configurationException, injectsKey.getName() + ".inject",
  458. "2 errors");
  459. }
  460. try {
  461. Injectable injectable = injectsKey.newInstance();
  462. newInjector().injectMembers(injectable);
  463. fail();
  464. } catch (ConfigurationException expected) {
  465. assertContains(expected.getMessage(),
  466. configurationException, injectsKey.getName() + ".inject",
  467. configurationException, injectsKey.getName() + ".inject",
  468. "2 errors");
  469. }
  470. }
  471. }
  472. public static class UserExceptionsTest extends TestCase {
  473. final String name;
  474. final Key<?> key;
  475. final Class<? extends Injectable> injectsKey;
  476. final ImmutableList<Module> modules;
  477. final ImmutableList<Object> expectedValues;
  478. final CreationTime creationTime;
  479. public UserExceptionsTest(Builder builder) {
  480. super("test");
  481. name = builder.name;
  482. key = builder.key;
  483. injectsKey = builder.injectsKey;
  484. modules = ImmutableList.copyOf(builder.modules);
  485. expectedValues = ImmutableList.copyOf(builder.expectedValues);
  486. creationTime = builder.creationTime;
  487. }
  488. public String getName() {
  489. return "provision errors:" + name;
  490. }
  491. Injector newInjector() {
  492. return Guice.createInjector(modules);
  493. }
  494. public void test() throws IllegalAccessException, InstantiationException {
  495. nextId.set(-1);
  496. try {
  497. newInjector();
  498. assertEquals(CreationTime.LAZY, creationTime);
  499. } catch (CreationException expected) {
  500. assertEquals(CreationTime.EAGER, creationTime);
  501. assertContains(expected.getMessage(), "Illegal value: -1");
  502. return;
  503. }
  504. Provider<?> provider = newInjector().getProvider(key);
  505. Provider<?> bindingProvider = newInjector().getBinding(key).getProvider();
  506. nextId.set(-1);
  507. try {
  508. newInjector().getInstance(key);
  509. fail();
  510. } catch (ProvisionException expected) {
  511. assertContains(expected.getMessage(), "Illegal value: -1");
  512. }
  513. nextId.set(-1);
  514. try {
  515. provider.get();
  516. fail();
  517. } catch (ProvisionException expected) {
  518. assertContains(expected.getMessage(), "Illegal value: -1");
  519. }
  520. nextId.set(-1);
  521. try {
  522. bindingProvider.get();
  523. fail();
  524. } catch (ProvisionException expected) {
  525. assertContains(expected.getMessage(), "Illegal value: -1");
  526. }
  527. try {
  528. nextId.set(-1);
  529. newInjector().getInstance(injectsKey);
  530. } catch (ProvisionException expected) {
  531. assertContains(expected.getMessage(), "Illegal value: -1",
  532. "for parameter 0 at " + injectsKey.getName() + ".inject");
  533. }
  534. nextId.set(201);
  535. Injectable injectable = injectsKey.newInstance();
  536. try {
  537. nextId.set(-1);
  538. newInjector().injectMembers(injectable);
  539. } catch (ProvisionException expected) {
  540. assertContains(expected.getMessage(), "Illegal value: -1",
  541. "for parameter 0 at " + injectsKey.getName() + ".inject");
  542. }
  543. nextId.set(201);
  544. Injectable hasProvider = newInjector().getInstance(injectsKey);
  545. hasProvider.provider.get();
  546. try {
  547. nextId.set(-1);
  548. hasProvider.provider.get();
  549. } catch (ProvisionException expected) {
  550. assertContains(expected.getMessage(), "Illegal value: -1");
  551. }
  552. }
  553. }
  554. /** negative to throw, 101... for eager singletons, 201... for everything else */
  555. static final AtomicInteger nextId = new AtomicInteger();
  556. @ProvidedBy(PlainAProvider.class)
  557. interface AWithProvidedBy {}
  558. static class InjectsAWithProvidedBy extends Injectable {
  559. @Inject public void inject(AWithProvidedBy aWithProvidedBy,
  560. Provider<AWithProvidedBy> aWithProvidedByProvider) {
  561. this.value = aWithProvidedBy;
  562. this.provider = aWithProvidedByProvider;
  563. }
  564. }
  565. static class InjectsAWithProvidedByNamedApple extends Injectable {
  566. @Inject public void inject(@Named("apple") AWithProvidedBy aWithProvidedBy,
  567. @Named("apple") Provider<AWithProvidedBy> aWithProvidedByProvider) {
  568. this.value = aWithProvidedBy;
  569. this.provider = aWithProvidedByProvider;
  570. }
  571. }
  572. @ImplementedBy(PlainA.class)
  573. interface AWithImplementedBy {}
  574. static class InjectsAWithImplementedBy extends Injectable {
  575. @Inject public void inject(AWithImplementedBy aWithImplementedBy,
  576. Provider<AWithImplementedBy> aWithImplementedByProvider) {
  577. this.value = aWithImplementedBy;
  578. this.provider = aWithImplementedByProvider;
  579. }
  580. }
  581. static class InjectsAWithImplementedByNamedApple extends Injectable {
  582. @Inject public void inject(@Named("apple") AWithImplementedBy aWithImplementedBy,
  583. @Named("apple") Provider<AWithImplementedBy> aWithImplementedByProvider) {
  584. this.value = aWithImplementedBy;
  585. this.provider = aWithImplementedByProvider;
  586. }
  587. }
  588. interface A extends AWithProvidedBy, AWithImplementedBy {}
  589. static class InjectsA extends Injectable {
  590. @Inject public void inject(A a, Provider<A> aProvider) {
  591. this.value = a;
  592. this.provider = aProvider;
  593. }
  594. }
  595. static class PlainA implements A {
  596. final int value;
  597. PlainA() {
  598. value = nextId.getAndIncrement();
  599. if (value < 0) {
  600. throw new RuntimeException("Illegal value: " + value);
  601. }
  602. }
  603. PlainA(int value) {
  604. this.value = value;
  605. }
  606. public boolean equals(Object obj) {
  607. return obj instanceof PlainA
  608. && value == ((PlainA) obj).value;
  609. }
  610. public int hashCode() {
  611. return value;
  612. }
  613. public String toString() {
  614. return "PlainA#" + value;
  615. }
  616. }
  617. static class PlainAProvider implements Provider<A> {
  618. public A get() {
  619. return new PlainA();
  620. }
  621. }
  622. static class InjectsPlainA extends Injectable {
  623. @Inject public void inject(PlainA plainA, Provider<PlainA> plainAProvider) {
  624. this.value = plainA;
  625. this.provider = plainAProvider;
  626. }
  627. }
  628. /** This scope hands out each value exactly twice */
  629. static class TwoAtATimeScope implements Scope {
  630. public <T> Provider<T> scope(Key<T> key, final Provider<T> unscoped) {
  631. return new Provider<T>() {
  632. T instance;
  633. public T get() {
  634. if (instance == null) {
  635. instance = unscoped.get();
  636. return instance;
  637. } else {
  638. T result = instance;
  639. instance = null;
  640. return result;
  641. }
  642. }
  643. };
  644. }
  645. }
  646. @Target({ TYPE, METHOD }) @Retention(RUNTIME) @ScopeAnnotation
  647. public @interface TwoAtATimeScoped {}
  648. @TwoAtATimeScoped
  649. static class ScopedA extends PlainA {}
  650. static class InjectsScopedA extends Injectable {
  651. @Inject public void inject(ScopedA scopedA, Provider<ScopedA> scopedAProvider) {
  652. this.value = scopedA;
  653. this.provider = scopedAProvider;
  654. }
  655. }
  656. static class InjectsScopedANamedApple extends Injectable {
  657. @Inject public void inject(@Named("apple") ScopedA scopedA,
  658. @Named("apple") Provider<ScopedA> scopedAProvider) {
  659. this.value = scopedA;
  660. this.provider = scopedAProvider;
  661. }
  662. }
  663. static class Injectable {
  664. Object value = new Object();
  665. Provider<?> provider = Providers.of(new Object());
  666. }
  667. }