| /** |
| * Copyright (C) 2008 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.google.inject.internal; |
| |
| import com.google.inject.Binder; |
| import com.google.inject.Binding; |
| import com.google.inject.Key; |
| import com.google.inject.Provider; |
| import com.google.inject.spi.ConstructorBinding; |
| import com.google.inject.spi.ConvertedConstantBinding; |
| import com.google.inject.spi.ExposedBinding; |
| import com.google.inject.spi.InjectionPoint; |
| import com.google.inject.spi.InstanceBinding; |
| import com.google.inject.spi.LinkedKeyBinding; |
| import com.google.inject.spi.PrivateElements; |
| import com.google.inject.spi.ProviderBinding; |
| import com.google.inject.spi.ProviderInstanceBinding; |
| import com.google.inject.spi.ProviderKeyBinding; |
| import com.google.inject.spi.UntargettedBinding; |
| |
| import java.util.Set; |
| |
| /** |
| * Handles {@link Binder#bind} and {@link Binder#bindConstant} elements. |
| * |
| * @author crazybob@google.com (Bob Lee) |
| * @author jessewilson@google.com (Jesse Wilson) |
| */ |
| final class BindingProcessor extends AbstractBindingProcessor { |
| |
| private final Initializer initializer; |
| |
| BindingProcessor(Errors errors, Initializer initializer, ProcessedBindingData bindingData) { |
| super(errors, bindingData); |
| this.initializer = initializer; |
| } |
| |
| @Override public <T> Boolean visit(Binding<T> command) { |
| Class<?> rawType = command.getKey().getTypeLiteral().getRawType(); |
| if (Void.class.equals(rawType)) { |
| if (command instanceof ProviderInstanceBinding |
| && ((ProviderInstanceBinding) command).getProviderInstance() instanceof ProviderMethod) { |
| errors.voidProviderMethod(); |
| } else { |
| errors.missingConstantValues(); |
| } |
| return true; |
| } |
| |
| if (rawType == Provider.class) { |
| errors.bindingToProvider(); |
| return true; |
| } |
| |
| return command.acceptTargetVisitor(new Processor<T, Boolean>((BindingImpl<T>)command) { |
| @Override |
| public Boolean visit(ConstructorBinding<? extends T> binding) { |
| prepareBinding(); |
| try { |
| ConstructorBindingImpl<T> onInjector = ConstructorBindingImpl.create(injector, key, |
| binding.getConstructor(), source, scoping, errors, false, false); |
| scheduleInitialization(onInjector); |
| putBinding(onInjector); |
| } catch (ErrorsException e) { |
| errors.merge(e.getErrors()); |
| putBinding(invalidBinding(injector, key, source)); |
| } |
| return true; |
| } |
| |
| @Override |
| public Boolean visit(InstanceBinding<? extends T> binding) { |
| prepareBinding(); |
| Set<InjectionPoint> injectionPoints = binding.getInjectionPoints(); |
| T instance = binding.getInstance(); |
| @SuppressWarnings("unchecked") // safe to cast to binding<T> because |
| // the processor was constructed w/ it |
| Initializable<T> ref = initializer.requestInjection( |
| injector, instance, (Binding<T>) binding, source, injectionPoints); |
| ConstantFactory<? extends T> factory = new ConstantFactory<T>(ref); |
| InternalFactory<? extends T> scopedFactory |
| = Scoping.scope(key, injector, factory, source, scoping); |
| putBinding(new InstanceBindingImpl<T>(injector, key, source, scopedFactory, injectionPoints, |
| instance)); |
| return true; |
| } |
| |
| @Override |
| public Boolean visit(ProviderInstanceBinding<? extends T> binding) { |
| prepareBinding(); |
| Provider<? extends T> provider = binding.getProviderInstance(); |
| Set<InjectionPoint> injectionPoints = binding.getInjectionPoints(); |
| Initializable<Provider<? extends T>> initializable = initializer |
| .<Provider<? extends T>>requestInjection(injector, provider, null, source, injectionPoints); |
| // always visited with Binding<T> |
| @SuppressWarnings("unchecked") |
| InternalFactory<T> factory = new InternalFactoryToInitializableAdapter<T>( |
| initializable, source, !injector.options.disableCircularProxies, |
| injector.provisionListenerStore.get((ProviderInstanceBinding<T>)binding)); |
| InternalFactory<? extends T> scopedFactory |
| = Scoping.scope(key, injector, factory, source, scoping); |
| putBinding(new ProviderInstanceBindingImpl<T>(injector, key, source, scopedFactory, scoping, |
| provider, injectionPoints)); |
| return true; |
| } |
| |
| @Override |
| public Boolean visit(ProviderKeyBinding<? extends T> binding) { |
| prepareBinding(); |
| Key<? extends javax.inject.Provider<? extends T>> providerKey = binding.getProviderKey(); |
| // always visited with Binding<T> |
| @SuppressWarnings("unchecked") |
| BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>( |
| injector, providerKey, source, !injector.options.disableCircularProxies, |
| injector.provisionListenerStore.get((ProviderKeyBinding<T>)binding)); |
| bindingData.addCreationListener(boundProviderFactory); |
| InternalFactory<? extends T> scopedFactory = Scoping.scope( |
| key, injector, (InternalFactory<? extends T>) boundProviderFactory, source, scoping); |
| putBinding(new LinkedProviderBindingImpl<T>( |
| injector, key, source, scopedFactory, scoping, providerKey)); |
| return true; |
| } |
| |
| @Override |
| public Boolean visit(LinkedKeyBinding<? extends T> binding) { |
| prepareBinding(); |
| Key<? extends T> linkedKey = binding.getLinkedKey(); |
| if (key.equals(linkedKey)) { |
| errors.recursiveBinding(); |
| } |
| |
| FactoryProxy<T> factory = new FactoryProxy<T>(injector, key, linkedKey, source); |
| bindingData.addCreationListener(factory); |
| InternalFactory<? extends T> scopedFactory |
| = Scoping.scope(key, injector, factory, source, scoping); |
| putBinding( |
| new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey)); |
| return true; |
| } |
| |
| @Override |
| public Boolean visit(UntargettedBinding<? extends T> untargetted) { |
| return false; |
| } |
| |
| @Override |
| public Boolean visit(ExposedBinding<? extends T> binding) { |
| throw new IllegalArgumentException("Cannot apply a non-module element"); |
| } |
| |
| @Override |
| public Boolean visit(ConvertedConstantBinding<? extends T> binding) { |
| throw new IllegalArgumentException("Cannot apply a non-module element"); |
| } |
| |
| @Override |
| public Boolean visit(ProviderBinding<? extends T> binding) { |
| throw new IllegalArgumentException("Cannot apply a non-module element"); |
| } |
| |
| @Override |
| protected Boolean visitOther(Binding<? extends T> binding) { |
| throw new IllegalStateException("BindingProcessor should override all visitations"); |
| } |
| }); |
| } |
| |
| @Override public Boolean visit(PrivateElements privateElements) { |
| for (Key<?> key : privateElements.getExposedKeys()) { |
| bindExposed(privateElements, key); |
| } |
| return false; // leave the private elements for the PrivateElementsProcessor to handle |
| } |
| |
| private <T> void bindExposed(PrivateElements privateElements, Key<T> key) { |
| ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateElements); |
| bindingData.addCreationListener(exposedKeyFactory); |
| putBinding(new ExposedBindingImpl<T>( |
| injector, privateElements.getExposedSource(key), key, exposedKeyFactory, privateElements)); |
| } |
| } |