1 /*
2  * Copyright (C) 2006 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 
17 package com.google.inject;
18 
19 import static com.google.inject.Asserts.asModuleChain;
20 import static com.google.inject.Asserts.assertContains;
21 import static com.google.inject.Asserts.getDeclaringSourcePart;
22 import static com.google.inject.name.Names.named;
23 import static java.lang.annotation.RetentionPolicy.RUNTIME;
24 
25 import com.google.common.base.Joiner;
26 import com.google.common.collect.ArrayListMultimap;
27 import com.google.common.collect.ImmutableList;
28 import com.google.common.collect.ImmutableMap;
29 import com.google.common.collect.ListMultimap;
30 import com.google.common.collect.Maps;
31 import com.google.inject.matcher.Matchers;
32 import com.google.inject.name.Named;
33 import com.google.inject.spi.DefaultBindingScopingVisitor;
34 import com.google.inject.spi.Element;
35 import com.google.inject.spi.Elements;
36 import com.google.inject.spi.Message;
37 import com.google.inject.spi.PrivateElements;
38 import com.google.inject.spi.ProvisionListener;
39 import com.google.inject.util.Providers;
40 import java.io.IOException;
41 import java.lang.annotation.ElementType;
42 import java.lang.annotation.Retention;
43 import java.lang.annotation.Target;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Iterator;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.concurrent.Callable;
50 import java.util.concurrent.CyclicBarrier;
51 import java.util.concurrent.ExecutionException;
52 import java.util.concurrent.Executors;
53 import java.util.concurrent.Future;
54 import java.util.concurrent.FutureTask;
55 import java.util.concurrent.TimeUnit;
56 import junit.framework.TestCase;
57 
58 /** @author crazybob@google.com (Bob Lee) */
59 public class ScopesTest extends TestCase {
60 
61   static final long DEADLOCK_TIMEOUT_SECONDS = 1;
62 
63   private final AbstractModule singletonsModule =
64       new AbstractModule() {
65         @Override
66         protected void configure() {
67           bind(BoundAsSingleton.class).in(Scopes.SINGLETON);
68           bind(AnnotatedSingleton.class);
69           bind(EagerSingleton.class).asEagerSingleton();
70           bind(LinkedSingleton.class).to(RealLinkedSingleton.class);
71           bind(DependsOnJustInTimeSingleton.class);
72           bind(NotASingleton.class);
73           bind(ImplementedBySingleton.class).in(Scopes.SINGLETON);
74           bind(ProvidedBySingleton.class).in(Scopes.SINGLETON);
75         }
76       };
77 
78   @Override
setUp()79   protected void setUp() throws Exception {
80     AnnotatedSingleton.nextInstanceId = 0;
81     BoundAsSingleton.nextInstanceId = 0;
82     EagerSingleton.nextInstanceId = 0;
83     RealLinkedSingleton.nextInstanceId = 0;
84     JustInTimeSingleton.nextInstanceId = 0;
85     NotASingleton.nextInstanceId = 0;
86     Implementation.nextInstanceId = 0;
87     ProvidedBySingleton.nextInstanceId = 0;
88     ThrowingSingleton.nextInstanceId = 0;
89   }
90 
testSingletons()91   public void testSingletons() {
92     Injector injector = Guice.createInjector(singletonsModule);
93 
94     assertSame(
95         injector.getInstance(BoundAsSingleton.class), injector.getInstance(BoundAsSingleton.class));
96 
97     assertSame(
98         injector.getInstance(AnnotatedSingleton.class),
99         injector.getInstance(AnnotatedSingleton.class));
100 
101     assertSame(
102         injector.getInstance(EagerSingleton.class), injector.getInstance(EagerSingleton.class));
103 
104     assertSame(
105         injector.getInstance(LinkedSingleton.class), injector.getInstance(LinkedSingleton.class));
106 
107     assertSame(
108         injector.getInstance(JustInTimeSingleton.class),
109         injector.getInstance(JustInTimeSingleton.class));
110 
111     assertNotSame(
112         injector.getInstance(NotASingleton.class), injector.getInstance(NotASingleton.class));
113 
114     assertSame(
115         injector.getInstance(ImplementedBySingleton.class),
116         injector.getInstance(ImplementedBySingleton.class));
117 
118     assertSame(
119         injector.getInstance(ProvidedBySingleton.class),
120         injector.getInstance(ProvidedBySingleton.class));
121   }
122 
testJustInTimeAnnotatedSingleton()123   public void testJustInTimeAnnotatedSingleton() {
124     Injector injector = Guice.createInjector();
125 
126     assertSame(
127         injector.getInstance(AnnotatedSingleton.class),
128         injector.getInstance(AnnotatedSingleton.class));
129   }
130 
testSingletonIsPerInjector()131   public void testSingletonIsPerInjector() {
132     assertNotSame(
133         Guice.createInjector().getInstance(AnnotatedSingleton.class),
134         Guice.createInjector().getInstance(AnnotatedSingleton.class));
135   }
136 
testOverriddingAnnotation()137   public void testOverriddingAnnotation() {
138     Injector injector =
139         Guice.createInjector(
140             new AbstractModule() {
141               @Override
142               protected void configure() {
143                 bind(AnnotatedSingleton.class).in(Scopes.NO_SCOPE);
144               }
145             });
146 
147     assertNotSame(
148         injector.getInstance(AnnotatedSingleton.class),
149         injector.getInstance(AnnotatedSingleton.class));
150   }
151 
testScopingAnnotationsOnAbstractTypeViaBind()152   public void testScopingAnnotationsOnAbstractTypeViaBind() {
153     try {
154       Guice.createInjector(
155           new AbstractModule() {
156             @Override
157             protected void configure() {
158               bind(A.class).to(AImpl.class);
159             }
160           });
161       fail();
162     } catch (CreationException expected) {
163       assertContains(
164           expected.getMessage(),
165           A.class.getName() + " is annotated with " + Singleton.class.getName(),
166           "but scope annotations are not supported for abstract types.",
167           "at " + A.class.getName() + ".class(ScopesTest.java:");
168     }
169   }
170 
171   @Singleton
172   interface A {}
173 
174   static class AImpl implements A {}
175 
176   @Retention(RUNTIME)
177   @interface Component {}
178 
179   @Component
180   @Singleton
181   interface ComponentAnnotationTest {}
182 
183   static class ComponentAnnotationTestImpl implements ComponentAnnotationTest {}
184 
testScopingAnnotationsOnAbstractTypeIsValidForComponent()185   public void testScopingAnnotationsOnAbstractTypeIsValidForComponent() {
186     Guice.createInjector(
187         new AbstractModule() {
188           @Override
189           protected void configure() {
190             bind(ComponentAnnotationTest.class).to(ComponentAnnotationTestImpl.class);
191           }
192         });
193   }
194 
testScopingAnnotationsOnAbstractTypeViaImplementedBy()195   public void testScopingAnnotationsOnAbstractTypeViaImplementedBy() {
196     try {
197       Guice.createInjector().getInstance(D.class);
198       fail();
199     } catch (ConfigurationException expected) {
200       assertContains(
201           expected.getMessage(),
202           D.class.getName() + " is annotated with " + Singleton.class.getName(),
203           "but scope annotations are not supported for abstract types.",
204           "at " + D.class.getName() + ".class(ScopesTest.java:");
205     }
206   }
207 
208   @Singleton
209   @ImplementedBy(DImpl.class)
210   interface D {}
211 
212   static class DImpl implements D {}
213 
testScopingAnnotationsOnAbstractTypeViaProvidedBy()214   public void testScopingAnnotationsOnAbstractTypeViaProvidedBy() {
215     try {
216       Guice.createInjector().getInstance(E.class);
217       fail();
218     } catch (ConfigurationException expected) {
219       assertContains(
220           expected.getMessage(),
221           E.class.getName() + " is annotated with " + Singleton.class.getName(),
222           "but scope annotations are not supported for abstract types.",
223           "at " + E.class.getName() + ".class(ScopesTest.java:");
224     }
225   }
226 
227   @Singleton
228   @ProvidedBy(EProvider.class)
229   interface E {}
230 
231   static class EProvider implements Provider<E> {
232     @Override
get()233     public E get() {
234       return null;
235     }
236   }
237 
testScopeUsedButNotBound()238   public void testScopeUsedButNotBound() {
239     try {
240       Guice.createInjector(
241           new AbstractModule() {
242             @Override
243             protected void configure() {
244               bind(B.class).in(CustomScoped.class);
245               bind(C.class);
246             }
247           });
248       fail();
249     } catch (CreationException expected) {
250       assertContains(
251           expected.getMessage(),
252           "1) No scope is bound to " + CustomScoped.class.getName(),
253           "at " + getClass().getName(),
254           getDeclaringSourcePart(getClass()),
255           "2) No scope is bound to " + CustomScoped.class.getName(),
256           "at " + C.class.getName() + ".class");
257     }
258   }
259 
260   static class B {}
261 
262   @CustomScoped
263   static class C {}
264 
testSingletonsInProductionStage()265   public void testSingletonsInProductionStage() {
266     Guice.createInjector(Stage.PRODUCTION, singletonsModule);
267 
268     assertEquals(1, AnnotatedSingleton.nextInstanceId);
269     assertEquals(1, BoundAsSingleton.nextInstanceId);
270     assertEquals(1, EagerSingleton.nextInstanceId);
271     assertEquals(1, RealLinkedSingleton.nextInstanceId);
272     assertEquals(1, JustInTimeSingleton.nextInstanceId);
273     assertEquals(0, NotASingleton.nextInstanceId);
274   }
275 
testSingletonsInDevelopmentStage()276   public void testSingletonsInDevelopmentStage() {
277     Guice.createInjector(Stage.DEVELOPMENT, singletonsModule);
278 
279     assertEquals(0, AnnotatedSingleton.nextInstanceId);
280     assertEquals(0, BoundAsSingleton.nextInstanceId);
281     assertEquals(1, EagerSingleton.nextInstanceId);
282     assertEquals(0, RealLinkedSingleton.nextInstanceId);
283     assertEquals(0, JustInTimeSingleton.nextInstanceId);
284     assertEquals(0, NotASingleton.nextInstanceId);
285   }
286 
testSingletonScopeIsNotSerializable()287   public void testSingletonScopeIsNotSerializable() throws IOException {
288     Asserts.assertNotSerializable(Scopes.SINGLETON);
289   }
290 
testNoScopeIsNotSerializable()291   public void testNoScopeIsNotSerializable() throws IOException {
292     Asserts.assertNotSerializable(Scopes.NO_SCOPE);
293   }
294 
testUnscopedProviderWorksOutsideOfRequestedScope()295   public void testUnscopedProviderWorksOutsideOfRequestedScope() {
296     final RememberProviderScope scope = new RememberProviderScope();
297 
298     Injector injector =
299         Guice.createInjector(
300             new AbstractModule() {
301               @Override
302               protected void configure() {
303                 bindScope(CustomScoped.class, scope);
304                 bind(List.class).to(ArrayList.class).in(CustomScoped.class);
305               }
306             });
307 
308     injector.getInstance(List.class);
309     Provider<?> listProvider = scope.providers.get(Key.get(List.class));
310 
311     // this line fails with a NullPointerException because the Providers
312     // passed to Scope.scope() don't work outside of the scope() method.
313     assertTrue(listProvider.get() instanceof ArrayList);
314   }
315 
316   static class OuterRuntimeModule extends AbstractModule {
317     @Override
configure()318     protected void configure() {
319       install(new InnerRuntimeModule());
320     }
321   }
322 
323   static class InnerRuntimeModule extends AbstractModule {
324     @Override
configure()325     protected void configure() {
326       bindScope(NotRuntimeRetainedScoped.class, Scopes.NO_SCOPE);
327     }
328   }
329 
testScopeAnnotationWithoutRuntimeRetention()330   public void testScopeAnnotationWithoutRuntimeRetention() {
331     try {
332       Guice.createInjector(new OuterRuntimeModule());
333       fail();
334     } catch (CreationException expected) {
335       assertContains(
336           expected.getMessage(),
337           "1) Please annotate "
338               + NotRuntimeRetainedScoped.class.getName()
339               + " with @Retention(RUNTIME).",
340           "at " + InnerRuntimeModule.class.getName() + getDeclaringSourcePart(getClass()),
341           asModuleChain(OuterRuntimeModule.class, InnerRuntimeModule.class));
342     }
343   }
344 
345   static class OuterDeprecatedModule extends AbstractModule {
346     @Override
configure()347     protected void configure() {
348       install(new InnerDeprecatedModule());
349     }
350   }
351 
352   static class InnerDeprecatedModule extends AbstractModule {
353     @Override
configure()354     protected void configure() {
355       bindScope(Deprecated.class, Scopes.NO_SCOPE);
356     }
357   }
358 
testBindScopeToAnnotationWithoutScopeAnnotation()359   public void testBindScopeToAnnotationWithoutScopeAnnotation() {
360     try {
361       Guice.createInjector(new OuterDeprecatedModule());
362       fail();
363     } catch (CreationException expected) {
364       assertContains(
365           expected.getMessage(),
366           "1) Please annotate " + Deprecated.class.getName() + " with @ScopeAnnotation.",
367           "at " + InnerDeprecatedModule.class.getName() + getDeclaringSourcePart(getClass()),
368           asModuleChain(OuterDeprecatedModule.class, InnerDeprecatedModule.class));
369     }
370   }
371 
372   static class OuterScopeModule extends AbstractModule {
373     @Override
configure()374     protected void configure() {
375       install(new CustomNoScopeModule());
376       install(new CustomSingletonModule());
377     }
378   }
379 
380   static class CustomNoScopeModule extends AbstractModule {
381     @Override
configure()382     protected void configure() {
383       bindScope(CustomScoped.class, Scopes.NO_SCOPE);
384     }
385   }
386 
387   static class CustomSingletonModule extends AbstractModule {
388     @Override
configure()389     protected void configure() {
390       bindScope(CustomScoped.class, Scopes.SINGLETON);
391     }
392   }
393 
testBindScopeTooManyTimes()394   public void testBindScopeTooManyTimes() {
395     try {
396       Guice.createInjector(new OuterScopeModule());
397       fail();
398     } catch (CreationException expected) {
399       assertContains(
400           expected.getMessage(),
401           "1) Scope Scopes.NO_SCOPE is already bound to "
402               + CustomScoped.class.getName()
403               + " at "
404               + CustomNoScopeModule.class.getName()
405               + getDeclaringSourcePart(getClass()),
406           asModuleChain(OuterScopeModule.class, CustomNoScopeModule.class),
407           "Cannot bind Scopes.SINGLETON.",
408           "at " + ScopesTest.class.getName(),
409           getDeclaringSourcePart(getClass()),
410           asModuleChain(OuterScopeModule.class, CustomSingletonModule.class));
411     }
412   }
413 
testBindDuplicateScope()414   public void testBindDuplicateScope() {
415     Injector injector =
416         Guice.createInjector(
417             new AbstractModule() {
418               @Override
419               protected void configure() {
420                 bindScope(CustomScoped.class, Scopes.SINGLETON);
421                 bindScope(CustomScoped.class, Scopes.SINGLETON);
422               }
423             });
424 
425     assertSame(
426         injector.getInstance(AnnotatedCustomScoped.class),
427         injector.getInstance(AnnotatedCustomScoped.class));
428   }
429 
testDuplicateScopeAnnotations()430   public void testDuplicateScopeAnnotations() {
431     Injector injector =
432         Guice.createInjector(
433             new AbstractModule() {
434               @Override
435               protected void configure() {
436                 bindScope(CustomScoped.class, Scopes.NO_SCOPE);
437               }
438             });
439 
440     try {
441       injector.getInstance(SingletonAndCustomScoped.class);
442       fail();
443     } catch (ConfigurationException expected) {
444       assertContains(
445           expected.getMessage(),
446           "1) More than one scope annotation was found: ",
447           "while locating " + SingletonAndCustomScoped.class.getName());
448     }
449   }
450 
testNullScopedAsASingleton()451   public void testNullScopedAsASingleton() {
452     Injector injector =
453         Guice.createInjector(
454             new AbstractModule() {
455 
456               final Iterator<String> values = Arrays.asList(null, "A").iterator();
457 
458               @Provides
459               @Singleton
460               String provideString() {
461                 return values.next();
462               }
463             });
464 
465     assertNull(injector.getInstance(String.class));
466     assertNull(injector.getInstance(String.class));
467     assertNull(injector.getInstance(String.class));
468   }
469 
470   class RememberProviderScope implements Scope {
471     final Map<Key<?>, Provider<?>> providers = Maps.newHashMap();
472 
473     @Override
scope(Key<T> key, Provider<T> unscoped)474     public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
475       providers.put(key, unscoped);
476       return unscoped;
477     }
478   }
479 
testSingletonAnnotationOnParameterizedType()480   public void testSingletonAnnotationOnParameterizedType() {
481     Injector injector = Guice.createInjector();
482     assertSame(
483         injector.getInstance(new Key<Injected<String>>() {}),
484         injector.getInstance(new Key<Injected<String>>() {}));
485     assertSame(
486         injector.getInstance(new Key<In<Integer>>() {}),
487         injector.getInstance(new Key<In<Short>>() {}));
488   }
489 
490   @ImplementedBy(Injected.class)
491   public interface In<T> {}
492 
493   @Singleton
494   public static class Injected<T> implements In<T> {}
495 
496   @Target({ElementType.TYPE, ElementType.METHOD})
497   @Retention(RUNTIME)
498   @ScopeAnnotation
499   public @interface CustomScoped {}
500 
501   static final Scope CUSTOM_SCOPE =
502       new Scope() {
503         @Override
504         public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
505           return Scopes.SINGLETON.scope(key, unscoped);
506         }
507       };
508 
509   @Target({ElementType.TYPE, ElementType.METHOD})
510   @ScopeAnnotation
511   public @interface NotRuntimeRetainedScoped {}
512 
513   @CustomScoped
514   static class AnnotatedCustomScoped {}
515 
516   @Singleton
517   static class AnnotatedSingleton {
518     static int nextInstanceId;
519     final int instanceId = nextInstanceId++;
520   }
521 
522   static class BoundAsSingleton {
523     static int nextInstanceId;
524     final int instanceId = nextInstanceId++;
525   }
526 
527   static class EagerSingleton {
528     static int nextInstanceId;
529     final int instanceId = nextInstanceId++;
530   }
531 
532   interface LinkedSingleton {}
533 
534   @Singleton
535   static class RealLinkedSingleton implements LinkedSingleton {
536     static int nextInstanceId;
537     final int instanceId = nextInstanceId++;
538   }
539 
540   static class DependsOnJustInTimeSingleton {
541     @Inject JustInTimeSingleton justInTimeSingleton;
542   }
543 
544   @Singleton
545   static class JustInTimeSingleton {
546     static int nextInstanceId;
547     final int instanceId = nextInstanceId++;
548   }
549 
550   static class NotASingleton {
551     static int nextInstanceId;
552     final int instanceId = nextInstanceId++;
553   }
554 
555   // suppress compiler error for testing
556   @SuppressWarnings({"MoreThanOneScopeAnnotationOnClass", "multiple-scope"})
557   @Singleton
558   @CustomScoped
559   static class SingletonAndCustomScoped {}
560 
561   @ImplementedBy(Implementation.class)
562   static interface ImplementedBySingleton {}
563 
564   @ProvidedBy(ImplementationProvider.class)
565   static class ProvidedBySingleton {
566     static int nextInstanceId;
567     final int instanceId = nextInstanceId++;
568   }
569 
570   static class Implementation implements ImplementedBySingleton {
571     static int nextInstanceId;
572     final int instanceId = nextInstanceId++;
573   }
574 
575   static class ImplementationProvider implements Provider<ProvidedBySingleton> {
576     @Override
get()577     public ProvidedBySingleton get() {
578       return new ProvidedBySingleton();
579     }
580   }
581 
testScopeThatGetsAnUnrelatedObject()582   public void testScopeThatGetsAnUnrelatedObject() {
583     Injector injector =
584         Guice.createInjector(
585             new AbstractModule() {
586               @Override
587               protected void configure() {
588                 bind(B.class);
589                 bind(C.class);
590                 ProviderGetScope providerGetScope = new ProviderGetScope();
591                 requestInjection(providerGetScope);
592                 bindScope(CustomScoped.class, providerGetScope);
593               }
594             });
595 
596     injector.getInstance(C.class);
597   }
598 
599   class ProviderGetScope implements Scope {
600     @Inject Provider<B> bProvider;
601 
602     @Override
scope(Key<T> key, final Provider<T> unscoped)603     public <T> Provider<T> scope(Key<T> key, final Provider<T> unscoped) {
604       return new Provider<T>() {
605         @Override
606         public T get() {
607           bProvider.get();
608           return unscoped.get();
609         }
610       };
611     }
612   }
613 
614   public void testIsSingletonPositive() {
615     final Key<String> a = Key.get(String.class, named("A"));
616     final Key<String> b = Key.get(String.class, named("B"));
617     final Key<String> c = Key.get(String.class, named("C"));
618     final Key<String> d = Key.get(String.class, named("D"));
619     final Key<String> e = Key.get(String.class, named("E"));
620     final Key<String> f = Key.get(String.class, named("F"));
621     final Key<String> g = Key.get(String.class, named("G"));
622     final Key<Object> h = Key.get(Object.class, named("H"));
623     final Key<String> i = Key.get(String.class, named("I"));
624 
625     Module singletonBindings =
626         new AbstractModule() {
627           @Override
628           protected void configure() {
629             bind(a).to(b);
630             bind(b).to(c);
631             bind(c).toProvider(Providers.of("c")).in(Scopes.SINGLETON);
632             bind(d).toInstance("d");
633             bind(e).toProvider(Providers.of("e")).asEagerSingleton();
634             bind(f).toProvider(Providers.of("f")).in(Singleton.class);
635             bind(h).to(AnnotatedSingleton.class);
636             install(
637                 new PrivateModule() {
638                   @Override
639                   protected void configure() {
640                     bind(i).toProvider(Providers.of("i")).in(Singleton.class);
641                     expose(i);
642                   }
643                 });
644           }
645 
646           @Provides
647           @Named("G")
648           @Singleton
649           String provideG() {
650             return "g";
651           }
652         };
653 
654     @SuppressWarnings("unchecked") // we know the module contains only bindings
655     List<Element> moduleBindings = Elements.getElements(singletonBindings);
656     ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
657     assertFalse(Scopes.isSingleton(map.get(a))); // linked bindings are not followed by modules
658     assertFalse(Scopes.isSingleton(map.get(b)));
659     assertTrue(Scopes.isSingleton(map.get(c)));
660     assertTrue(Scopes.isSingleton(map.get(d)));
661     assertTrue(Scopes.isSingleton(map.get(e)));
662     assertTrue(Scopes.isSingleton(map.get(f)));
663     assertTrue(Scopes.isSingleton(map.get(g)));
664     assertFalse(Scopes.isSingleton(map.get(h))); // annotated classes are not followed by modules
665     assertTrue(Scopes.isSingleton(map.get(i)));
666 
667     Injector injector = Guice.createInjector(singletonBindings);
668     assertTrue(Scopes.isSingleton(injector.getBinding(a)));
669     assertTrue(Scopes.isSingleton(injector.getBinding(b)));
670     assertTrue(Scopes.isSingleton(injector.getBinding(c)));
671     assertTrue(Scopes.isSingleton(injector.getBinding(d)));
672     assertTrue(Scopes.isSingleton(injector.getBinding(e)));
673     assertTrue(Scopes.isSingleton(injector.getBinding(f)));
674     assertTrue(Scopes.isSingleton(injector.getBinding(g)));
675     assertTrue(Scopes.isSingleton(injector.getBinding(h)));
676     assertTrue(Scopes.isSingleton(injector.getBinding(i)));
677   }
678 
679   public void testIsSingletonNegative() {
680     final Key<String> a = Key.get(String.class, named("A"));
681     final Key<String> b = Key.get(String.class, named("B"));
682     final Key<String> c = Key.get(String.class, named("C"));
683     final Key<String> d = Key.get(String.class, named("D"));
684     final Key<String> e = Key.get(String.class, named("E"));
685     final Key<String> f = Key.get(String.class, named("F"));
686 
687     Module singletonBindings =
688         new AbstractModule() {
689           @Override
690           protected void configure() {
691             bind(a).to(b);
692             bind(b).to(c);
693             bind(c).toProvider(Providers.of("c")).in(Scopes.NO_SCOPE);
694             bind(d).toProvider(Providers.of("d")).in(CustomScoped.class);
695             bindScope(CustomScoped.class, Scopes.NO_SCOPE);
696             install(
697                 new PrivateModule() {
698                   @Override
699                   protected void configure() {
700                     bind(f).toProvider(Providers.of("f")).in(CustomScoped.class);
701                     expose(f);
702                   }
703                 });
704           }
705 
706           @Provides
707           @Named("E")
708           @CustomScoped
709           String provideE() {
710             return "e";
711           }
712         };
713 
714     @SuppressWarnings("unchecked") // we know the module contains only bindings
715     List<Element> moduleBindings = Elements.getElements(singletonBindings);
716     ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
717     assertFalse(Scopes.isSingleton(map.get(a)));
718     assertFalse(Scopes.isSingleton(map.get(b)));
719     assertFalse(Scopes.isSingleton(map.get(c)));
720     assertFalse(Scopes.isSingleton(map.get(d)));
721     assertFalse(Scopes.isSingleton(map.get(e)));
722     assertFalse(Scopes.isSingleton(map.get(f)));
723 
724     Injector injector = Guice.createInjector(singletonBindings);
725     assertFalse(Scopes.isSingleton(injector.getBinding(a)));
726     assertFalse(Scopes.isSingleton(injector.getBinding(b)));
727     assertFalse(Scopes.isSingleton(injector.getBinding(c)));
728     assertFalse(Scopes.isSingleton(injector.getBinding(d)));
729     assertFalse(Scopes.isSingleton(injector.getBinding(e)));
730     assertFalse(Scopes.isSingleton(injector.getBinding(f)));
731   }
732 
733   public void testIsScopedPositive() {
734     final Key<String> a = Key.get(String.class, named("A"));
735     final Key<String> b = Key.get(String.class, named("B"));
736     final Key<String> c = Key.get(String.class, named("C"));
737     final Key<String> d = Key.get(String.class, named("D"));
738     final Key<String> e = Key.get(String.class, named("E"));
739     final Key<Object> f = Key.get(Object.class, named("F"));
740     final Key<String> g = Key.get(String.class, named("G"));
741 
742     Module customBindings =
743         new AbstractModule() {
744           @Override
745           protected void configure() {
746             bindScope(CustomScoped.class, CUSTOM_SCOPE);
747             bind(a).to(b);
748             bind(b).to(c);
749             bind(c).toProvider(Providers.of("c")).in(CUSTOM_SCOPE);
750             bind(d).toProvider(Providers.of("d")).in(CustomScoped.class);
751             bind(f).to(AnnotatedCustomScoped.class);
752             install(
753                 new PrivateModule() {
754                   @Override
755                   protected void configure() {
756                     bind(g).toProvider(Providers.of("g")).in(CustomScoped.class);
757                     expose(g);
758                   }
759                 });
760           }
761 
762           @Provides
763           @Named("E")
764           @CustomScoped
765           String provideE() {
766             return "e";
767           }
768         };
769 
770     @SuppressWarnings("unchecked") // we know the module contains only bindings
771     List<Element> moduleBindings = Elements.getElements(customBindings);
772     ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
773     assertFalse(isCustomScoped(map.get(a))); // linked bindings are not followed by modules
774     assertFalse(isCustomScoped(map.get(b)));
775     assertTrue(isCustomScoped(map.get(c)));
776     assertTrue(isCustomScoped(map.get(d)));
777     assertTrue(isCustomScoped(map.get(e)));
778     assertFalse(isCustomScoped(map.get(f))); // annotated classes are not followed by modules
779     assertTrue(isCustomScoped(map.get(g)));
780 
781     Injector injector = Guice.createInjector(customBindings);
782     assertTrue(isCustomScoped(injector.getBinding(a)));
783     assertTrue(isCustomScoped(injector.getBinding(b)));
784     assertTrue(isCustomScoped(injector.getBinding(c)));
785     assertTrue(isCustomScoped(injector.getBinding(d)));
786     assertTrue(isCustomScoped(injector.getBinding(e)));
787     assertTrue(isCustomScoped(injector.getBinding(f)));
788     assertTrue(isCustomScoped(injector.getBinding(g)));
789   }
790 
791   public void testIsScopedNegative() {
792     final Key<String> a = Key.get(String.class, named("A"));
793     final Key<String> b = Key.get(String.class, named("B"));
794     final Key<String> c = Key.get(String.class, named("C"));
795     final Key<String> d = Key.get(String.class, named("D"));
796     final Key<String> e = Key.get(String.class, named("E"));
797     final Key<String> f = Key.get(String.class, named("F"));
798     final Key<String> g = Key.get(String.class, named("G"));
799     final Key<String> h = Key.get(String.class, named("H"));
800 
801     Module customBindings =
802         new AbstractModule() {
803           @Override
804           protected void configure() {
805             bind(a).to(b);
806             bind(b).to(c);
807             bind(c).toProvider(Providers.of("c")).in(Scopes.NO_SCOPE);
808             bind(d).toProvider(Providers.of("d")).in(Singleton.class);
809             install(
810                 new PrivateModule() {
811                   @Override
812                   protected void configure() {
813                     bind(f).toProvider(Providers.of("f")).in(Singleton.class);
814                     expose(f);
815                   }
816                 });
817             bind(g).toInstance("g");
818             bind(h).toProvider(Providers.of("h")).asEagerSingleton();
819           }
820 
821           @Provides
822           @Named("E")
823           @Singleton
824           String provideE() {
825             return "e";
826           }
827         };
828 
829     @SuppressWarnings("unchecked") // we know the module contains only bindings
830     List<Element> moduleBindings = Elements.getElements(customBindings);
831     ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
832     assertFalse(isCustomScoped(map.get(a)));
833     assertFalse(isCustomScoped(map.get(b)));
834     assertFalse(isCustomScoped(map.get(c)));
835     assertFalse(isCustomScoped(map.get(d)));
836     assertFalse(isCustomScoped(map.get(e)));
837     assertFalse(isCustomScoped(map.get(f)));
838     assertFalse(isCustomScoped(map.get(g)));
839     assertFalse(isCustomScoped(map.get(h)));
840 
841     Injector injector = Guice.createInjector(customBindings);
842     assertFalse(isCustomScoped(injector.getBinding(a)));
843     assertFalse(isCustomScoped(injector.getBinding(b)));
844     assertFalse(isCustomScoped(injector.getBinding(c)));
845     assertFalse(isCustomScoped(injector.getBinding(d)));
846     assertFalse(isCustomScoped(injector.getBinding(e)));
847     assertFalse(isCustomScoped(injector.getBinding(f)));
848     assertFalse(isCustomScoped(injector.getBinding(g)));
849     assertFalse(isCustomScoped(injector.getBinding(h)));
850   }
851 
852   private boolean isCustomScoped(Binding<?> binding) {
853     return Scopes.isScoped(binding, CUSTOM_SCOPE, CustomScoped.class);
854   }
855 
856   ImmutableMap<Key<?>, Binding<?>> indexBindings(Iterable<Element> elements) {
857     ImmutableMap.Builder<Key<?>, Binding<?>> builder = ImmutableMap.builder();
858     for (Element element : elements) {
859       if (element instanceof Binding) {
860         Binding<?> binding = (Binding<?>) element;
861         builder.put(binding.getKey(), binding);
862       } else if (element instanceof PrivateElements) {
863         PrivateElements privateElements = (PrivateElements) element;
864         Map<Key<?>, Binding<?>> privateBindings = indexBindings(privateElements.getElements());
865         for (Key<?> exposed : privateElements.getExposedKeys()) {
866           builder.put(exposed, privateBindings.get(exposed));
867         }
868       }
869     }
870     return builder.build();
871   }
872 
873   @Singleton
874   static class ThrowingSingleton {
875     static int nextInstanceId;
876     final int instanceId = nextInstanceId++;
877 
878     ThrowingSingleton() {
879       if (instanceId == 0) {
880         throw new RuntimeException();
881       }
882     }
883   }
884 
885   public void testSingletonConstructorThrows() {
886     Injector injector = Guice.createInjector();
887 
888     try {
889       injector.getInstance(ThrowingSingleton.class);
890       fail();
891     } catch (ProvisionException expected) {
892     }
893 
894     // this behaviour is unspecified. If we change Guice to re-throw the exception, this test
895     // should be changed
896     injector.getInstance(ThrowingSingleton.class);
897     assertEquals(2, ThrowingSingleton.nextInstanceId);
898   }
899 
900   /**
901    * Should only be created by {@link SBarrierProvider}.
902    *
903    * <p>{@code S} stands for synchronization.
904    *
905    * @see SBarrierProvider
906    */
907   static class S {
908 
909     private S(int preventInjectionWithoutProvider) {}
910   }
911 
912   /**
913    * Provides all the instances of S simultaneously using {@link CyclicBarrier} with {@code
914    * nThreads}. Intended to be used for threads synchronization during injection.
915    */
916   static class SBarrierProvider implements Provider<S> {
917 
918     final CyclicBarrier barrier;
919     volatile boolean barrierPassed = false;
920 
921     SBarrierProvider(int nThreads) {
922       barrier =
923           new CyclicBarrier(
924               nThreads,
925               new Runnable() {
926                 @Override
927                 public void run() {
928                   // would finish before returning from await() for any thread
929                   barrierPassed = true;
930                 }
931               });
932     }
933 
934     @Override
935     public S get() {
936       try {
937         if (!barrierPassed) {
938           // only if we're triggering barrier for the first time
939           barrier.await(DEADLOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
940         }
941       } catch (Exception e) {
942         throw new RuntimeException(e);
943       }
944       return new S(0);
945     }
946   }
947 
948   /**
949    * Tests that different injectors should not affect each other.
950    *
951    * <p>This creates a second thread to work in parallel, to create two instances of {@link S} as
952    * the same time. If the lock if not granular enough (i.e. JVM-wide) then they would block each
953    * other creating a deadlock and await timeout.
954    */
955 
956   public void testInjectorsDontDeadlockOnSingletons() throws Exception {
957     final Provider<S> provider = new SBarrierProvider(2);
958     final Injector injector =
959         Guice.createInjector(
960             new AbstractModule() {
961               @Override
962               protected void configure() {
963                 Thread.currentThread().setName("S.class[1]");
964                 bind(S.class).toProvider(provider).in(Scopes.SINGLETON);
965               }
966             });
967     final Injector secondInjector =
968         Guice.createInjector(
969             new AbstractModule() {
970               @Override
971               protected void configure() {
972                 Thread.currentThread().setName("S.class[2]");
973                 bind(S.class).toProvider(provider).in(Scopes.SINGLETON);
974               }
975             });
976 
977     Future<S> secondThreadResult =
978         Executors.newSingleThreadExecutor()
979             .submit(
980                 new Callable<S>() {
981                   @Override
982                   public S call() {
983                     return secondInjector.getInstance(S.class);
984                   }
985                 });
986 
987     S firstS = injector.getInstance(S.class);
988     S secondS = secondThreadResult.get();
989 
990     assertNotSame(firstS, secondS);
991   }
992 
993   @ImplementedBy(GImpl.class)
994   interface G {}
995 
996   @Singleton
997   static class GImpl implements G {
998 
999     final H h;
1000 
1001     /** Relies on Guice implementation to inject S first and H later, which provides a barrier . */
1002     @Inject
1003     GImpl(S synchronizationBarrier, H h) {
1004       this.h = h;
1005     }
1006   }
1007 
1008   @ImplementedBy(HImpl.class)
1009   interface H {}
1010 
1011   @Singleton
1012   static class HImpl implements H {
1013 
1014     final G g;
1015 
1016     /** Relies on Guice implementation to inject S first and G later, which provides a barrier . */
1017     @Inject
1018     HImpl(S synchronizationBarrier, G g) throws Exception {
1019       this.g = g;
1020     }
1021   }
1022 
1023   /**
1024    * Tests that injector can create two singletons with circular dependency in parallel.
1025    *
1026    * <p>This creates two threads to work in parallel, to create instances of {@link G} and {@link
1027    * H}. Creation is synchronized by injection of {@link S}, first thread would block until second
1028    * would be inside a singleton creation as well.
1029    *
1030    * <p>Both instances are created by sibling injectors, that share singleton scope. Verifies that
1031    * exactly one circular proxy object is created.
1032    */
1033 
1034   public void testSiblingInjectorGettingCircularSingletonsOneCircularProxy() throws Exception {
1035     final Provider<S> provider = new SBarrierProvider(2);
1036     final Injector injector =
1037         Guice.createInjector(
1038             new AbstractModule() {
1039               @Override
1040               protected void configure() {
1041                 bind(S.class).toProvider(provider);
1042               }
1043             });
1044 
1045     Future<G> firstThreadResult =
1046         Executors.newSingleThreadExecutor()
1047             .submit(
1048                 new Callable<G>() {
1049                   @Override
1050                   public G call() {
1051                     Thread.currentThread().setName("G.class");
1052                     return injector.createChildInjector().getInstance(G.class);
1053                   }
1054                 });
1055     Future<H> secondThreadResult =
1056         Executors.newSingleThreadExecutor()
1057             .submit(
1058                 new Callable<H>() {
1059                   @Override
1060                   public H call() {
1061                     Thread.currentThread().setName("H.class");
1062                     return injector.createChildInjector().getInstance(H.class);
1063                   }
1064                 });
1065 
1066     // using separate threads to avoid potential deadlock on the main thread
1067     // waiting twice as much to be sure that both would time out in their respective barriers
1068     GImpl g = (GImpl) firstThreadResult.get(DEADLOCK_TIMEOUT_SECONDS * 3, TimeUnit.SECONDS);
1069     HImpl h = (HImpl) secondThreadResult.get(DEADLOCK_TIMEOUT_SECONDS * 3, TimeUnit.SECONDS);
1070 
1071     // Check that G and H created are not proxied
1072     assertTrue(!Scopes.isCircularProxy(g) && !Scopes.isCircularProxy(h));
1073 
1074     // Check that we have no more than one circular proxy created
1075     assertFalse(Scopes.isCircularProxy(g.h) && Scopes.isCircularProxy(h.g));
1076 
1077     // Check that non-proxy variable points to another singleton
1078     assertTrue(g.h == h || h.g == g);
1079 
1080     // Check correct proxy initialization as default equals implementation would
1081     assertEquals(g.h, h);
1082     assertEquals(h.g, g);
1083   }
1084 
1085   @Singleton
1086   static class I0 {
1087 
1088     /** Relies on Guice implementation to inject S first, which provides a barrier . */
1089     @Inject
1090     I0(I1 i) {}
1091   }
1092 
1093   @Singleton
1094   static class I1 {
1095 
1096     /** Relies on Guice implementation to inject S first, which provides a barrier . */
1097     @Inject
1098     I1(S synchronizationBarrier, I2 i) {}
1099   }
1100 
1101   @Singleton
1102   static class I2 {
1103 
1104     /** Relies on Guice implementation to inject S first, which provides a barrier . */
1105     @Inject
1106     I2(J1 j) {}
1107   }
1108 
1109   @Singleton
1110   static class J0 {
1111 
1112     /** Relies on Guice implementation to inject S first, which provides a barrier . */
1113     @Inject
1114     J0(J1 j) {}
1115   }
1116 
1117   @Singleton
1118   static class J1 {
1119 
1120     /** Relies on Guice implementation to inject S first, which provides a barrier . */
1121     @Inject
1122     J1(S synchronizationBarrier, J2 j) {}
1123   }
1124 
1125   @Singleton
1126   static class J2 {
1127 
1128     /** Relies on Guice implementation to inject S first, which provides a barrier . */
1129     @Inject
1130     J2(K1 k) {}
1131   }
1132 
1133   @Singleton
1134   static class K0 {
1135 
1136     /** Relies on Guice implementation to inject S first, which provides a barrier . */
1137     @Inject
1138     K0(K1 k) {}
1139   }
1140 
1141   @Singleton
1142   static class K1 {
1143 
1144     /** Relies on Guice implementation to inject S first, which provides a barrier . */
1145     @Inject
1146     K1(S synchronizationBarrier, K2 k) {}
1147   }
1148 
1149   @Singleton
1150   static class K2 {
1151 
1152     /** Relies on Guice implementation to inject S first, which provides a barrier . */
1153     @Inject
1154     K2(I1 i) {}
1155   }
1156 
1157   /**
1158    * Check that circular dependencies on non-interfaces are correctly resolved in multi-threaded
1159    * case. And that an error message constructed is a good one.
1160    *
1161    * <p>I0 -> I1 -> I2 -> J1 and J0 -> J1 -> J2 -> K1 and K0 -> K1 -> K2, where I1, J1 and K1 are
1162    * created in parallel.
1163    *
1164    * <p>Creation is synchronized by injection of {@link S}, first thread would block until second
1165    * would be inside a singleton creation as well.
1166    *
1167    * <p>Verifies that provision results in an error, that spans two threads and has a dependency
1168    * cycle.
1169    */
1170 
1171   public void testUnresolvableSingletonCircularDependencyErrorMessage() throws Exception {
1172     final Provider<S> provider = new SBarrierProvider(3);
1173     final Injector injector =
1174         Guice.createInjector(
1175             new AbstractModule() {
1176               @Override
1177               protected void configure() {
1178                 bind(S.class).toProvider(provider);
1179               }
1180             });
1181 
1182     FutureTask<I0> firstThreadResult = new FutureTask<>(fetchClass(injector, I0.class));
1183     Thread i0Thread = new Thread(firstThreadResult, "I0.class");
1184     // we need to call toString() now, because the toString() changes after the thread exits.
1185     String i0ThreadString = i0Thread.toString();
1186     i0Thread.start();
1187 
1188     FutureTask<J0> secondThreadResult = new FutureTask<>(fetchClass(injector, J0.class));
1189     Thread j0Thread = new Thread(secondThreadResult, "J0.class");
1190     String j0ThreadString = j0Thread.toString();
1191     j0Thread.start();
1192 
1193     FutureTask<K0> thirdThreadResult = new FutureTask<>(fetchClass(injector, K0.class));
1194     Thread k0Thread = new Thread(thirdThreadResult, "K0.class");
1195     String k0ThreadString = k0Thread.toString();
1196     k0Thread.start();
1197 
1198     // using separate threads to avoid potential deadlock on the main thread
1199     // waiting twice as much to be sure that both would time out in their respective barriers
1200     Throwable firstException = null;
1201     Throwable secondException = null;
1202     Throwable thirdException = null;
1203     try {
1204       firstThreadResult.get(DEADLOCK_TIMEOUT_SECONDS * 3, TimeUnit.SECONDS);
1205       fail();
1206     } catch (ExecutionException e) {
1207       firstException = e.getCause();
1208     }
1209     try {
1210       secondThreadResult.get(DEADLOCK_TIMEOUT_SECONDS * 3, TimeUnit.SECONDS);
1211       fail();
1212     } catch (ExecutionException e) {
1213       secondException = e.getCause();
1214     }
1215     try {
1216       thirdThreadResult.get(DEADLOCK_TIMEOUT_SECONDS * 3, TimeUnit.SECONDS);
1217       fail();
1218     } catch (ExecutionException e) {
1219       thirdException = e.getCause();
1220     }
1221 
1222     // verification of error messages generated
1223     List<Message> errors = new ArrayList<>();
1224     errors.addAll(((ProvisionException) firstException).getErrorMessages());
1225     errors.addAll(((ProvisionException) secondException).getErrorMessages());
1226     errors.addAll(((ProvisionException) thirdException).getErrorMessages());
1227     // We want to find the longest error reported for a cycle spanning multiple threads
1228     Message spanningError = null;
1229     for (Message error : errors) {
1230       if (error.getMessage().contains("Encountered circular dependency spanning several threads")) {
1231         if (spanningError == null
1232             || spanningError.getMessage().length() < error.getMessage().length()) {
1233           spanningError = error;
1234         }
1235       }
1236     }
1237     if (spanningError == null) {
1238       fail(
1239           "Couldn't find multi thread circular dependency error: "
1240               + Joiner.on("\n\n").join(errors));
1241     }
1242 
1243     String errorMessage = spanningError.getMessage();
1244     assertContains(
1245         errorMessage,
1246         "Encountered circular dependency spanning several threads. Tried proxying "
1247             + this.getClass().getName());
1248     assertFalse(
1249         "Both I0 and J0 can not be a part of a dependency cycle",
1250         errorMessage.contains(I0.class.getName()) && errorMessage.contains(J0.class.getName()));
1251     assertFalse(
1252         "Both J0 and K0 can not be a part of a dependency cycle",
1253         errorMessage.contains(J0.class.getName()) && errorMessage.contains(K0.class.getName()));
1254     assertFalse(
1255         "Both K0 and I0 can not be a part of a dependency cycle",
1256         errorMessage.contains(K0.class.getName()) && errorMessage.contains(I0.class.getName()));
1257 
1258     ListMultimap<String, String> threadToSingletons = ArrayListMultimap.create();
1259     boolean inSingletonsList = false;
1260     String currentThread = null;
1261     for (String errorLine : errorMessage.split("\\n")) {
1262       if (errorLine.startsWith("Thread[")) {
1263         inSingletonsList = true;
1264         currentThread =
1265             errorLine.substring(
1266                 0, errorLine.indexOf(" is holding locks the following singletons in the cycle:"));
1267       } else if (inSingletonsList) {
1268         if (errorLine.startsWith("\tat ")) {
1269           inSingletonsList = false;
1270         } else {
1271           threadToSingletons.put(currentThread, errorLine);
1272         }
1273       }
1274     }
1275 
1276     assertEquals("All threads should be in the cycle", 3, threadToSingletons.keySet().size());
1277 
1278     // NOTE:  J0,K0,I0 are not reported because their locks are not part of the cycle.
1279     assertEquals(
1280         threadToSingletons.get(j0ThreadString),
1281         ImmutableList.of(J1.class.getName(), J2.class.getName(), K1.class.getName()));
1282     assertEquals(
1283         threadToSingletons.get(k0ThreadString),
1284         ImmutableList.of(K1.class.getName(), K2.class.getName(), I1.class.getName()));
1285     assertEquals(
1286         threadToSingletons.get(i0ThreadString),
1287         ImmutableList.of(I1.class.getName(), I2.class.getName(), J1.class.getName()));
1288   }
1289 
1290   private static <T> Callable<T> fetchClass(final Injector injector, final Class<T> clazz) {
1291     return new Callable<T>() {
1292       @Override
1293       public T call() {
1294         return injector.getInstance(clazz);
1295       }
1296     };
1297   }
1298 
1299   // Test for https://github.com/google/guice/issues/1032
1300 
1301   public void testScopeAppliedByUserInsteadOfScoping() throws Exception {
1302     Injector injector =
1303         java.util.concurrent.Executors.newSingleThreadExecutor()
1304             .submit(
1305                 new Callable<Injector>() {
1306                   @Override
1307                   public Injector call() {
1308                     return Guice.createInjector(
1309                         new AbstractModule() {
1310                           @Override
1311                           protected void configure() {
1312                             bindListener(Matchers.any(), new ScopeMutatingProvisionListener());
1313                             bind(SingletonClass.class);
1314                           }
1315                         });
1316                   }
1317                 })
1318             .get();
1319     injector.getInstance(SingletonClass.class); // will fail here with NPE
1320   }
1321 
1322   @Singleton
1323   static class SingletonClass {}
1324 
1325   /** Uses Scope's public API to add a 'marker' into the provisioned instance's scope. */
1326   private static final class ScopeMutatingProvisionListener implements ProvisionListener {
1327     private static class ScopeMarker {
1328       static final Provider<ScopeMarker> PROVIDER =
1329           new Provider<ScopeMarker>() {
1330             @Override
1331             public ScopeMarker get() {
1332               return new ScopeMarker();
1333             }
1334           };
1335     }
1336 
1337     @Override
1338     public <T> void onProvision(final ProvisionInvocation<T> provisionInvocation) {
1339       provisionInvocation.provision();
1340       provisionInvocation
1341           .getBinding()
1342           .acceptScopingVisitor(
1343               new DefaultBindingScopingVisitor<Void>() {
1344                 @Override
1345                 public Void visitScope(Scope scope) {
1346                   scope.scope(Key.get(ScopeMarker.class), ScopeMarker.PROVIDER);
1347                   return null;
1348                 }
1349               });
1350     }
1351   }
1352 
1353   public void testForInstanceOfNoScopingReturnsUnscoped() {
1354     Injector injector =
1355         Guice.createInjector(
1356             new AbstractModule() {
1357               @Override
1358               protected void configure() {
1359                 bind(AImpl.class).in(Scopes.NO_SCOPE);
1360               }
1361             });
1362 
1363     assertTrue(
1364         injector
1365             .getBinding(Key.get(AImpl.class))
1366             .acceptScopingVisitor(
1367                 new DefaultBindingScopingVisitor<Boolean>() {
1368                   @Override
1369                   protected Boolean visitOther() {
1370                     return false;
1371                   }
1372 
1373                   @Override
1374                   public Boolean visitNoScoping() {
1375                     return true;
1376                   }
1377                 }));
1378   }
1379 }
1380