package com.google.inject.internal;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ListMultimap;
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.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.InstanceBinding;
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;
final class InjectorImpl implements Injector, Lookups {
public static final TypeLiteral<String> STRING_TYPE = TypeLiteral.get(String.class);
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();
}
}
enum JitLimitation {
NO_JIT,
EXISTING_JIT,
NEW_OR_EXISTING_JIT,
}
final State state;
final InjectorImpl parent;
final ListMultimap<TypeLiteral<?>, Binding<?>> bindingsMultimap = ArrayListMultimap.create();
final InjectorOptions options;
final Map<Key<?>, BindingImpl<?>> jitBindings = Maps.newHashMap();
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 {
localContext = new ThreadLocal<>();
}
}
void index() {
for (Binding<?> binding : state.getExplicitBindingsThisLevel().values()) {
bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
}
}
@Override
public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
@SuppressWarnings("unchecked")
List<Binding<T>> list = (List<Binding<T>>) (List) bindingsMultimap.get(type);
return Collections.unmodifiableList(list);
}
@Override
public <T> BindingImpl<T> getBinding(Key<T> 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());
}
}
@Override
public <T> BindingImpl<T> getExistingBinding(Key<T> key) {
BindingImpl<T> explicitBinding = state.getExplicitBinding(key);
if (explicitBinding != null) {
return explicitBinding;
}
synchronized (state.lock()) {
for (InjectorImpl injector = this; injector != null; injector = injector.parent) {
@SuppressWarnings("unchecked")
BindingImpl<T> jitBinding = (BindingImpl<T>) injector.jitBindings.get(key);
if (jitBinding != null) {
return jitBinding;
}
}
}
if (isProvider(key)) {
try {
@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());
}
}
return null;
}
<T> BindingImpl<T> getBindingOrThrow(Key<T> key, Errors errors, JitLimitation jitType)
throws ErrorsException {
BindingImpl<T> binding = state.getExplicitBinding(key);
if (binding != null) {
return binding;
}
return getJustInTimeBinding(key, errors, jitType);
}
@Override
public <T> Binding<T> getBinding(Class<T> type) {
return getBinding(Key.get(type));
}
@Override
public Injector getParent() {
return parent;
}
@Override
public Injector createChildInjector(Iterable<? extends Module> modules) {
return new InternalInjectorCreator().parentInjector(this).addModules(modules).build();
}
@Override
public Injector createChildInjector(Module... modules) {
return createChildInjector(ImmutableList.copyOf(modules));
}
private <T> BindingImpl<T> getJustInTimeBinding(Key<T> key, Errors errors, JitLimitation jitType)
throws ErrorsException {
boolean jitOverride = isProvider(key) || isTypeLiteral(key) || isMembersInjector(key);
synchronized (state.lock()) {
for (InjectorImpl injector = this; injector != null; injector = injector.parent) {
@SuppressWarnings("unchecked")
BindingImpl<T> binding = (BindingImpl<T>) injector.jitBindings.get(key);
if (binding != null) {
if (options.jitDisabled
&& jitType == JitLimitation.NO_JIT
&& !jitOverride
&& !(binding instanceof ConvertedConstantBindingImpl)) {
throw errors.jitDisabled(key).toException();
} else {
return binding;
}
}
}
if (failedJitBindings.contains(key) && errors.hasErrors()) {
throw errors.toException();
}
return createJustInTimeBindingRecursive(key, errors, options.jitDisabled, jitType);
}
}
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<T> getProvidedKey(Key<Provider<T>> key, Errors errors)
throws ErrorsException {
Type providerType = key.getTypeLiteral().getType();
if (!(providerType instanceof ParameterizedType)) {
throw errors.cannotInjectRawProvider().toException();
}
Type entryType = ((ParameterizedType) providerType).getActualTypeArguments()[0];
@SuppressWarnings("unchecked")
Key<T> providedKey = (Key<T>) key.ofType(entryType);
return providedKey;
}
private static boolean isMembersInjector(Key<?> key) {
return key.getTypeLiteral().getRawType().equals(MembersInjector.class)
&& key.getAnnotationType() == null;
}
private <T> BindingImpl<MembersInjector<T>> createMembersInjectorBinding(
Key<MembersInjector<T>> key, Errors errors) throws ErrorsException {
Type membersInjectorType = key.getTypeLiteral().getType();
if (!(membersInjectorType instanceof ParameterizedType)) {
throw errors.cannotInjectRawMembersInjector().toException();
}
@SuppressWarnings("unchecked")
TypeLiteral<T> instanceType =
(TypeLiteral<T>)
TypeLiteral.get(((ParameterizedType) membersInjectorType).getActualTypeArguments()[0]);
MembersInjector<T> membersInjector = membersInjectorStore.get(instanceType, errors);
InternalFactory<MembersInjector<T>> factory =
new ConstantFactory<MembersInjector<T>>(Initializables.of(membersInjector));
return new InstanceBindingImpl<MembersInjector<T>>(
this,
key,
SourceProvider.UNKNOWN_SOURCE,
factory,
ImmutableSet.<InjectionPoint>of(),
membersInjector);
}
private <T> BindingImpl<Provider<T>> createProviderBinding(Key<Provider<T>> 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<Provider<T>>
implements ProviderBinding<Provider<T>>, HasDependencies {
final BindingImpl<T> providedBinding;
ProviderBindingImpl(InjectorImpl injector, Key<Provider<T>> key, Binding<T> providedBinding) {
super(
injector,
key,
providedBinding.getSource(),
createInternalFactory(providedBinding),
Scoping.UNSCOPED);
this.providedBinding = (BindingImpl<T>) providedBinding;
}
static <T> InternalFactory<Provider<T>> createInternalFactory(Binding<T> providedBinding) {
final Provider<T> provider = providedBinding.getProvider();
return new InternalFactory<Provider<T>>() {
@Override
public Provider<T> get(InternalContext context, Dependency<?> dependency, boolean linked) {
return provider;
}
};
}
@Override
public Key<? extends T> getProvidedKey() {
return providedBinding.getKey();
}
@Override
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super Provider<T>, V> visitor) {
return visitor.visit(this);
}
@Override
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();
}
@Override
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);
}
}
private <T> BindingImpl<T> convertConstantStringBinding(Key<T> key, Errors errors)
throws ErrorsException {
Key<String> stringKey = key.ofType(STRING_TYPE);
BindingImpl<String> stringBinding = state.getExplicitBinding(stringKey);
if (stringBinding == null || !stringBinding.isConstant()) {
return null;
}
@SuppressWarnings("unchecked")
String stringValue = ((InstanceBinding<String>) stringBinding).getInstance();
Object source = stringBinding.getSource();
TypeLiteral<T> type = key.getTypeLiteral();
TypeConverterBinding typeConverterBinding =
state.getConverter(stringValue, type, errors, source);
if (typeConverterBinding == null) {
return null;
}
try {
@SuppressWarnings("unchecked")
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<T> {
final T value;
final Provider<T> provider;
final Binding<String> originalBinding;
final TypeConverterBinding typeConverterBinding;
ConvertedConstantBindingImpl(
InjectorImpl injector,
Key<T> key,
T value,
Binding<String> 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;
}
@Override
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
@Override
public T getValue() {
return value;
}
@Override
public TypeConverterBinding getTypeConverterBinding() {
return typeConverterBinding;
}
@Override
public Key<String> getSourceKey() {
return originalBinding.getKey();
}
@Override
public Set<Dependency<?>> getDependencies() {
return ImmutableSet.<Dependency<?>>of(Dependency.get(getSourceKey()));
}
@Override
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<T> binding, Errors errors) throws ErrorsException {
if (binding instanceof DelayedInitialize) {
((DelayedInitialize) binding).initialize(this, errors);
}
}
<T> void initializeJitBinding(BindingImpl<T> binding, Errors errors) throws ErrorsException {
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) {
removeFailedJitBinding(binding, null);
cleanup(binding, new HashSet<Key>());
}
}
}
}
private boolean cleanup(BindingImpl<?> binding, Set<Key> 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)) {
BindingImpl depBinding = jitBindings.get(depKey);
if (depBinding != null) {
boolean failed = cleanup(depBinding, encountered);
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) {
bindingFailed = true;
}
}
}
return bindingFailed;
}
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);
}
}
@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();
}
}
<T> BindingImpl<T> createUninitializedBinding(
Key<T> key, Scoping scoping, Object source, Errors errors, boolean jitBinding)
throws ErrorsException {
Class<?> rawType = key.getTypeLiteral().getRawType();
ImplementedBy implementedBy = rawType.getAnnotation(ImplementedBy.class);
if (rawType.isArray() || (rawType.isEnum() && implementedBy != null)) {
throw errors.missingImplementationWithHint(key, this).toException();
}
if (rawType == TypeLiteral.class) {
@SuppressWarnings("unchecked")
BindingImpl<T> binding =
(BindingImpl<T>) createTypeLiteralBinding((Key<TypeLiteral<Object>>) key, errors);
return binding;
}
if (implementedBy != null) {
Annotations.checkForMisplacedScopeAnnotations(rawType, source, errors);
return createImplementedByBinding(key, scoping, implementedBy, errors);
}
ProvidedBy providedBy = rawType.getAnnotation(ProvidedBy.class);
if (providedBy != null) {
Annotations.checkForMisplacedScopeAnnotations(rawType, source, errors);
return createProvidedByBinding(key, scoping, providedBy, errors);
}
return ConstructorBindingImpl.create(
this,
key,
null,
source,
scoping,
errors,
jitBinding && options.jitDisabled,
options.atInjectRequired);
}
private <T> BindingImpl<TypeLiteral<T>> createTypeLiteralBinding(
Key<TypeLiteral<T>> key, Errors errors) throws ErrorsException {
Type typeLiteralType = key.getTypeLiteral().getType();
if (!(typeLiteralType instanceof ParameterizedType)) {
throw errors.cannotInjectRawTypeLiteral().toException();
}
ParameterizedType parameterizedType = (ParameterizedType) typeLiteralType;
Type innerType = parameterizedType.getActualTypeArguments()[0];
if (!(innerType instanceof Class)
&& !(innerType instanceof GenericArrayType)
&& !(innerType instanceof ParameterizedType)) {
throw errors.cannotInjectTypeLiteralOf(innerType).toException();
}
@SuppressWarnings("unchecked")
TypeLiteral<T> value = (TypeLiteral<T>) TypeLiteral.get(innerType);
InternalFactory<TypeLiteral<T>> factory =
new ConstantFactory<TypeLiteral<T>>(Initializables.of(value));
return new InstanceBindingImpl<TypeLiteral<T>>(
this,
key,
SourceProvider.UNKNOWN_SOURCE,
factory,
ImmutableSet.<InjectionPoint>of(),
value);
}
<T> BindingImpl<T> createProvidedByBinding(
Key<T> key, Scoping scoping, ProvidedBy providedBy, Errors errors) throws ErrorsException {
Class<?> rawType = key.getTypeLiteral().getRawType();
Class<? extends javax.inject.Provider<?>> providerType = providedBy.value();
if (providerType == rawType) {
throw errors.recursiveProviderType().toException();
}
@SuppressWarnings("unchecked")
Key<? extends Provider<T>> providerKey = (Key<? extends Provider<T>>) Key.get(providerType);
ProvidedByInternalFactory<T> internalFactory =
new ProvidedByInternalFactory<T>(rawType, providerType, providerKey);
Object source = rawType;
BindingImpl<T> binding =
LinkedProviderBindingImpl.createWithInitializer(
this,
key,
source,
Scoping.<T>scope(key, this, internalFactory, source, scoping),
scoping,
providerKey,
internalFactory);
internalFactory.setProvisionListenerCallback(provisionListenerStore.get(binding));
return binding;
}
private <T> BindingImpl<T> createImplementedByBinding(
Key<T> key, Scoping scoping, ImplementedBy implementedBy, Errors errors)
throws ErrorsException {
Class<?> rawType = key.getTypeLiteral().getRawType();
Class<?> implementationType = implementedBy.value();
if (implementationType == rawType) {
throw errors.recursiveImplementationType().toException();
}
if (!rawType.isAssignableFrom(implementationType)) {
throw errors.notASubtype(implementationType, rawType).toException();
}
@SuppressWarnings("unchecked")
Class<? extends T> subclass = (Class<? extends T>) implementationType;
final Key<? extends T> targetKey = Key.get(subclass);
Object source = rawType;
FactoryProxy<T> factory = new FactoryProxy<>(this, key, targetKey, source);
factory.notify(errors);
return new LinkedBindingImpl<T>(
this,
key,
source,
Scoping.<T>scope(key, this, factory, source, scoping),
scoping,
targetKey);
}
private <T> BindingImpl<T> createJustInTimeBindingRecursive(
Key<T> key, Errors errors, boolean jitDisabled, JitLimitation jitType)
throws ErrorsException {
if (parent != null) {
if (jitType == JitLimitation.NEW_OR_EXISTING_JIT
&& jitDisabled
&& !parent.options.jitDisabled) {
throw errors.jitDisabledInParent(key).toException();
}
try {
return parent.createJustInTimeBindingRecursive(
key,
new Errors(),
jitDisabled,
parent.options.jitDisabled ? JitLimitation.NO_JIT : jitType);
} catch (ErrorsException ignored) {
}
}
Set<Object> sources = state.getSourcesForBlacklistedKey(key);
if (state.isBlacklisted(key)) {
throw errors.childBindingAlreadySet(key, sources).toException();
}
key = MoreTypes.canonicalizeKey(key);
BindingImpl<T> binding = createJustInTimeBinding(key, errors, jitDisabled, jitType);
state.parent().blacklist(key, state, binding.getSource());
jitBindings.put(key, binding);
return binding;
}
private <T> BindingImpl<T> createJustInTimeBinding(
Key<T> key, Errors errors, boolean jitDisabled, JitLimitation jitType)
throws ErrorsException {
int numErrorsBefore = errors.size();
Set<Object> sources = state.getSourcesForBlacklistedKey(key);
if (state.isBlacklisted(key)) {
throw errors.childBindingAlreadySet(key, sources).toException();
}
if (isProvider(key)) {
@SuppressWarnings({"unchecked", "cast"})
BindingImpl<T> binding = (BindingImpl<T>) createProviderBinding((Key) key, errors);
return binding;
}
if (isMembersInjector(key)) {
@SuppressWarnings({"unchecked", "cast"})
BindingImpl<T> binding = (BindingImpl<T>) createMembersInjectorBinding((Key) key, errors);
return binding;
}
BindingImpl<T> convertedBinding = convertConstantStringBinding(key, errors);
if (convertedBinding != null) {
return convertedBinding;
}
if (!isTypeLiteral(key) && jitDisabled && jitType != JitLimitation.NEW_OR_EXISTING_JIT) {
throw errors.jitDisabled(key).toException();
}
if (key.getAnnotationType() != null) {
if (key.hasAttributes() && !options.exactBindingAnnotationsRequired) {
try {
Errors ignored = new Errors();
return getBindingOrThrow(key.withoutAttributes(), ignored, JitLimitation.NO_JIT);
} catch (ErrorsException ignored) {
}
}
throw errors.missingImplementationWithHint(key, this).toException();
}
Object source = key.getTypeLiteral().getRawType();
BindingImpl<T> binding =
createUninitializedBinding(key, Scoping.UNSCOPED, source, errors, true);
errors.throwIfNewErrors(numErrorsBefore);
initializeJitBinding(binding, errors);
return binding;
}
<T> InternalFactory<? extends T> getInternalFactory(
Key<T> key, Errors errors, JitLimitation jitType) throws ErrorsException {
return getBindingOrThrow(key, errors, jitType).getInternalFactory();
}
@Override
public Map<Key<?>, Binding<?>> getBindings() {
return state.getExplicitBindingsThisLevel();
}
@Override
public Map<Key<?>, Binding<?>> getAllBindings() {
synchronized (state.lock()) {
return new ImmutableMap.Builder<Key<?>, Binding<?>>()
.putAll(state.getExplicitBindingsThisLevel())
.putAll(jitBindings)
.build();
}
}
@Override
public Map<Class<? extends Annotation>, Scope> getScopeBindings() {
return ImmutableMap.copyOf(state.getScopes());
}
@Override
public Set<TypeConverterBinding> getTypeConverterBindings() {
return ImmutableSet.copyOf(state.getConvertersThisLevel());
}
SingleParameterInjector<?>[] getParametersInjectors(List<Dependency<?>> parameters, Errors errors)
throws ErrorsException {
if (parameters.isEmpty()) {
return null;
}
int numErrorsBefore = errors.size();
SingleParameterInjector<?>[] result = new SingleParameterInjector<?>[parameters.size()];
int i = 0;
for (Dependency<?> parameter : parameters) {
try {
result[i++] = createParameterInjector(parameter, errors.withSource(parameter));
} catch (ErrorsException rethrownBelow) {
}
}
errors.throwIfNewErrors(numErrorsBefore);
return result;
}
<T> SingleParameterInjector<T> createParameterInjector(
final Dependency<T> dependency, final Errors errors) throws ErrorsException {
BindingImpl<? extends T> binding =
getBindingOrThrow(dependency.getKey(), errors, JitLimitation.NO_JIT);
return new SingleParameterInjector<T>(dependency, binding);
}
interface MethodInvoker {
Object invoke(Object target, Object... parameters)
throws IllegalAccessException, InvocationTargetException;
}
final ConstructorInjectorStore constructors = new ConstructorInjectorStore(this);
MembersInjectorStore membersInjectorStore;
ProvisionListenerCallbackStore provisionListenerStore;
@Override
@SuppressWarnings("unchecked")
public void injectMembers(Object instance) {
MembersInjector membersInjector = getMembersInjector(instance.getClass());
membersInjector.injectMembers(instance);
}
@Override
public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
Errors errors = new Errors(typeLiteral);
try {
return membersInjectorStore.get(typeLiteral, errors);
} catch (ErrorsException e) {
throw new ConfigurationException(errors.merge(e.getErrors()).getMessages());
}
}
@Override
public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
return getMembersInjector(TypeLiteral.get(type));
}
@Override
public <T> Provider<T> getProvider(Class<T> type) {
return getProvider(Key.get(type));
}
<T> Provider<T> getProviderOrThrow(final Dependency<T> dependency, Errors errors)
throws ErrorsException {
Key<T> key = dependency.getKey();
BindingImpl<? extends T> binding = getBindingOrThrow(key, errors, JitLimitation.NO_JIT);
final InternalFactory<? extends T> internalFactory = binding.getInternalFactory();
final Object source = binding.getSource();
return new Provider<T>() {
@Override
public T get() {
InternalContext currentContext = enterContext();
Dependency previous = currentContext.pushDependency(dependency, source);
try {
T t = internalFactory.get(currentContext, dependency, false);
return t;
} catch (InternalProvisionException e) {
throw e.addSource(dependency).toProvisionException();
} finally {
currentContext.popStateAndSetDependency(previous);
currentContext.close();
}
}
@Override
public String toString() {
return internalFactory.toString();
}
};
}
@Override
public <T> Provider<T> getProvider(final Key<T> key) {
Errors errors = new Errors(key);
try {
Provider<T> result = getProviderOrThrow(Dependency.get(key), errors);
errors.throwIfNewErrors(0);
return result;
} catch (ErrorsException e) {
throw new ConfigurationException(errors.merge(e.getErrors()).getMessages());
}
}
@Override
public <T> T getInstance(Key<T> key) {
return getProvider(key).get();
}
@Override
public <T> T getInstance(Class<T> type) {
return getProvider(type).get();
}
private final ThreadLocal<Object[]> localContext;
InternalContext getLocalContext() {
return (InternalContext) localContext.get()[0];
}
InternalContext enterContext() {
Object[] reference = localContext.get();
if (reference == null) {
reference = new Object[1];
localContext.set(reference);
}
InternalContext ctx = (InternalContext) reference[0];
if (ctx == null) {
reference[0] = ctx = new InternalContext(options, reference);
} else {
ctx.enter();
}
return ctx;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(Injector.class)
.add("bindings", state.getExplicitBindingsThisLevel().values())
.toString();
}
}