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