Home | History | Annotate | Download | only in inject
      1 /*
      2  * Copyright (C) 2008 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.common.base.Preconditions.checkState;
     20 
     21 import com.google.inject.binder.AnnotatedBindingBuilder;
     22 import com.google.inject.binder.AnnotatedConstantBindingBuilder;
     23 import com.google.inject.binder.AnnotatedElementBuilder;
     24 import com.google.inject.binder.LinkedBindingBuilder;
     25 import com.google.inject.matcher.Matcher;
     26 import com.google.inject.spi.Message;
     27 import com.google.inject.spi.ProvisionListener;
     28 import com.google.inject.spi.TypeConverter;
     29 import com.google.inject.spi.TypeListener;
     30 import java.lang.annotation.Annotation;
     31 import java.lang.reflect.Method;
     32 
     33 /**
     34  * A module whose configuration information is hidden from its environment by default. Only bindings
     35  * that are explicitly exposed will be available to other modules and to the users of the injector.
     36  * This module may expose the bindings it creates and the bindings of the modules it installs.
     37  *
     38  * <p>A private module can be nested within a regular module or within another private module using
     39  * {@link Binder#install install()}. Its bindings live in a new environment that inherits bindings,
     40  * type converters, scopes, and interceptors from the surrounding ("parent") environment. When you
     41  * nest multiple private modules, the result is a tree of environments where the injector's
     42  * environment is the root.
     43  *
     44  * <p>Guice EDSL bindings can be exposed with {@link #expose(Class) expose()}. {@literal @}{@link
     45  * com.google.inject.Provides Provides} bindings can be exposed with the {@literal @}{@link Exposed}
     46  * annotation:
     47  *
     48  * <pre>
     49  * public class FooBarBazModule extends PrivateModule {
     50  *   protected void configure() {
     51  *     bind(Foo.class).to(RealFoo.class);
     52  *     expose(Foo.class);
     53  *
     54  *     install(new TransactionalBarModule());
     55  *     expose(Bar.class).annotatedWith(Transactional.class);
     56  *
     57  *     bind(SomeImplementationDetail.class);
     58  *     install(new MoreImplementationDetailsModule());
     59  *   }
     60  *
     61  *   {@literal @}Provides {@literal @}Exposed
     62  *   public Baz provideBaz() {
     63  *     return new SuperBaz();
     64  *   }
     65  * }
     66  * </pre>
     67  *
     68  * <p>Private modules are implemented using {@link Injector#createChildInjector(Module[]) parent
     69  * injectors}. When it can satisfy their dependencies, just-in-time bindings will be created in the
     70  * root environment. Such bindings are shared among all environments in the tree.
     71  *
     72  * <p>The scope of a binding is constrained to its environment. A singleton bound in a private
     73  * module will be unique to its environment. But a binding for the same type in a different private
     74  * module will yield a different instance.
     75  *
     76  * <p>A shared binding that injects the {@code Injector} gets the root injector, which only has
     77  * access to bindings in the root environment. An explicit binding that injects the {@code Injector}
     78  * gets access to all bindings in the child environment.
     79  *
     80  * <p>To promote a just-in-time binding to an explicit binding, bind it:
     81  *
     82  * <pre>
     83  *   bind(FooImpl.class);
     84  * </pre>
     85  *
     86  * @author jessewilson (at) google.com (Jesse Wilson)
     87  * @since 2.0
     88  */
     89 public abstract class PrivateModule implements Module {
     90 
     91   /** Like abstract module, the binder of the current private module */
     92   private PrivateBinder binder;
     93 
     94   @Override
     95   public final synchronized void configure(Binder binder) {
     96     checkState(this.binder == null, "Re-entry is not allowed.");
     97 
     98     // Guice treats PrivateModules specially and passes in a PrivateBinder automatically.
     99     this.binder = (PrivateBinder) binder.skipSources(PrivateModule.class);
    100     try {
    101       configure();
    102     } finally {
    103       this.binder = null;
    104     }
    105   }
    106 
    107   /**
    108    * Creates bindings and other configurations private to this module. Use {@link #expose(Class)
    109    * expose()} to make the bindings in this module available externally.
    110    */
    111   protected abstract void configure();
    112 
    113   /** Makes the binding for {@code key} available to other modules and the injector. */
    114   protected final <T> void expose(Key<T> key) {
    115     binder().expose(key);
    116   }
    117 
    118   /**
    119    * Makes a binding for {@code type} available to other modules and the injector. Use {@link
    120    * AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type} with a
    121    * binding annotation.
    122    */
    123   protected final AnnotatedElementBuilder expose(Class<?> type) {
    124     return binder().expose(type);
    125   }
    126 
    127   /**
    128    * Makes a binding for {@code type} available to other modules and the injector. Use {@link
    129    * AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type} with a
    130    * binding annotation.
    131    */
    132   protected final AnnotatedElementBuilder expose(TypeLiteral<?> type) {
    133     return binder().expose(type);
    134   }
    135 
    136   // everything below is copied from AbstractModule
    137 
    138   /** Returns the current binder. */
    139   protected final PrivateBinder binder() {
    140     checkState(binder != null, "The binder can only be used inside configure()");
    141     return binder;
    142   }
    143 
    144   /** @see Binder#bindScope(Class, Scope) */
    145   protected final void bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) {
    146     binder().bindScope(scopeAnnotation, scope);
    147   }
    148 
    149   /** @see Binder#bind(Key) */
    150   protected final <T> LinkedBindingBuilder<T> bind(Key<T> key) {
    151     return binder().bind(key);
    152   }
    153 
    154   /** @see Binder#bind(TypeLiteral) */
    155   protected final <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
    156     return binder().bind(typeLiteral);
    157   }
    158 
    159   /** @see Binder#bind(Class) */
    160   protected final <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
    161     return binder().bind(clazz);
    162   }
    163 
    164   /** @see Binder#bindConstant() */
    165   protected final AnnotatedConstantBindingBuilder bindConstant() {
    166     return binder().bindConstant();
    167   }
    168 
    169   /** @see Binder#install(Module) */
    170   protected final void install(Module module) {
    171     binder().install(module);
    172   }
    173 
    174   /** @see Binder#addError(String, Object[]) */
    175   protected final void addError(String message, Object... arguments) {
    176     binder().addError(message, arguments);
    177   }
    178 
    179   /** @see Binder#addError(Throwable) */
    180   protected final void addError(Throwable t) {
    181     binder().addError(t);
    182   }
    183 
    184   /** @see Binder#addError(Message) */
    185   protected final void addError(Message message) {
    186     binder().addError(message);
    187   }
    188 
    189   /** @see Binder#requestInjection(Object) */
    190   protected final void requestInjection(Object instance) {
    191     binder().requestInjection(instance);
    192   }
    193 
    194   /** @see Binder#requestStaticInjection(Class[]) */
    195   protected final void requestStaticInjection(Class<?>... types) {
    196     binder().requestStaticInjection(types);
    197   }
    198 
    199   /*if[AOP]*/
    200   /**
    201    * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher,
    202    *     com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
    203    */
    204   protected final void bindInterceptor(
    205       Matcher<? super Class<?>> classMatcher,
    206       Matcher<? super Method> methodMatcher,
    207       org.aopalliance.intercept.MethodInterceptor... interceptors) {
    208     binder().bindInterceptor(classMatcher, methodMatcher, interceptors);
    209   }
    210   /*end[AOP]*/
    211 
    212   /** Instructs Guice to require a binding to the given key. */
    213   protected final void requireBinding(Key<?> key) {
    214     binder().getProvider(key);
    215   }
    216 
    217   /** Instructs Guice to require a binding to the given type. */
    218   protected final void requireBinding(Class<?> type) {
    219     binder().getProvider(type);
    220   }
    221 
    222   /** @see Binder#getProvider(Key) */
    223   protected final <T> Provider<T> getProvider(Key<T> key) {
    224     return binder().getProvider(key);
    225   }
    226 
    227   /** @see Binder#getProvider(Class) */
    228   protected final <T> Provider<T> getProvider(Class<T> type) {
    229     return binder().getProvider(type);
    230   }
    231 
    232   /**
    233    * @see Binder#convertToTypes(com.google.inject.matcher.Matcher,
    234    *     com.google.inject.spi.TypeConverter)
    235    */
    236   protected final void convertToTypes(
    237       Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) {
    238     binder().convertToTypes(typeMatcher, converter);
    239   }
    240 
    241   /** @see Binder#currentStage() */
    242   protected final Stage currentStage() {
    243     return binder().currentStage();
    244   }
    245 
    246   /** @see Binder#getMembersInjector(Class) */
    247   protected <T> MembersInjector<T> getMembersInjector(Class<T> type) {
    248     return binder().getMembersInjector(type);
    249   }
    250 
    251   /** @see Binder#getMembersInjector(TypeLiteral) */
    252   protected <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
    253     return binder().getMembersInjector(type);
    254   }
    255 
    256   /**
    257    * @see Binder#bindListener(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeListener)
    258    */
    259   protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) {
    260     binder().bindListener(typeMatcher, listener);
    261   }
    262 
    263   /**
    264    * @see Binder#bindListener(Matcher, ProvisionListener...)
    265    * @since 4.0
    266    */
    267   protected void bindListener(
    268       Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners) {
    269     binder().bindListener(bindingMatcher, listeners);
    270   }
    271 }
    272