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

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 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 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)
            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) getImplicitBinding(member,
            rawType, null);
      }
      finally {
        this.errorHandler = previous;
      }
    }
    // note: intelliJ thinks this cast is superfluous, but is it?
    return (InternalFactory) 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>> map
        = new HashMap, List>>();

    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 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 factory;

    public SingleParameterInjector(ExternalContext externalContext,
        InternalFactory 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 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 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> 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> providerFactory
          = getInternalFactory(member, Key.get(providerType));
      Key> 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 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() {
    public Object get(InternalContext context) {
      throw new AssertionError();
    }
  };

  @SuppressWarnings("unchecked")
  static  InternalFactory invalidFactory() {
    return (InternalFactory) INVALID_FACTORY;
  }

  public String toString() {
    return new ToStringBuilder(Injector.class)
        .add("bindings", bindings)
        .toString();
  }
}