com.google.inject.InjectorImpl Maven / Gradle / Ivy
Go to download
Guice (pronounced 'juice') is a lightweight dependency injection framework for Java
5, brought to you by Google.
The newest version!
/**
* 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;
import com.google.inject.spi.SourceProviders;
import com.google.inject.util.GuiceFastClass;
import com.google.inject.util.Objects;
import com.google.inject.util.ReferenceCache;
import com.google.inject.util.StackTraceElements;
import com.google.inject.util.Strings;
import com.google.inject.util.ToStringBuilder;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
/**
* Default {@link Injector} implementation.
*
* @author [email protected] (Bob Lee)
* @see BinderImpl
*/
class InjectorImpl implements Injector {
/**
* Maps between primitive types and their wrappers and vice versa.
*/
private static final Map, Class>> PRIMITIVE_COUNTERPARTS;
static {
Map, Class>> primitiveToWrapper =
new HashMap, Class>>() {{
put(int.class, Integer.class);
put(long.class, Long.class);
put(boolean.class, Boolean.class);
put(byte.class, Byte.class);
put(short.class, Short.class);
put(float.class, Float.class);
put(double.class, Double.class);
put(char.class, Character.class);
}};
Map, Class>> counterparts = new HashMap, Class>>();
for (Map.Entry, Class>> entry : primitiveToWrapper.entrySet()) {
Class> key = entry.getKey();
Class> value = entry.getValue();
counterparts.put(key, value);
counterparts.put(value, key);
}
PRIMITIVE_COUNTERPARTS = Collections.unmodifiableMap(counterparts);
}
private static final Map, Converter>> PRIMITIVE_CONVERTERS
= new PrimitiveConverters();
final ConstructionProxyFactory constructionProxyFactory;
final Map, BindingImpl>> bindings;
final BindingsMultimap bindingsMultimap = new BindingsMultimap();
final Map, Scope> scopes;
ErrorHandler errorHandler = new InvalidErrorHandler();
Object defaultSource = SourceProviders.UNKNOWN_SOURCE;
InjectorImpl(ConstructionProxyFactory constructionProxyFactory,
Map, BindingImpl>> bindings,
Map, Scope> scopes) {
this.constructionProxyFactory = constructionProxyFactory;
this.bindings = bindings;
this.scopes = scopes;
}
/**
* Indexes bindings by type.
*/
void index() {
for (BindingImpl> binding : bindings.values()) {
index(binding);
}
}
void index(BindingImpl binding) {
bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
}
// not test-covered
public List> findBindingsByType(TypeLiteral type) {
return Collections.>unmodifiableList(
bindingsMultimap.getAll(type));
}
// not test-covered
List getNamesOfBindingAnnotations(TypeLiteral type) {
List names = new ArrayList();
for (Binding binding : findBindingsByType(type)) {
Key key = binding.getKey();
if (!key.hasAnnotationType()) {
names.add("[no annotation]");
} else {
names.add(key.getAnnotationName());
}
}
return names;
}
/**
* This is only used during Injector building.
*/
void withDefaultSource(Object defaultSource, Runnable runnable) {
Object previous = this.defaultSource;
this.defaultSource = defaultSource;
try {
runnable.run();
}
finally {
this.defaultSource = previous;
}
}
void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
InternalFactory extends T> getInternalFactory(
final Member member, Key key) {
// TODO: Clean up unchecked type warnings.
// Do we have a factory for the specified type and name?
BindingImpl binding = getBinding(key);
if (binding != null) {
return binding.getInternalFactory();
}
Class super T> rawType = key.getTypeLiteral().getRawType();
// Handle cases where T is a Provider>.
if (rawType.equals(Provider.class)) {
Type providerType = key.getTypeLiteral().getType();
if (!(providerType instanceof ParameterizedType)) {
// Raw Provider.
return null;
}
Type entryType
= ((ParameterizedType) providerType).getActualTypeArguments()[0];
try {
final Provider> provider = getProvider(key.ofType(entryType));
return new InternalFactory() {
@SuppressWarnings("unchecked")
public T get(InternalContext context) {
return (T) provider;
}
};
}
catch (ConfigurationException e) {
// Look for a factory bound to a key without annotation attributes if
// necessary.
if (key.hasAttributes()) {
return getInternalFactory(member, key.withoutAttributes());
}
// End of the road.
ErrorMessages.handleMissingBinding(errorHandler, member, key,
getNamesOfBindingAnnotations(key.getTypeLiteral()));
return invalidFactory();
}
}
// Auto[un]box primitives.
Class> primitiveCounterpart
= PRIMITIVE_COUNTERPARTS.get(rawType);
if (primitiveCounterpart != null) {
BindingImpl> counterpartBinding
= getBinding(key.ofType(primitiveCounterpart));
if (counterpartBinding != null) {
return (InternalFactory extends T>)
counterpartBinding.getInternalFactory();
}
}
// TODO: Should we try to convert from a String first, or should we look
// for a binding to the annotation type sans attributes? Right now, we
// convert from a String.
// Can we convert from a String constant?
Key stringKey = key.ofType(String.class);
BindingImpl stringBinding = getBinding(stringKey);
if (stringBinding != null && stringBinding.isConstant()) {
// We don't need do pass in an InternalContext because we know this is
// a ConstantFactory which will not use it.
String value = stringBinding.getInternalFactory().get(null);
// TODO: Generalize everything below here and enable users to plug in
// their own converters.
// Do we need a primitive?
Converter converter = (Converter) PRIMITIVE_CONVERTERS.get(rawType);
if (converter != null) {
try {
T t = converter.convert(member, key, value);
return new ConstantFactory(t);
}
catch (ConstantConversionException e) {
return handleConstantConversionError(
member, stringBinding, rawType, e);
}
}
// Do we need an enum?
if (Enum.class.isAssignableFrom(rawType)) {
T t;
try {
t = (T) Enum.valueOf((Class) rawType, value);
}
catch (IllegalArgumentException e) {
return handleConstantConversionError(
member, stringBinding, rawType, e);
}
return new ConstantFactory(t);
}
// Do we need a class?
if (rawType == Class.class) {
try {
// TODO: Make sure we use the right classloader.
return new ConstantFactory((T) Class.forName(value));
}
catch (ClassNotFoundException e) {
return handleConstantConversionError(
member, stringBinding, rawType, e);
}
}
}
// Don't try to inject primitives, arrays, or enums.
int modifiers = rawType.getModifiers();
if (rawType.isArray() || rawType.isEnum() || rawType.isPrimitive()) {
// Look for a factory bound to a key without annotation attributes if
// necessary.
if (key.hasAttributes()) {
return getInternalFactory(member, key.withoutAttributes());
}
return null;
}
// We don't want to implicitly inject a member if we have a binding
// annotation.
if (key.hasAnnotationType()) {
// Look for a factory bound to a key without annotation attributes if
// necessary.
if (key.hasAttributes()) {
return getInternalFactory(member, key.withoutAttributes());
}
return null;
}
// Last resort: inject the type itself.
if (member != null) {
// If we're injecting into a member, include it in the error messages.
final ErrorHandler previous = this.errorHandler;
this.errorHandler = new AbstractErrorHandler() {
public void handle(Object source, String message) {
previous.handle(source, "Error while injecting at "
+ StackTraceElements.forMember(member) + ": " + message);
}
};
try {
// note: intelliJ thinks this cast is superfluous, but is it?
return (InternalFactory extends T>) getImplicitBinding(member,
rawType, null);
}
finally {
this.errorHandler = previous;
}
}
// note: intelliJ thinks this cast is superfluous, but is it?
return (InternalFactory extends T>) getImplicitBinding(member, rawType,
null);
}
private InternalFactory handleConstantConversionError(
Member member, Binding stringBinding, Class> rawType,
Exception e) {
errorHandler.handle(
StackTraceElements.forMember(member),
ErrorMessages.CONSTANT_CONVERSION_ERROR,
stringBinding.getSource(),
rawType,
e.getMessage());
return invalidFactory();
}
/**
* Field and method injectors.
*/
final Map, List> injectors
= new ReferenceCache, List>() {
protected List create(Class> key) {
List injectors
= new ArrayList();
addInjectors(key, injectors);
return injectors;
}
};
/**
* Recursively adds injectors for fields and methods from the given class to
* the given list. Injects parent classes before sub classes.
*/
void addInjectors(Class clazz, List injectors) {
if (clazz == Object.class) {
return;
}
// Add injectors for superclass first.
addInjectors(clazz.getSuperclass(), injectors);
// TODO (crazybob): Filter out overridden members.
addSingleInjectorsForFields(clazz.getDeclaredFields(), false, injectors);
addSingleInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors);
}
void addSingleInjectorsForMethods(Method[] methods, boolean statics,
List injectors) {
addInjectorsForMembers(Arrays.asList(methods), statics, injectors,
new SingleInjectorFactory() {
public SingleMemberInjector create(InjectorImpl injector,
Method method) throws MissingDependencyException {
return new SingleMethodInjector(injector, method);
}
});
}
void addSingleInjectorsForFields(Field[] fields, boolean statics,
List injectors) {
addInjectorsForMembers(Arrays.asList(fields), statics, injectors,
new SingleInjectorFactory() {
public SingleMemberInjector create(InjectorImpl injector,
Field field) throws MissingDependencyException {
return new SingleFieldInjector(injector, field);
}
});
}
void addInjectorsForMembers(
List members, boolean statics, List injectors,
SingleInjectorFactory injectorFactory) {
for (M member : members) {
if (isStatic(member) == statics) {
Inject inject = member.getAnnotation(Inject.class);
if (inject != null) {
try {
injectors.add(injectorFactory.create(this, member));
}
catch (MissingDependencyException e) {
if (!inject.optional()) {
// TODO: Report errors for more than one parameter per member.
e.handle(errorHandler);
}
}
}
}
}
}
Map, BindingImpl>> internalBindings() {
return bindings;
}
// not test-covered
public Map, Binding>> getBindings() {
return Collections., Binding>>unmodifiableMap(bindings);
}
@SuppressWarnings("unchecked")
public BindingImpl getBinding(Key key) {
return (BindingImpl) bindings.get(key);
}
interface SingleInjectorFactory {
SingleMemberInjector create(InjectorImpl injector, M member)
throws MissingDependencyException;
}
private boolean isStatic(Member member) {
return Modifier.isStatic(member.getModifiers());
}
private static class BindingsMultimap {
private final Map, List extends BindingImpl>>> map
= new HashMap, List extends BindingImpl>>>();
public void put(TypeLiteral type, BindingImpl binding) {
List> bindingsForThisType = getFromMap(type);
if (bindingsForThisType == null) {
bindingsForThisType = new ArrayList>();
// We only put matching entries into the map
map.put(type, bindingsForThisType);
}
bindingsForThisType.add(binding);
}
public List> getAll(TypeLiteral type) {
List> list = getFromMap(type);
return list == null ? Collections.>emptyList() : list;
}
// safe because we only put matching entries into the map
@SuppressWarnings("unchecked")
private List> getFromMap(TypeLiteral type) {
return (List>) map.get(type);
}
}
class SingleFieldInjector implements SingleMemberInjector {
final Field field;
final InternalFactory> factory;
final ExternalContext> externalContext;
public SingleFieldInjector(InjectorImpl injector, Field field)
throws MissingDependencyException {
this.field = field;
// Ewwwww...
field.setAccessible(true);
Key> key = Key.get(
field.getGenericType(), field, field.getAnnotations(), errorHandler);
factory = injector.getInternalFactory(field, key);
if (factory == null) {
throw new MissingDependencyException(key, field);
}
this.externalContext = ExternalContext.newInstance(field, key, injector);
}
public void inject(InternalContext context, Object o) {
ExternalContext> previous = context.getExternalContext();
context.setExternalContext(externalContext);
try {
Object value = factory.get(context);
if (value == null) {
throw new AssertionError(); // we should have prevented this
}
field.set(o, value);
}
catch (IllegalAccessException e) {
throw new AssertionError(e);
}
catch (ConfigurationException e) {
throw e;
}
catch (Throwable throwable) {
throw new ProvisionException(externalContext, throwable);
}
finally {
context.setExternalContext(previous);
}
}
}
/**
* Gets parameter injectors.
*
* @param member to which the parameters belong
* @param annotations on the parameters
* @param parameterTypes parameter types
* @return injections
*/
SingleParameterInjector>[] getParametersInjectors(M member,
Annotation[][] annotations, Type[] parameterTypes)
throws MissingDependencyException {
SingleParameterInjector>[] parameterInjectors
= new SingleParameterInjector>[parameterTypes.length];
Iterator annotationsIterator
= Arrays.asList(annotations).iterator();
int index = 0;
for (Type parameterType : parameterTypes) {
Annotation[] parameterAnnotations = annotationsIterator.next();
Key> key = Key.get(
parameterType, member, parameterAnnotations, errorHandler);
parameterInjectors[index] = createParameterInjector(key, member, index);
index++;
}
return parameterInjectors;
}
SingleParameterInjector createParameterInjector(
Key key, Member member, int index) throws MissingDependencyException {
InternalFactory extends T> factory = getInternalFactory(member, key);
if (factory == null) {
throw new MissingDependencyException(key, member);
}
ExternalContext externalContext
= ExternalContext.newInstance(member, index, key, this);
return new SingleParameterInjector(externalContext, factory);
}
static class SingleMethodInjector implements SingleMemberInjector {
final MethodInvoker methodInvoker;
final SingleParameterInjector>[] parameterInjectors;
public SingleMethodInjector(InjectorImpl injector, final Method method)
throws MissingDependencyException {
// We can't use FastMethod if the method is private.
if (Modifier.isPrivate(method.getModifiers())
|| Modifier.isProtected(method.getModifiers())) {
method.setAccessible(true);
this.methodInvoker = new MethodInvoker() {
public Object invoke(Object target, Object... parameters) throws
IllegalAccessException, InvocationTargetException {
Objects.assertNoNulls(parameters);
return method.invoke(target, parameters);
}
};
}
else {
FastClass fastClass = GuiceFastClass.create(method.getDeclaringClass());
final FastMethod fastMethod = fastClass.getMethod(method);
this.methodInvoker = new MethodInvoker() {
public Object invoke(Object target, Object... parameters)
throws IllegalAccessException, InvocationTargetException {
Objects.assertNoNulls(parameters);
return fastMethod.invoke(target, parameters);
}
};
}
Type[] parameterTypes = method.getGenericParameterTypes();
parameterInjectors = parameterTypes.length > 0
? injector.getParametersInjectors(
method, method.getParameterAnnotations(), parameterTypes)
: null;
}
public void inject(InternalContext context, Object o) {
try {
methodInvoker.invoke(o, getParameters(context, parameterInjectors));
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* Invokes a method.
*/
interface MethodInvoker {
Object invoke(Object target, Object... parameters) throws
IllegalAccessException, InvocationTargetException;
}
final Map, ConstructorInjector> constructors
= new ReferenceCache, ConstructorInjector>() {
@SuppressWarnings("unchecked")
protected ConstructorInjector> create(Class> implementation) {
if (implementation.isInterface()) {
errorHandler.handle(defaultSource,
ErrorMessages.CANNOT_INJECT_ABSTRACT_TYPE, implementation);
return ConstructorInjector.invalidConstructor();
}
return new ConstructorInjector(InjectorImpl.this, implementation);
}
};
/**
* A placeholder. This enables us to continue processing and gather more
* errors but blows up if you actually try to use it.
*/
static class InvalidConstructor {
InvalidConstructor() {
throw new AssertionError();
}
}
@SuppressWarnings("unchecked")
static Constructor invalidConstructor() {
try {
return (Constructor) InvalidConstructor.class.getDeclaredConstructor();
}
catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
static class SingleParameterInjector {
final ExternalContext externalContext;
final InternalFactory extends T> factory;
public SingleParameterInjector(ExternalContext externalContext,
InternalFactory extends T> factory) {
this.externalContext = externalContext;
this.factory = factory;
}
T inject(InternalContext context) {
ExternalContext> previous = context.getExternalContext();
context.setExternalContext(externalContext);
try {
return factory.get(context);
}
catch (ConfigurationException e) {
throw e;
}
catch (Throwable throwable) {
throw new ProvisionException(externalContext, throwable);
}
finally {
context.setExternalContext(previous);
}
}
}
/**
* Iterates over parameter injectors and creates an array of parameter
* values.
*/
static Object[] getParameters(InternalContext context,
SingleParameterInjector[] parameterInjectors) {
if (parameterInjectors == null) {
return null;
}
Object[] parameters = new Object[parameterInjectors.length];
for (int i = 0; i < parameters.length; i++) {
parameters[i] = parameterInjectors[i].inject(context);
}
return parameters;
}
void injectMembers(Object o, InternalContext context) {
List injectorsForClass = injectors.get(o.getClass());
for (SingleMemberInjector injector : injectorsForClass) {
injector.inject(context, o);
}
}
// Not test-covered
public void injectMembers(final Object o) {
callInContext(new ContextualCallable() {
public Void call(InternalContext context) {
injectMembers(o, context);
return null;
}
});
}
public Provider getProvider(Class type) {
return getProvider(Key.get(type));
}
public Provider getProvider(final Key key) {
final InternalFactory extends T> factory = getInternalFactory(null, key);
if (factory == null) {
throw new ConfigurationException(
"Missing binding to " + ErrorMessages.convert(key) + ".");
}
return new Provider() {
public T get() {
return callInContext(new ContextualCallable() {
public T call(InternalContext context) {
ExternalContext> previous = context.getExternalContext();
context.setExternalContext(
ExternalContext.newInstance(null, key, InjectorImpl.this));
try {
return factory.get(context);
}
finally {
context.setExternalContext(previous);
}
}
});
}
public String toString() {
return factory.toString();
}
};
}
public T getInstance(Key key) {
return getProvider(key).get();
}
public T getInstance(Class type) {
return getProvider(type).get();
}
final ThreadLocal localContext
= new ThreadLocal() {
protected InternalContext[] initialValue() {
return new InternalContext[1];
}
};
/**
* Looks up thread local context. Creates (and removes) a new context if
* necessary.
*/
T callInContext(ContextualCallable callable) {
InternalContext[] reference = localContext.get();
if (reference[0] == null) {
reference[0] = new InternalContext(this);
try {
return callable.call(reference[0]);
}
finally {
// Only remove the context if this call created it.
reference[0] = null;
}
}
else {
// Someone else will clean up this context.
return callable.call(reference[0]);
}
}
/**
* Gets a constructor function for a given implementation class.
*/
@SuppressWarnings("unchecked")
ConstructorInjector getConstructor(Class implementation) {
return constructors.get(implementation);
}
@SuppressWarnings("unchecked")
ConstructorInjector getConstructor(TypeLiteral implementation) {
return constructors.get(implementation.getRawType());
}
/**
* Injects a field or method in a given object.
*/
interface SingleMemberInjector {
void inject(InternalContext context, Object o);
}
class MissingDependencyException extends Exception {
final Key> key;
final Member member;
MissingDependencyException(Key> key, Member member) {
this.key = key;
this.member = member;
}
void handle(ErrorHandler errorHandler) {
ErrorMessages.handleMissingBinding(errorHandler, member, key,
getNamesOfBindingAnnotations(key.getTypeLiteral()));
}
}
/**
* Map of primitive type converters.
*/
static class PrimitiveConverters extends HashMap, Converter>> {
PrimitiveConverters() {
putParser(int.class);
putParser(long.class);
putParser(boolean.class);
putParser(byte.class);
putParser(short.class);
putParser(float.class);
putParser(double.class);
// Character doesn't follow the same pattern.
Converter characterConverter = new Converter() {
public Character convert(Member member, Key key,
String value) throws ConstantConversionException {
value = value.trim();
if (value.length() != 1) {
throw new ConstantConversionException(member, key, value,
"Length != 1.");
}
return value.charAt(0);
}
};
put(char.class, characterConverter);
put(Character.class, characterConverter);
}
void putParser(final Class primitive) {
try {
Class> wrapper = PRIMITIVE_COUNTERPARTS.get(primitive);
final Method parser = wrapper.getMethod(
"parse" + Strings.capitalize(primitive.getName()), String.class);
Converter converter = new Converter() {
@SuppressWarnings("unchecked")
public T convert(Member member, Key key, String value)
throws ConstantConversionException {
try {
return (T) parser.invoke(null, value);
}
catch (IllegalAccessException e) {
throw new AssertionError(e);
}
catch (InvocationTargetException e) {
throw new ConstantConversionException(member, key, value,
e.getTargetException());
}
}
};
put(wrapper, converter);
put(primitive, converter);
}
catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
}
/**
* Converts a {@code String} to another type.
*/
interface Converter {
/**
* Converts {@code String} value.
*/
T convert(Member member, Key key, String value)
throws ConstantConversionException;
}
Map, InternalFactory>> implicitBindings =
new HashMap, InternalFactory>>();
/**
* Gets a factory for the specified type. Used when an explicit binding
* was not made. Uses synchronization here so it's not necessary in the
* factory itself. Returns {@code null} if the type isn't injectable.
*/
InternalFactory extends T> getImplicitBinding(Member member,
final Class type, Scope scope) {
// Look for @DefaultImplementation.
ImplementedBy implementedBy =
type.getAnnotation(ImplementedBy.class);
if (implementedBy != null) {
Class> implementationType = implementedBy.value();
// Make sure it's not the same type. TODO: Can we check for deeper loops?
if (implementationType == type) {
errorHandler.handle(StackTraceElements.forType(type),
ErrorMessages.RECURSIVE_IMPLEMENTATION_TYPE, type);
return invalidFactory();
}
// Make sure implementationType extends type.
if (!type.isAssignableFrom(implementationType)) {
errorHandler.handle(StackTraceElements.forType(type),
ErrorMessages.NOT_A_SUBTYPE, implementationType, type);
return invalidFactory();
}
return (InternalFactory) getInternalFactory(
member, Key.get(implementationType));
}
// Look for @DefaultProvider.
ProvidedBy providedBy = type.getAnnotation(ProvidedBy.class);
if (providedBy != null) {
final Class extends Provider>> providerType = providedBy.value();
// Make sure it's not the same type. TODO: Can we check for deeper loops?
if (providerType == type) {
errorHandler.handle(StackTraceElements.forType(type),
ErrorMessages.RECURSIVE_PROVIDER_TYPE, type);
return invalidFactory();
}
// TODO: Make sure the provided type extends type. We at least check
// the type at runtime below.
InternalFactory extends Provider>> providerFactory
= getInternalFactory(member, Key.get(providerType));
Key extends Provider>> providerKey = Key.get(providerType);
return (InternalFactory) new BoundProviderFactory(
providerKey, providerFactory, StackTraceElements.forType(type)) {
public Object get(InternalContext context) {
Object o = super.get(context);
try {
return type.cast(o);
} catch (ClassCastException e) {
errorHandler.handle(StackTraceElements.forType(type),
ErrorMessages.SUBTYPE_NOT_PROVIDED, providerType, type);
throw new AssertionError();
}
}
};
}
// TODO: Method interceptors could actually enable us to implement
// abstract types. Should we remove this restriction?
if (Modifier.isAbstract(type.getModifiers())) {
return null;
}
// Inject the class itself.
synchronized (implicitBindings) {
@SuppressWarnings("unchecked")
InternalFactory factory =
(InternalFactory) implicitBindings.get(type);
if (factory != null) {
return factory;
}
// Create the factory.
ImplicitBinding implicitBinding = new ImplicitBinding(type);
// Scope the factory if necessary.
// If we don't have a scope from the configuration, look for one on
// the type.
if (scope == null) {
scope = Scopes.getScopeForType(type, scopes, errorHandler);
}
InternalFactory extends T> scoped;
if (scope != null) {
scoped = Scopes.scope(Key.get(type), this, implicitBinding, scope);
} else {
scoped = implicitBinding;
}
implicitBindings.put(type, scoped);
try {
// Look up the constructor. We do this separately from constructions to
// support circular dependencies.
ConstructorInjector constructor = getConstructor(type);
implicitBinding.setConstructorInjector(constructor);
}
catch (RuntimeException e) {
// Clean up state.
implicitBindings.remove(type);
throw e;
}
catch (Throwable t) {
// Clean up state.
implicitBindings.remove(type);
throw new AssertionError(t);
}
return scoped;
}
}
static class ImplicitBinding implements InternalFactory {
final Class implementation;
ConstructorInjector constructorInjector;
ImplicitBinding(Class implementation) {
this.implementation = implementation;
}
void setConstructorInjector(
ConstructorInjector constructorInjector) {
this.constructorInjector = constructorInjector;
}
public T get(InternalContext context) {
return (T) constructorInjector.construct(context,
context.getExpectedType());
}
}
private static final InternalFactory> INVALID_FACTORY
= new InternalFactory
© 2015 - 2025 Weber Informatics LLC | Privacy Policy