This example Java source code file (InjectorImpl.java) is included in the alvinalexander.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
/**
* Copyright (C) 2006 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.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.ConfigurationException;
import com.google.inject.ImplementedBy;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Module;
import com.google.inject.ProvidedBy;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import com.google.inject.Scope;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.util.SourceProvider;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.ConvertedConstantBinding;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.ProviderBinding;
import com.google.inject.spi.TypeConverterBinding;
import com.google.inject.util.Providers;
import java.lang.annotation.Annotation;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Default {@link Injector} implementation.
*
* @author crazybob@google.com (Bob Lee)
*/
final class InjectorImpl implements Injector, Lookups {
public static final TypeLiteral<String> STRING_TYPE = TypeLiteral.get(String.class);
/** Options that control how the injector behaves. */
static class InjectorOptions {
final Stage stage;
final boolean jitDisabled;
final boolean disableCircularProxies;
final boolean atInjectRequired;
final boolean exactBindingAnnotationsRequired;
InjectorOptions(Stage stage, boolean jitDisabled, boolean disableCircularProxies,
boolean atInjectRequired, boolean exactBindingAnnotationsRequired) {
this.stage = stage;
this.jitDisabled = jitDisabled;
this.disableCircularProxies = disableCircularProxies;
this.atInjectRequired = atInjectRequired;
this.exactBindingAnnotationsRequired = exactBindingAnnotationsRequired;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("stage", stage)
.add("jitDisabled", jitDisabled)
.add("disableCircularProxies", disableCircularProxies)
.add("atInjectRequired", atInjectRequired)
.add("exactBindingAnnotationsRequired", exactBindingAnnotationsRequired)
.toString();
}
}
/** some limitations on what just in time bindings are allowed. */
enum JitLimitation {
/** does not allow just in time bindings */
NO_JIT,
/** allows existing just in time bindings, but does not allow new ones */
EXISTING_JIT,
/** allows existing just in time bindings & allows new ones to be created */
NEW_OR_EXISTING_JIT,
}
final State state;
final InjectorImpl parent;
final BindingsMultimap bindingsMultimap = new BindingsMultimap();
final InjectorOptions options;
/** Just-in-time binding cache. Guarded by state.lock() */
final Map<Key>, BindingImpl>> jitBindings = Maps.newHashMap();
/**
* Cache of Keys that we were unable to create JIT bindings for, so we don't
* keep trying. Also guarded by state.lock().
*/
final Set<Key>> failedJitBindings = Sets.newHashSet();
Lookups lookups = new DeferredLookups(this);
InjectorImpl(InjectorImpl parent, State state, InjectorOptions injectorOptions) {
this.parent = parent;
this.state = state;
this.options = injectorOptions;
if (parent != null) {
localContext = parent.localContext;
} else {
// No ThreadLocal.initialValue(), as that would cause classloader leaks. See
// https://github.com/google/guice/issues/288#issuecomment-48216933,
// https://github.com/google/guice/issues/288#issuecomment-48216944
localContext = new ThreadLocal<Object[]>();
}
}
/** Indexes bindings by type. */
void index() {
for (Binding<?> binding : state.getExplicitBindingsThisLevel().values()) {
index(binding);
}
}
<T> void index(Binding binding) {
bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
}
public <T> List> findBindingsByType(TypeLiteral type) {
return bindingsMultimap.getAll(type);
}
/** Returns the binding for {@code key} */
public <T> BindingImpl getBinding(Key key) {
Errors errors = new Errors(key);
try {
BindingImpl<T> result = getBindingOrThrow(key, errors, JitLimitation.EXISTING_JIT);
errors.throwConfigurationExceptionIfErrorsExist();
return result;
} catch (ErrorsException e) {
throw new ConfigurationException(errors.merge(e.getErrors()).getMessages());
}
}
public <T> BindingImpl getExistingBinding(Key key) {
// Check explicit bindings, i.e. bindings created by modules.
BindingImpl<T> explicitBinding = state.getExplicitBinding(key);
if (explicitBinding != null) {
return explicitBinding;
}
synchronized (state.lock()) {
// See if any jit bindings have been created for this key.
for (InjectorImpl injector = this; injector != null; injector = injector.parent) {
@SuppressWarnings("unchecked")
BindingImpl<T> jitBinding = (BindingImpl) injector.jitBindings.get(key);
if(jitBinding != null) {
return jitBinding;
}
}
}
// If Key is a Provider, we have to see if the type it is providing exists,
// and, if so, we have to create the binding for the provider.
if(isProvider(key)) {
try {
// This is safe because isProvider above ensures that T is a Provider<?>
@SuppressWarnings({"unchecked", "cast"})
Key<?> providedKey = (Key>)getProvidedKey((Key)key, new Errors());
if(getExistingBinding(providedKey) != null) {
return getBinding(key);
}
} catch(ErrorsException e) {
throw new ConfigurationException(e.getErrors().getMessages());
}
}
// No existing binding exists.
return null;
}
/**
* Gets a binding implementation. First, it check to see if the parent has a binding. If the
* parent has a binding and the binding is scoped, it will use that binding. Otherwise, this
* checks for an explicit binding. If no explicit binding is found, it looks for a just-in-time
* binding.
*/
<T> BindingImpl getBindingOrThrow(Key key, Errors errors, JitLimitation jitType)
throws ErrorsException {
// Check explicit bindings, i.e. bindings created by modules.
BindingImpl<T> binding = state.getExplicitBinding(key);
if (binding != null) {
return binding;
}
// Look for an on-demand binding.
return getJustInTimeBinding(key, errors, jitType);
}
public <T> Binding getBinding(Class type) {
return getBinding(Key.get(type));
}
public Injector getParent() {
return parent;
}
public Injector createChildInjector(Iterable<? extends Module> modules) {
return new InternalInjectorCreator()
.parentInjector(this)
.addModules(modules)
.build();
}
public Injector createChildInjector(Module... modules) {
return createChildInjector(ImmutableList.copyOf(modules));
}
/**
* Returns a just-in-time binding for {@code key}, creating it if necessary.
*
* @throws ErrorsException if the binding could not be created.
*/
private <T> BindingImpl getJustInTimeBinding(Key key, Errors errors, JitLimitation jitType)
throws ErrorsException {
boolean jitOverride = isProvider(key) || isTypeLiteral(key) || isMembersInjector(key);
synchronized (state.lock()) {
// first try to find a JIT binding that we've already created
for (InjectorImpl injector = this; injector != null; injector = injector.parent) {
@SuppressWarnings("unchecked") // we only store bindings that match their key
BindingImpl<T> binding = (BindingImpl) injector.jitBindings.get(key);
if (binding != null) {
// If we found a JIT binding and we don't allow them,
// fail. (But allow bindings created through TypeConverters.)
if (options.jitDisabled
&& jitType == JitLimitation.NO_JIT
&& !jitOverride
&& !(binding instanceof ConvertedConstantBindingImpl)) {
throw errors.jitDisabled(key).toException();
} else {
return binding;
}
}
}
// If we previously failed creating this JIT binding and our Errors has
// already recorded an error, then just directly throw that error.
// We need to do this because it's possible we already cleaned up the
// entry in jitBindings (during cleanup), and we may be trying
// to create it again (in the case of a recursive JIT binding).
// We need both of these guards for different reasons
// failedJitBindings.contains: We want to continue processing if we've never
// failed before, so that our initial error message contains
// as much useful information as possible about what errors exist.
// errors.hasErrors: If we haven't already failed, then it's OK to
// continue processing, to make sure the ultimate error message
// is the correct one.
// See: ImplicitBindingsTest#testRecursiveJitBindingsCleanupCorrectly
// for where this guard compes into play.
if (failedJitBindings.contains(key) && errors.hasErrors()) {
throw errors.toException();
}
return createJustInTimeBindingRecursive(key, errors, options.jitDisabled, jitType);
} // end synchronized(state.lock())
}
/** Returns true if the key type is Provider (but not a subclass of Provider). */
private static boolean isProvider(Key<?> key) {
return key.getTypeLiteral().getRawType().equals(Provider.class);
}
private static boolean isTypeLiteral(Key<?> key) {
return key.getTypeLiteral().getRawType().equals(TypeLiteral.class);
}
private static <T> Key getProvidedKey(Key> key, Errors errors) throws ErrorsException {
Type providerType = key.getTypeLiteral().getType();
// If the Provider has no type parameter (raw Provider)...
if (!(providerType instanceof ParameterizedType)) {
throw errors.cannotInjectRawProvider().toException();
}
Type entryType = ((ParameterizedType) providerType).getActualTypeArguments()[0];
@SuppressWarnings("unchecked") // safe because T came from Key<Provider
Key<T> providedKey = (Key) key.ofType(entryType);
return providedKey;
}
/** Returns true if the key type is MembersInjector (but not a subclass of MembersInjector). */
private static boolean isMembersInjector(Key<?> key) {
return key.getTypeLiteral().getRawType().equals(MembersInjector.class)
&& key.getAnnotationType() == null;
}
private <T> BindingImpl> createMembersInjectorBinding(
Key<MembersInjector key, Errors errors) throws ErrorsException {
Type membersInjectorType = key.getTypeLiteral().getType();
if (!(membersInjectorType instanceof ParameterizedType)) {
throw errors.cannotInjectRawMembersInjector().toException();
}
@SuppressWarnings("unchecked") // safe because T came from Key<MembersInjector
TypeLiteral<T> instanceType = (TypeLiteral) TypeLiteral.get(
((ParameterizedType) membersInjectorType).getActualTypeArguments()[0]);
MembersInjector<T> membersInjector = membersInjectorStore.get(instanceType, errors);
InternalFactory<MembersInjector factory = new ConstantFactory>(
Initializables.of(membersInjector));
return new InstanceBindingImpl<MembersInjector(this, key, SourceProvider.UNKNOWN_SOURCE,
factory, ImmutableSet.<InjectionPoint>of(), membersInjector);
}
/**
* Creates a synthetic binding to {@code Provider<T>}, i.e. a binding to the provider from
* {@code Binding<T>}.
*/
private <T> BindingImpl> createProviderBinding(Key> key, Errors errors)
throws ErrorsException {
Key<T> providedKey = getProvidedKey(key, errors);
BindingImpl<T> delegate = getBindingOrThrow(providedKey, errors, JitLimitation.NO_JIT);
return new ProviderBindingImpl<T>(this, key, delegate);
}
private static class ProviderBindingImpl<T> extends BindingImpl>
implements ProviderBinding<Provider, HasDependencies {
final BindingImpl<T> providedBinding;
ProviderBindingImpl(InjectorImpl injector, Key<Provider key, Binding providedBinding) {
super(injector, key, providedBinding.getSource(), createInternalFactory(providedBinding),
Scoping.UNSCOPED);
this.providedBinding = (BindingImpl<T>) providedBinding;
}
static <T> InternalFactory> createInternalFactory(Binding providedBinding) {
final Provider<T> provider = providedBinding.getProvider();
return new InternalFactory<Provider() {
public Provider<T> get(Errors errors, InternalContext context, Dependency dependency, boolean linked) {
return provider;
}
};
}
public Key<? extends T> getProvidedKey() {
return providedBinding.getKey();
}
public <V> V acceptTargetVisitor(BindingTargetVisitor super Provider, V> visitor) {
return visitor.visit(this);
}
public void applyTo(Binder binder) {
throw new UnsupportedOperationException("This element represents a synthetic binding.");
}
@Override public String toString() {
return MoreObjects.toStringHelper(ProviderBinding.class)
.add("key", getKey())
.add("providedKey", getProvidedKey())
.toString();
}
public Set<Dependency>> getDependencies() {
return ImmutableSet.<Dependency>>of(Dependency.get(getProvidedKey()));
}
@Override
public boolean equals(Object obj) {
if(obj instanceof ProviderBindingImpl) {
ProviderBindingImpl<?> o = (ProviderBindingImpl>)obj;
return getKey().equals(o.getKey())
&& getScoping().equals(o.getScoping())
&& Objects.equal(providedBinding, o.providedBinding);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hashCode(getKey(), getScoping(), providedBinding);
}
}
/**
* Converts a constant string binding to the required type.
*
* @return the binding if it could be resolved, or null if the binding doesn't exist
* @throws com.google.inject.internal.ErrorsException if there was an error resolving the binding
*/
private <T> BindingImpl convertConstantStringBinding(Key key, Errors errors)
throws ErrorsException {
// Find a constant string binding.
Key<String> stringKey = key.ofType(STRING_TYPE);
BindingImpl<String> stringBinding = state.getExplicitBinding(stringKey);
if (stringBinding == null || !stringBinding.isConstant()) {
return null;
}
String stringValue = stringBinding.getProvider().get();
Object source = stringBinding.getSource();
// Find a matching type converter.
TypeLiteral<T> type = key.getTypeLiteral();
TypeConverterBinding typeConverterBinding = state.getConverter(stringValue, type, errors, source);
if (typeConverterBinding == null) {
// No converter can handle the given type.
return null;
}
// Try to convert the string. A failed conversion results in an error.
try {
@SuppressWarnings("unchecked") // This cast is safe because we double check below.
T converted = (T) typeConverterBinding.getTypeConverter().convert(stringValue, type);
if (converted == null) {
throw errors.converterReturnedNull(stringValue, source, type, typeConverterBinding)
.toException();
}
if (!type.getRawType().isInstance(converted)) {
throw errors.conversionTypeError(stringValue, source, type, typeConverterBinding, converted)
.toException();
}
return new ConvertedConstantBindingImpl<T>(this, key, converted, stringBinding,
typeConverterBinding);
} catch (ErrorsException e) {
throw e;
} catch (RuntimeException e) {
throw errors.conversionError(stringValue, source, type, typeConverterBinding, e)
.toException();
}
}
private static class ConvertedConstantBindingImpl<T>
extends BindingImpl<T> implements ConvertedConstantBinding {
final T value;
final Provider<T> provider;
final Binding<String> originalBinding;
final TypeConverterBinding typeConverterBinding;
ConvertedConstantBindingImpl(
InjectorImpl injector, Key<T> key, T value, Binding originalBinding,
TypeConverterBinding typeConverterBinding) {
super(injector, key, originalBinding.getSource(),
new ConstantFactory<T>(Initializables.of(value)), Scoping.UNSCOPED);
this.value = value;
provider = Providers.of(value);
this.originalBinding = originalBinding;
this.typeConverterBinding = typeConverterBinding;
}
@Override public Provider<T> getProvider() {
return provider;
}
public <V> V acceptTargetVisitor(BindingTargetVisitor super T, V> visitor) {
return visitor.visit(this);
}
public T getValue() {
return value;
}
public TypeConverterBinding getTypeConverterBinding() {
return typeConverterBinding;
}
public Key<String> getSourceKey() {
return originalBinding.getKey();
}
public Set<Dependency>> getDependencies() {
return ImmutableSet.<Dependency>>of(Dependency.get(getSourceKey()));
}
public void applyTo(Binder binder) {
throw new UnsupportedOperationException("This element represents a synthetic binding.");
}
@Override public String toString() {
return MoreObjects.toStringHelper(ConvertedConstantBinding.class)
.add("key", getKey())
.add("sourceKey", getSourceKey())
.add("value", value)
.toString();
}
@Override
public boolean equals(Object obj) {
if(obj instanceof ConvertedConstantBindingImpl) {
ConvertedConstantBindingImpl<?> o = (ConvertedConstantBindingImpl>)obj;
return getKey().equals(o.getKey())
&& getScoping().equals(o.getScoping())
&& Objects.equal(value, o.value);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hashCode(getKey(), getScoping(), value);
}
}
<T> void initializeBinding(BindingImpl binding, Errors errors) throws ErrorsException {
if (binding instanceof DelayedInitialize) {
((DelayedInitialize) binding).initialize(this, errors);
}
}
<T> void initializeJitBinding(BindingImpl binding, Errors errors) throws ErrorsException {
// Put the partially constructed binding in the map a little early. This enables us to handle
// circular dependencies. Example: FooImpl -> BarImpl -> FooImpl.
// Note: We don't need to synchronize on state.lock() during injector creation.
if (binding instanceof DelayedInitialize) {
Key<T> key = binding.getKey();
jitBindings.put(key, binding);
boolean successful = false;
DelayedInitialize delayed = (DelayedInitialize)binding;
try {
delayed.initialize(this, errors);
successful = true;
} finally {
if (!successful) {
// We do not pass cb.getInternalConstructor as the second parameter
// so that cached exceptions while constructing it get stored.
// See TypeListenerTest#testTypeListenerThrows
removeFailedJitBinding(binding, null);
cleanup(binding, new HashSet<Key>());
}
}
}
}
/**
* Iterates through the binding's dependencies to clean up any stray bindings that were leftover
* from a failed JIT binding. This is required because the bindings are eagerly &
* optimistically added to allow circular dependency support, so dependencies may pass where they
* should have failed.
*/
private boolean cleanup(BindingImpl<?> binding, Set encountered) {
boolean bindingFailed = false;
Set<Dependency>> deps = getInternalDependencies(binding);
for(Dependency dep : deps) {
Key<?> depKey = dep.getKey();
InjectionPoint ip = dep.getInjectionPoint();
if(encountered.add(depKey)) { // only check if we haven't looked at this key yet
BindingImpl depBinding = jitBindings.get(depKey);
if(depBinding != null) { // if the binding still exists, validate
boolean failed = cleanup(depBinding, encountered); // if children fail, we fail
if(depBinding instanceof ConstructorBindingImpl) {
ConstructorBindingImpl ctorBinding = (ConstructorBindingImpl)depBinding;
ip = ctorBinding.getInternalConstructor();
if(!ctorBinding.isInitialized()) {
failed = true;
}
}
if(failed) {
removeFailedJitBinding(depBinding, ip);
bindingFailed = true;
}
} else if(state.getExplicitBinding(depKey) == null) {
// ignore keys if they were explicitly bound, but if neither JIT
// nor explicit, it's also invalid & should let parent know.
bindingFailed = true;
}
}
}
return bindingFailed;
}
/** Cleans up any state that may have been cached when constructing the JIT binding. */
private void removeFailedJitBinding(Binding<?> binding, InjectionPoint ip) {
failedJitBindings.add(binding.getKey());
jitBindings.remove(binding.getKey());
membersInjectorStore.remove(binding.getKey().getTypeLiteral());
provisionListenerStore.remove(binding);
if(ip != null) {
constructors.remove(ip);
}
}
/** Safely gets the dependencies of possibly not initialized bindings. */
@SuppressWarnings("unchecked")
private Set<Dependency>> getInternalDependencies(BindingImpl> binding) {
if(binding instanceof ConstructorBindingImpl) {
return ((ConstructorBindingImpl)binding).getInternalDependencies();
} else if(binding instanceof HasDependencies) {
return ((HasDependencies)binding).getDependencies();
} else {
return ImmutableSet.of();
}
}
/**
* Creates a binding for an injectable type with the given scope. Looks for a scope on the type if
* none is specified.
*/
<T> BindingImpl createUninitializedBinding(Key key, Scoping scoping, Object source,
Errors errors, boolean jitBinding) throws ErrorsException {
Class<?> rawType = key.getTypeLiteral().getRawType();
ImplementedBy implementedBy = rawType.getAnnotation(ImplementedBy.class);
// Don't try to inject arrays or enums annotated with @ImplementedBy.
if (rawType.isArray() || (rawType.isEnum() && implementedBy != null)) {
throw errors.missingImplementation(key).toException();
}
// Handle TypeLiteral<T> by binding the inner type
if (rawType == TypeLiteral.class) {
@SuppressWarnings("unchecked") // we have to fudge the inner type as Object
BindingImpl<T> binding = (BindingImpl) createTypeLiteralBinding(
(Key<TypeLiteral
Other Java examples (source code examples)
Here is a short list of links related to this Java InjectorImpl.java source code file: