• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.google.inject.internal.CircularDependencyProxy;
20 import com.google.inject.internal.LinkedBindingImpl;
21 import com.google.inject.internal.SingletonScope;
22 import com.google.inject.spi.BindingScopingVisitor;
23 import com.google.inject.spi.ExposedBinding;
24 import java.lang.annotation.Annotation;
25 
26 /**
27  * Built-in scope implementations.
28  *
29  * @author crazybob@google.com (Bob Lee)
30  */
31 public class Scopes {
32 
Scopes()33   private Scopes() {}
34 
35   /** One instance per {@link Injector}. Also see {@code @}{@link Singleton}. */
36   public static final Scope SINGLETON = new SingletonScope();
37 
38   /**
39    * No scope; the same as not applying any scope at all. Each time the Injector obtains an instance
40    * of an object with "no scope", it injects this instance then immediately forgets it. When the
41    * next request for the same binding arrives it will need to obtain the instance over again.
42    *
43    * <p>This exists only in case a class has been annotated with a scope annotation such as {@link
44    * Singleton @Singleton}, and you need to override this to "no scope" in your binding.
45    *
46    * @since 2.0
47    */
48   public static final Scope NO_SCOPE =
49       new Scope() {
50         @Override
51         public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
52           return unscoped;
53         }
54 
55         @Override
56         public String toString() {
57           return "Scopes.NO_SCOPE";
58         }
59       };
60 
61   private static final BindingScopingVisitor<Boolean> IS_SINGLETON_VISITOR =
62       new BindingScopingVisitor<Boolean>() {
63         @Override
64         public Boolean visitNoScoping() {
65           return false;
66         }
67 
68         @Override
69         public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
70           return scopeAnnotation == Singleton.class
71               || scopeAnnotation == javax.inject.Singleton.class;
72         }
73 
74         @Override
75         public Boolean visitScope(Scope scope) {
76           return scope == Scopes.SINGLETON;
77         }
78 
79         @Override
80         public Boolean visitEagerSingleton() {
81           return true;
82         }
83       };
84 
85   /**
86    * Returns true if {@code binding} is singleton-scoped. If the binding is a {@link
87    * com.google.inject.spi.LinkedKeyBinding linked key binding} and belongs to an injector (ie. it
88    * was retrieved via {@link Injector#getBinding Injector.getBinding()}), then this method will
89    * also true if the target binding is singleton-scoped.
90    *
91    * @since 3.0
92    */
isSingleton(Binding<?> binding)93   public static boolean isSingleton(Binding<?> binding) {
94     do {
95       boolean singleton = binding.acceptScopingVisitor(IS_SINGLETON_VISITOR);
96       if (singleton) {
97         return true;
98       }
99 
100       if (binding instanceof LinkedBindingImpl) {
101         LinkedBindingImpl<?> linkedBinding = (LinkedBindingImpl) binding;
102         Injector injector = linkedBinding.getInjector();
103         if (injector != null) {
104           binding = injector.getBinding(linkedBinding.getLinkedKey());
105           continue;
106         }
107       } else if (binding instanceof ExposedBinding) {
108         ExposedBinding<?> exposedBinding = (ExposedBinding) binding;
109         Injector injector = exposedBinding.getPrivateElements().getInjector();
110         if (injector != null) {
111           binding = injector.getBinding(exposedBinding.getKey());
112           continue;
113         }
114       }
115 
116       return false;
117     } while (true);
118   }
119 
120   /**
121    * Returns true if {@code binding} has the given scope. If the binding is a {@link
122    * com.google.inject.spi.LinkedKeyBinding linked key binding} and belongs to an injector (ie. it
123    * was retrieved via {@link Injector#getBinding Injector.getBinding()}), then this method will
124    * also true if the target binding has the given scope.
125    *
126    * @param binding binding to check
127    * @param scope scope implementation instance
128    * @param scopeAnnotation scope annotation class
129    * @since 4.0
130    */
isScoped( Binding<?> binding, final Scope scope, final Class<? extends Annotation> scopeAnnotation)131   public static boolean isScoped(
132       Binding<?> binding, final Scope scope, final Class<? extends Annotation> scopeAnnotation) {
133     do {
134       boolean matches =
135           binding.acceptScopingVisitor(
136               new BindingScopingVisitor<Boolean>() {
137                 @Override
138                 public Boolean visitNoScoping() {
139                   return false;
140                 }
141 
142                 @Override
143                 public Boolean visitScopeAnnotation(Class<? extends Annotation> visitedAnnotation) {
144                   return visitedAnnotation == scopeAnnotation;
145                 }
146 
147                 @Override
148                 public Boolean visitScope(Scope visitedScope) {
149                   return visitedScope == scope;
150                 }
151 
152                 @Override
153                 public Boolean visitEagerSingleton() {
154                   return false;
155                 }
156               });
157 
158       if (matches) {
159         return true;
160       }
161 
162       if (binding instanceof LinkedBindingImpl) {
163         LinkedBindingImpl<?> linkedBinding = (LinkedBindingImpl) binding;
164         Injector injector = linkedBinding.getInjector();
165         if (injector != null) {
166           binding = injector.getBinding(linkedBinding.getLinkedKey());
167           continue;
168         }
169       } else if (binding instanceof ExposedBinding) {
170         ExposedBinding<?> exposedBinding = (ExposedBinding) binding;
171         Injector injector = exposedBinding.getPrivateElements().getInjector();
172         if (injector != null) {
173           binding = injector.getBinding(exposedBinding.getKey());
174           continue;
175         }
176       }
177 
178       return false;
179     } while (true);
180   }
181 
182   /**
183    * Returns true if the object is a proxy for a circular dependency, constructed by Guice because
184    * it encountered a circular dependency. Scope implementations should be careful to <b>not cache
185    * circular proxies</b>, because the proxies are not intended for general purpose use. (They are
186    * designed just to fulfill the immediate injection, not all injections. Caching them can lead to
187    * IllegalArgumentExceptions or ClassCastExceptions.)
188    *
189    * @since 4.0
190    */
isCircularProxy(Object object)191   public static boolean isCircularProxy(Object object) {
192     return object instanceof CircularDependencyProxy;
193   }
194 }
195