Home | History | Annotate | Download | only in inject
      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 (at) google.com (Bob Lee)
     30  */
     31 public class Scopes {
     32 
     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    */
     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    */
    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    */
    191   public static boolean isCircularProxy(Object object) {
    192     return object instanceof CircularDependencyProxy;
    193   }
    194 }
    195