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