Home | History | Annotate | Download | only in internal
      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.internal;
     18 
     19 import com.google.inject.Binder;
     20 import com.google.inject.Binding;
     21 import com.google.inject.Key;
     22 import com.google.inject.Provider;
     23 import com.google.inject.spi.ConstructorBinding;
     24 import com.google.inject.spi.ConvertedConstantBinding;
     25 import com.google.inject.spi.ExposedBinding;
     26 import com.google.inject.spi.InjectionPoint;
     27 import com.google.inject.spi.InstanceBinding;
     28 import com.google.inject.spi.LinkedKeyBinding;
     29 import com.google.inject.spi.PrivateElements;
     30 import com.google.inject.spi.ProviderBinding;
     31 import com.google.inject.spi.ProviderInstanceBinding;
     32 import com.google.inject.spi.ProviderKeyBinding;
     33 import com.google.inject.spi.UntargettedBinding;
     34 
     35 import java.util.Set;
     36 
     37 /**
     38  * Handles {@link Binder#bind} and {@link Binder#bindConstant} elements.
     39  *
     40  * @author crazybob (at) google.com (Bob Lee)
     41  * @author jessewilson (at) google.com (Jesse Wilson)
     42  */
     43 final class BindingProcessor extends AbstractBindingProcessor {
     44 
     45   private final Initializer initializer;
     46 
     47   BindingProcessor(Errors errors, Initializer initializer, ProcessedBindingData bindingData) {
     48     super(errors, bindingData);
     49     this.initializer = initializer;
     50   }
     51 
     52   @Override public <T> Boolean visit(Binding<T> command) {
     53     Class<?> rawType = command.getKey().getTypeLiteral().getRawType();
     54     if (Void.class.equals(rawType)) {
     55       if (command instanceof ProviderInstanceBinding
     56           && ((ProviderInstanceBinding) command).getUserSuppliedProvider()
     57               instanceof ProviderMethod) {
     58         errors.voidProviderMethod();
     59       } else {
     60         errors.missingConstantValues();
     61       }
     62       return true;
     63     }
     64 
     65     if (rawType == Provider.class) {
     66       errors.bindingToProvider();
     67       return true;
     68     }
     69 
     70     return command.acceptTargetVisitor(new Processor<T, Boolean>((BindingImpl<T>)command) {
     71       @Override
     72       public Boolean visit(ConstructorBinding<? extends T> binding) {
     73         prepareBinding();
     74         try {
     75           ConstructorBindingImpl<T> onInjector = ConstructorBindingImpl.create(injector, key,
     76               binding.getConstructor(), source, scoping, errors, false, false);
     77           scheduleInitialization(onInjector);
     78           putBinding(onInjector);
     79         } catch (ErrorsException e) {
     80           errors.merge(e.getErrors());
     81           putBinding(invalidBinding(injector, key, source));
     82         }
     83         return true;
     84       }
     85 
     86       @Override
     87       public Boolean visit(InstanceBinding<? extends T> binding) {
     88         prepareBinding();
     89         Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
     90         T instance = binding.getInstance();
     91         @SuppressWarnings("unchecked") // safe to cast to binding<T> because
     92                                        // the processor was constructed w/ it
     93         Initializable<T> ref = initializer.requestInjection(
     94             injector, instance, (Binding<T>) binding, source, injectionPoints);
     95         ConstantFactory<? extends T> factory = new ConstantFactory<T>(ref);
     96         InternalFactory<? extends T> scopedFactory
     97             = Scoping.scope(key, injector, factory, source, scoping);
     98         putBinding(new InstanceBindingImpl<T>(injector, key, source, scopedFactory, injectionPoints,
     99             instance));
    100         return true;
    101       }
    102 
    103       @Override
    104       public Boolean visit(ProviderInstanceBinding<? extends T> binding) {
    105         prepareBinding();
    106         javax.inject.Provider<? extends T> provider = binding.getUserSuppliedProvider();
    107         Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
    108         Initializable<? extends javax.inject.Provider<? extends T>> initializable =
    109             initializer.<javax.inject.Provider<? extends T>>requestInjection(
    110                 injector, provider, null, source, injectionPoints);
    111         // always visited with Binding<T>
    112         @SuppressWarnings("unchecked")
    113         InternalFactory<T> factory = new InternalFactoryToInitializableAdapter<T>(
    114             initializable, source,
    115             injector.provisionListenerStore.get((ProviderInstanceBinding<T>)binding));
    116         InternalFactory<? extends T> scopedFactory
    117             = Scoping.scope(key, injector, factory, source, scoping);
    118         putBinding(new ProviderInstanceBindingImpl<T>(injector, key, source, scopedFactory, scoping,
    119             provider, injectionPoints));
    120         return true;
    121       }
    122 
    123       @Override
    124       public Boolean visit(ProviderKeyBinding<? extends T> binding) {
    125         prepareBinding();
    126         Key<? extends javax.inject.Provider<? extends T>> providerKey = binding.getProviderKey();
    127         // always visited with Binding<T>
    128         @SuppressWarnings("unchecked")
    129         BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>(
    130             injector, providerKey, source,
    131             injector.provisionListenerStore.get((ProviderKeyBinding<T>) binding));
    132         bindingData.addCreationListener(boundProviderFactory);
    133         InternalFactory<? extends T> scopedFactory = Scoping.scope(
    134             key, injector, (InternalFactory<? extends T>) boundProviderFactory, source, scoping);
    135         putBinding(new LinkedProviderBindingImpl<T>(
    136             injector, key, source, scopedFactory, scoping, providerKey));
    137         return true;
    138       }
    139 
    140       @Override
    141       public Boolean visit(LinkedKeyBinding<? extends T> binding) {
    142         prepareBinding();
    143         Key<? extends T> linkedKey = binding.getLinkedKey();
    144         if (key.equals(linkedKey)) {
    145           errors.recursiveBinding();
    146         }
    147 
    148         FactoryProxy<T> factory = new FactoryProxy<T>(injector, key, linkedKey, source);
    149         bindingData.addCreationListener(factory);
    150         InternalFactory<? extends T> scopedFactory
    151             = Scoping.scope(key, injector, factory, source, scoping);
    152         putBinding(
    153             new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey));
    154         return true;
    155       }
    156 
    157       @Override
    158       public Boolean visit(UntargettedBinding<? extends T> untargetted) {
    159         return false;
    160       }
    161 
    162       @Override
    163       public Boolean visit(ExposedBinding<? extends T> binding) {
    164         throw new IllegalArgumentException("Cannot apply a non-module element");
    165       }
    166 
    167       @Override
    168       public Boolean visit(ConvertedConstantBinding<? extends T> binding) {
    169         throw new IllegalArgumentException("Cannot apply a non-module element");
    170       }
    171 
    172       @Override
    173       public Boolean visit(ProviderBinding<? extends T> binding) {
    174         throw new IllegalArgumentException("Cannot apply a non-module element");
    175       }
    176 
    177       @Override
    178       protected Boolean visitOther(Binding<? extends T> binding) {
    179         throw new IllegalStateException("BindingProcessor should override all visitations");
    180       }
    181     });
    182   }
    183 
    184   @Override public Boolean visit(PrivateElements privateElements) {
    185     for (Key<?> key : privateElements.getExposedKeys()) {
    186       bindExposed(privateElements, key);
    187     }
    188     return false; // leave the private elements for the PrivateElementsProcessor to handle
    189   }
    190 
    191   private <T> void bindExposed(PrivateElements privateElements, Key<T> key) {
    192     ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateElements);
    193     bindingData.addCreationListener(exposedKeyFactory);
    194     putBinding(new ExposedBindingImpl<T>(
    195         injector, privateElements.getExposedSource(key), key, exposedKeyFactory, privateElements));
    196   }
    197 }
    198