All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.inject.internal.InjectorShell Maven / Gradle / Ivy

The newest version!
/*
 * 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 static com.google.common.base.Preconditions.checkState;
import static com.google.inject.Scopes.SINGLETON;
import static com.google.inject.internal.GuiceInternal.GUICE_INTERNAL;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.inject.Binder;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.Stage;
import com.google.inject.internal.InjectorImpl.InjectorOptions;
import com.google.inject.internal.util.ContinuousStopwatch;
import com.google.inject.internal.util.SourceProvider;
import com.google.inject.spi.BindingSourceRestriction;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.Element;
import com.google.inject.spi.Elements;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
import com.google.inject.spi.PrivateElements;
import com.google.inject.spi.ProvisionListenerBinding;
import com.google.inject.spi.TypeListenerBinding;
import java.util.List;
import java.util.Optional;
import java.util.logging.Logger;

/**
 * InjectorShell is used by {@link InternalInjectorCreator} to recursively create a tree of
 * uninitialized {@link Injector}s. Each InjectorShell corresponds to either the top-level root
 * injector, or a private child injector.
 *
 * 

The root InjectorShell extracts elements from its list of modules and processes these elements * to aggregate data that is used to populate its injector's fields. Child injectors are constructed * similarly, but using {@link PrivateElements} instead of modules. * *

It is necessary to create the root and child injectors in a single batch because there can be * bidirectional parent <-> child injector dependencies that require the entire tree of injectors to * be initialized together in the {@link InternalInjectorCreator}. * * @author [email protected] (Jesse Wilson) */ final class InjectorShell { private final List elements; private final InjectorImpl injector; private InjectorShell(List elements, InjectorImpl injector) { this.elements = elements; this.injector = injector; } InjectorImpl getInjector() { return injector; } List getElements() { return elements; } static class Builder { private final List elements = Lists.newArrayList(); private final List modules = Lists.newArrayList(); // lazily constructed fields private InjectorBindingData bindingData; private InjectorJitBindingData jitBindingData; private InjectorImpl parent; private InjectorOptions options; private Stage stage; /** null unless this exists in a {@link Binder#newPrivateBinder private environment} */ private PrivateElementsImpl privateElements; Builder stage(Stage stage) { this.stage = stage; return this; } Builder parent(InjectorImpl parent) { this.parent = parent; this.jitBindingData = new InjectorJitBindingData(Optional.of(parent.getJitBindingData())); this.bindingData = new InjectorBindingData(Optional.of(parent.getBindingData())); this.options = parent.options; this.stage = options.stage; return this; } Builder privateElements(PrivateElements privateElements) { this.privateElements = (PrivateElementsImpl) privateElements; this.elements.addAll(privateElements.getElements()); return this; } void addModules(Iterable modules) { for (Module module : modules) { this.modules.add(module); } } Stage getStage() { return options.stage; } /** Synchronize on this before calling {@link #build}. */ Object lock() { // Lazily initializes bindingData and jitBindingData, if they were not already // initialized with a parent injector by {@link #parent(InjectorImpl)}. if (bindingData == null) { jitBindingData = new InjectorJitBindingData(Optional.empty()); bindingData = new InjectorBindingData(Optional.empty()); } return jitBindingData.lock(); } /** * Creates and returns the injector shells for the current modules. Multiple shells will be * returned if any modules contain {@link Binder#newPrivateBinder private environments}. The * primary injector will be first in the returned list. */ List build( Initializer initializer, ProcessedBindingData processedBindingData, ContinuousStopwatch stopwatch, Errors errors) { checkState(stage != null, "Stage not initialized"); checkState(privateElements == null || parent != null, "PrivateElements with no parent"); checkState(bindingData != null, "no binding data. Did you remember to lock() ?"); checkState( (privateElements == null && elements.isEmpty()) || modules.isEmpty(), "The shell is either built from modules (root) or from PrivateElements (children)."); // bind Singleton if this is a top-level injector if (parent == null) { modules.add(0, new RootModule()); } else { modules.add(0, new InheritedScannersModule(parent.getBindingData())); } elements.addAll(Elements.getElements(stage, modules)); // Check binding source restrictions only for the root shell (note that the root shell // can have a parent Injector, when Injector.createChildInjector is called). It isn't // necessary to call this check on child PrivateElements shells because it walks the entire // tree of elements, recurring on PrivateElements. if (privateElements == null) { elements.addAll(BindingSourceRestriction.check(GUICE_INTERNAL, elements)); } // Look for injector-changing options InjectorOptionsProcessor optionsProcessor = new InjectorOptionsProcessor(errors); optionsProcessor.process(null, elements); options = optionsProcessor.getOptions(stage, options); InjectorImpl injector = new InjectorImpl(parent, bindingData, jitBindingData, options); if (privateElements != null) { privateElements.initInjector(injector); } // add default type converters if this is a top-level injector if (parent == null) { TypeConverterBindingProcessor.prepareBuiltInConverters(injector); } stopwatch.resetAndLog("Module execution"); new MessageProcessor(errors).process(injector, elements); new InterceptorBindingProcessor(errors).process(injector, elements); stopwatch.resetAndLog("Interceptors creation"); new ListenerBindingProcessor(errors).process(injector, elements); List typeListenerBindings = injector.getBindingData().getTypeListenerBindings(); injector.membersInjectorStore = new MembersInjectorStore(injector, typeListenerBindings); List provisionListenerBindings = injector.getBindingData().getProvisionListenerBindings(); injector.provisionListenerStore = new ProvisionListenerCallbackStore(provisionListenerBindings); stopwatch.resetAndLog("TypeListeners & ProvisionListener creation"); new ScopeBindingProcessor(errors).process(injector, elements); stopwatch.resetAndLog("Scopes creation"); new TypeConverterBindingProcessor(errors).process(injector, elements); stopwatch.resetAndLog("Converters creation"); bindStage(injector, stage); bindInjector(injector); bindLogger(injector); // Process all normal bindings, then UntargettedBindings. // This is necessary because UntargettedBindings can create JIT bindings // and need all their other dependencies set up ahead of time. new BindingProcessor(errors, initializer, processedBindingData).process(injector, elements); new UntargettedBindingProcessor(errors, processedBindingData).process(injector, elements); stopwatch.resetAndLog("Binding creation"); new ModuleAnnotatedMethodScannerProcessor(errors).process(injector, elements); stopwatch.resetAndLog("Module annotated method scanners creation"); List injectorShells = Lists.newArrayList(); injectorShells.add(new InjectorShell(elements, injector)); // recursively build child shells PrivateElementProcessor processor = new PrivateElementProcessor(errors); processor.process(injector, elements); for (Builder builder : processor.getInjectorShellBuilders()) { injectorShells.addAll(builder.build(initializer, processedBindingData, stopwatch, errors)); } stopwatch.resetAndLog("Private environment creation"); return injectorShells; } } /** * The Injector is a special case because we allow both parent and child injectors to both have a * binding for that key. */ private static void bindInjector(InjectorImpl injector) { Key key = Key.get(Injector.class); InjectorFactory injectorFactory = new InjectorFactory(injector); injector .getBindingData() .putBinding( key, new ProviderInstanceBindingImpl( injector, key, SourceProvider.UNKNOWN_SOURCE, injectorFactory, Scoping.UNSCOPED, injectorFactory, ImmutableSet.of())); } private static class InjectorFactory implements InternalFactory, Provider { private final Injector injector; private InjectorFactory(Injector injector) { this.injector = injector; } @Override public Injector get(InternalContext context, Dependency dependency, boolean linked) { return injector; } @Override public Injector get() { return injector; } @Override public String toString() { return "Provider"; } } /** * The Logger is a special case because it knows the injection point of the injected member. It's * the only binding that does this. */ private static void bindLogger(InjectorImpl injector) { Key key = Key.get(Logger.class); LoggerFactory loggerFactory = new LoggerFactory(); injector .getBindingData() .putBinding( key, new ProviderInstanceBindingImpl( injector, key, SourceProvider.UNKNOWN_SOURCE, loggerFactory, Scoping.UNSCOPED, loggerFactory, ImmutableSet.of())); } private static class LoggerFactory implements InternalFactory, Provider { @Override public Logger get(InternalContext context, Dependency dependency, boolean linked) { InjectionPoint injectionPoint = dependency.getInjectionPoint(); return injectionPoint == null ? Logger.getAnonymousLogger() : Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); } @Override public Logger get() { return Logger.getAnonymousLogger(); } @Override public String toString() { return "Provider"; } } private static void bindStage(InjectorImpl injector, Stage stage) { Key key = Key.get(Stage.class); InstanceBindingImpl stageBinding = new InstanceBindingImpl( injector, key, SourceProvider.UNKNOWN_SOURCE, new ConstantFactory(Initializables.of(stage)), ImmutableSet.of(), stage); injector.getBindingData().putBinding(key, stageBinding); } private static class RootModule implements Module { @Override public void configure(Binder binder) { binder = binder.withSource(SourceProvider.UNKNOWN_SOURCE); binder.bindScope(Singleton.class, SINGLETON); binder.bindScope(javax.inject.Singleton.class, SINGLETON); } } private static class InheritedScannersModule implements Module { private final InjectorBindingData bindingData; InheritedScannersModule(InjectorBindingData bindingData) { this.bindingData = bindingData; } @Override public void configure(Binder binder) { for (ModuleAnnotatedMethodScannerBinding binding : bindingData.getScannerBindings()) { binding.applyTo(binder); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy