Merge pie-platform-release to aosp-master - DO NOT MERGE

Change-Id: Ib1c12dfcaff433999e9aa6db0dc5f0a48e115ebc
diff --git a/.gitignore b/.gitignore
index a73b2cd..7131b22 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@
 .idea/
 *.iml
 *.ipr
+extensions/**/build/
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index b9b79e0..58a8877 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,14 @@
 language: java
+sudo: false
+
+cache:
+  directories:
+    - $HOME/.m2
 
 jdk:
+  - oraclejdk9
   - oraclejdk8
-  - oraclejdk7
   - openjdk7
-  - openjdk6
 
 env:
   global:
@@ -14,7 +18,7 @@
   matrix:
     - LABEL=ant        CMD="ant dist test.dist" INSTALL="/bin/true"
     - LABEL=ant_no_aop CMD="ant -f build/no_aop/build.xml dist test.dist" INSTALL="ant no_aop"
-    - LABEL=mvn        CMD="mvn -P!standard-with-extra-repos verify --fail-at-end -Dsource.skip=true -Dmaven.javadoc.skip=true" INSTALL="mvn -P!standard-with-extra-repos dependency:go-offline test clean --quiet --fail-never -DskipTests=true"
+    - LABEL=mvn        CMD="mvn -B -P!standard-with-extra-repos verify --fail-at-end -Dsource.skip=true -Dmaven.javadoc.skip=true" INSTALL="mvn -P!standard-with-extra-repos dependency:go-offline test clean --quiet --fail-never -DskipTests=true"
 
 install:
   - ${INSTALL}
@@ -22,11 +26,6 @@
 script:
   - ${CMD}
 
-notifications:
-  email:
-    recipients:
-      - google-guice-dev+ci@googlegroups.com
-
 after_success:
   - util/generate-latest-docs.sh
   - util/compareBuilds.sh
diff --git a/Android.bp b/Android.bp
index 154cee3..3fdc2cb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -104,4 +104,19 @@
     ],
 }
 
+// Variation that doesn't link guava statically
+java_library_static {
+    name: "guice-no-guava",
+    host_supported: true,
+    hostdex: true,
+    sdk_version: "core_current",
+    srcs: [":guice_munged_srcs"],
+    libs: [
+        "guava",
+    ],
+    static_libs: [
+        "jsr330",
+    ],
+}
+
 // TODO: Consider adding tests.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1405580..c104f59 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -54,7 +54,7 @@
   1. Finally, push the commits to your fork and submit a [pull request][].
 
 [forking]: https://help.github.com/articles/fork-a-repo
-[java style guide]: http://google-styleguide.googlecode.com/svn/trunk/javaguide.html
+[java style guide]: https://google.github.io/styleguide/javaguide.html
 [well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
 [pull request]: https://help.github.com/articles/creating-a-pull-request
 
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..010701d
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,18 @@
+name: "guice"
+description: "Guice (pronounced \'juice\') is a lightweight dependency injection framework for Java 6 and above."
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://github.com/google/guice"
+  }
+  url {
+    type: ARCHIVE
+    value: "https://github.com/google/guice/archive/4.2.tar.gz"
+  }
+  version: "4.2"
+  last_upgrade_date {
+    year: 2018
+    month: 8
+    day: 27
+  }
+}
diff --git a/README.md b/README.md
index a86d992..9061809 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,12 @@
 Guice
 ====
 
-**Latest version: [4.0](https://github.com/google/guice/wiki/Guice40)!**
+**Latest release: [4.1](https://github.com/google/guice/wiki/Guice41)**
 
-**Documentation:** [User Guide](https://github.com/google/guice/wiki/Motivation), [4.0 javadocs](http://google.github.io/guice/api-docs/4.0/javadoc/packages.html), [Latest javadocs](http://google.github.io/guice/api-docs/latest/javadoc/index.html) <br/>
+**Documentation:** [User Guide](https://github.com/google/guice/wiki/Motivation), [4.1 javadocs](http://google.github.io/guice/api-docs/4.1/javadoc/index.html), [Latest javadocs](http://google.github.io/guice/api-docs/latest/javadoc/index.html) <br/>
 **Continuous Integration:** [![Build Status](https://api.travis-ci.org/google/guice.png?branch=master)](https://travis-ci.org/google/guice) <br
 />
-**Mailing Lists:** [User Mailing List](http://groups.google.com/group/google-guice), [Developer Mailing List](http://groups.google.com/group/google-guice-dev) <br/>
+**Mailing Lists:** [User Mailing List](http://groups.google.com/group/google-guice) <br/>
 **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0)
 
 Put simply, Guice alleviates the need for factories and the use of new in your Java code. Think of Guice's @Inject as the new new. You will still need to write factories in some cases, but your code will not depend directly on them. Your code will be easier to change, unit test and reuse in other contexts.
diff --git a/README.version b/README.version
deleted file mode 100644
index d3de1cd..0000000
--- a/README.version
+++ /dev/null
@@ -1,4 +0,0 @@
-URL: https://github.com/google/guice
-Version: 4.0 (5a209e98e0dedf3dbb2cc657514e7daf1707296c)
-BugComponent: 99142
-Owners: iam
diff --git a/bom/pom.xml b/bom/pom.xml
index 81d2315..759bfca 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.google.inject</groupId>
     <artifactId>guice-parent</artifactId>
-    <version>4.0</version>
+    <version>4.2.0</version>
   </parent>
 
   <packaging>pom</packaging>
@@ -61,11 +61,6 @@
       </dependency>
       <dependency>
         <groupId>com.google.inject.extensions</groupId>
-        <artifactId>guice-multibindings</artifactId>
-        <version>${project.version}</version>
-      </dependency>
-      <dependency>
-        <groupId>com.google.inject.extensions</groupId>
         <artifactId>guice-persist</artifactId>
         <version>${project.version}</version>
       </dependency>
diff --git a/build.properties b/build.properties
index cca000c..244cb5b 100644
--- a/build.properties
+++ b/build.properties
@@ -7,7 +7,6 @@
 jmx.src.dir=extensions/jmx/src
 jndi.src.dir=extensions/jndi/src
 throwingproviders.src.dir=extensions/throwingproviders/src
-multibindings.src.dir=extensions/multibindings/src
 daggeradapter.src.dir=extensions/dagger-adapter/src
 privatemodules.src.dir=extensions/privatemodules/src
 lifecycle.src.dir=extensions/lifecycle/src
diff --git a/build.xml b/build.xml
index 3d0c772..b524258 100644
--- a/build.xml
+++ b/build.xml
@@ -34,7 +34,6 @@
     <ant antfile="extensions/jmx/build.xml" target="distjars" inheritAll="false"/>
     <ant antfile="extensions/jndi/build.xml" target="distjars" inheritAll="false"/>
     <ant antfile="extensions/throwingproviders/build.xml" target="distjars" inheritAll="false"/>
-    <ant antfile="extensions/multibindings/build.xml" target="distjars" inheritAll="false"/>
     <ant antfile="extensions/dagger-adapter/build.xml" target="distjars" inheritAll="false"/>
     <ant antfile="extensions/persist/build.xml" target="distjars" inheritAll="false"/>
     <ant antfile="extensions/grapher/build.xml" target="distjars" inheritAll="false"/>
@@ -62,9 +61,6 @@
       <fileset dir="extensions/throwingproviders/build" includes="*.jar"/>
     </copy>
     <copy toDir="${build.dir}/dist">
-      <fileset dir="extensions/multibindings/build" includes="*.jar"/>
-    </copy>
-    <copy toDir="${build.dir}/dist">
       <fileset dir="extensions/dagger-adapter/build" includes="*.jar"/>
     </copy>
     <copy toDir="${build.dir}/dist">
@@ -120,10 +116,11 @@
         <pathelement location="${build.dir}/dist/guice-${version}.jar"/>
         <pathelement location="lib/javax.inject.jar"/>
         <pathelement location="lib/aopalliance.jar"/>
-        <pathelement location="lib/guava-16.0.1.jar"/>
-        <pathelement location="lib/build/guava-testlib-16.0.1.jar"/>
+        <pathelement location="lib/guava-19.0.jar"/>
+        <pathelement location="lib/build/guava-testlib-19.0.jar"/>
         <pathelement location="lib/build/junit.jar"/>
         <pathelement location="lib/build/servlet-api-2.5.jar"/>
+        <pathelement location="lib/build/truth-0.36.jar"/>
         <pathelement location="lib/build/easymock.jar"/>
         <pathelement location="lib/build/javax.inject-tck.jar"/>
         <pathelement location="lib/build/bnd-0.0.384.jar"/>
@@ -139,7 +136,7 @@
     </java>
   </target>
 
-  <property name="old.api" value="3.0"/>
+  <property name="old.api" value="4.1"/>
   <property name="new.api" value="latest"/>
   <target name="jdiff" depends="compile">
     <property name="jdiff.home" value="lib/build/jdiff"/>
@@ -162,7 +159,6 @@
       <fileset dir="${jmx.src.dir}"/>
       <fileset dir="${jndi.src.dir}"/>
       <fileset dir="${throwingproviders.src.dir}"/>
-      <fileset dir="${multibindings.src.dir}"/>
       <fileset dir="${daggeradapter.src.dir}"/>
       <fileset dir="${persist.src.dir}"/>
       <fileset dir="${struts2.src.dir}"/>
@@ -204,7 +200,7 @@
              windowtitle="Guice ${new.api} API"
              author="false"
              protected="true">
-      <group title="Guice Core" packages="com.google.inject:com.google.inject.util:com.google.inject.spi:com.google.inject.name:com.google.inject.matcher:com.google.inject.binder"/>
+      <group title="Guice Core" packages="com.google.inject:com.google.inject.util:com.google.inject.spi:com.google.inject.name:com.google.inject.matcher:com.google.inject.binder:com.google.inject.multibindings:"/>
       <fileset dir="${src.dir}" defaultexcludes="yes">
         <include name="com/google/inject/**"/>
         <exclude name="com/google/inject/internal/**"/>
@@ -216,9 +212,6 @@
       <group title="AssistedInject Extension" packages="com.google.inject.assistedinject"/>
       <fileset dir="${assistedinject.src.dir}"/>
       
-      <group title="Multibinder Extension" packages="com.google.inject.multibindings"/>
-      <fileset dir="${multibindings.src.dir}"/>
-
       <group title="Dagger Adapter" packages="com.google.inject.daggeradapter"/>
       <fileset dir="${daggeradapter.src.dir}"/>
 
@@ -286,13 +279,13 @@
       <arg value="-DNO_AOP" />
     </munge>
     <replace file="build/no_aop/common.xml" value="">
-      <replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/asm-5.0.3.jar"/>]]></replacetoken>
+      <replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/asm-6.0.jar"/>]]></replacetoken>
     </replace>
     <replace file="build/no_aop/common.xml" value="">
-      <replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.1.jar"/>]]></replacetoken>
+      <replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.2.6.jar"/>]]></replacetoken>
     </replace>
     <replace file="build/no_aop/common.xml" value="">
-      <replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.1.jar"><include name="LICENSE"/><include name="NOTICE"/></zipfileset>]]></replacetoken>
+      <replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.2.6.jar"><include name="LICENSE"/><include name="NOTICE"/></zipfileset>]]></replacetoken>
     </replace>
     <replace file="build/no_aop/common.xml" value='Bundle-Name" value="$${ant.project.name} (no_aop)'>
       <replacetoken><![CDATA[Bundle-Name" value="${ant.project.name}]]></replacetoken>
@@ -309,7 +302,6 @@
     <ant dir="extensions/jmx" antfile="build.xml" target="clean"/>
     <ant dir="extensions/jndi" antfile="build.xml" target="clean"/>
     <ant dir="extensions/throwingproviders" antfile="build.xml" target="clean"/>
-    <ant dir="extensions/multibindings" antfile="build.xml" target="clean"/>
     <ant dir="extensions/dagger-adapter" antfile="build.xml" target="clean"/>
     <ant dir="extensions/persist" antfile="build.xml" target="clean"/>
     <ant dir="extensions/grapher" antfile="build.xml" target="clean"/>
diff --git a/common.xml b/common.xml
index a23eb90..0f66192 100644
--- a/common.xml
+++ b/common.xml
@@ -14,7 +14,7 @@
     <javac srcdir="${src.dir}"
          debug="on"
          destdir="${build.dir}/classes"
-         source="1.6" target="1.6" includeantruntime="false">
+         source="1.7" target="1.7" includeantruntime="false">
       <compilerarg value="-Xlint:all,-serial"/>
       <classpath refid="compile.classpath"/>
     </javac>
@@ -39,7 +39,7 @@
     <property name="Bundle-DocURL" value="https://github.com/google/guice"/>
     <property name="Bundle-Copyright" value="Copyright (C) 2006 Google Inc."/>
     <property name="Bundle-License" value="http://www.apache.org/licenses/LICENSE-2.0.txt"/>
-    <property name="Bundle-RequiredExecutionEnvironment" value="JavaSE-1.6"/>
+    <property name="Bundle-RequiredExecutionEnvironment" value="JavaSE-1.7"/>
     <property name="Bundle-Vendor" value="Google, Inc."/>
 
     <property name="Export-Package" value="!${module}.internal.*,${module}.*;version=${api.version}"/>
@@ -76,7 +76,7 @@
     <javac srcdir="${test.dir}"
          debug="on"
          destdir="${build.dir}/test"
-         source="1.6" target="1.6" includeantruntime="false">
+         source="1.7" target="1.7" includeantruntime="false">
       <classpath path="${build.dir}/classes"/>
       <classpath path="${build.dir}/test"/>
       <classpath refid="compile.classpath"/>
@@ -144,8 +144,8 @@
         classpath="${common.basedir}/lib/build/jarjar-1.1.jar"/>
     <jarjar jarfile="${build.dir}/${ant.project.name}-with-deps.jar">
       <fileset dir="${build.dir}/classes"/>
-      <zipfileset src="${common.basedir}/lib/build/cglib-3.1.jar"/>
-      <zipfileset src="${common.basedir}/lib/build/asm-5.0.3.jar"/>
+      <zipfileset src="${common.basedir}/lib/build/cglib-3.2.6.jar"/>
+      <zipfileset src="${common.basedir}/lib/build/asm-6.0.jar"/>
       <rule pattern="net.sf.cglib.*" result="com.google.inject.internal.cglib.$@1"/>
       <rule pattern="net.sf.cglib.**.*" result="com.google.inject.internal.cglib.@1.$@2"/>
       <rule pattern="org.objectweb.asm.*" result="com.google.inject.internal.asm.$@1"/>
diff --git a/core/pom.xml b/core/pom.xml
index 5a11a23..f2ab9ca 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.google.inject</groupId>
     <artifactId>guice-parent</artifactId>
-    <version>4.0</version>
+    <version>4.2.0</version>
   </parent>
 
   <artifactId>guice</artifactId>
@@ -70,6 +70,11 @@
       <version>3.0.5</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.truth</groupId>
+      <artifactId>truth</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
@@ -126,6 +131,11 @@
             <exclude>LICENSE</exclude>
             <exclude>NOTICE</exclude>
           </excludes>
+          <archive>
+            <manifestEntries>
+              <Automatic-Module-Name>com.google.guice</Automatic-Module-Name>
+            </manifestEntries>
+          </archive>
         </configuration>
       </plugin>
       <!--
diff --git a/core/src/com/google/inject/AbstractModule.java b/core/src/com/google/inject/AbstractModule.java
index fafbd12..7fece9f 100644
--- a/core/src/com/google/inject/AbstractModule.java
+++ b/core/src/com/google/inject/AbstractModule.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,15 +27,13 @@
 import com.google.inject.spi.ProvisionListener;
 import com.google.inject.spi.TypeConverter;
 import com.google.inject.spi.TypeListener;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 
 /**
- * A support class for {@link Module}s which reduces repetition and results in
- * a more readable configuration. Simply extend this class, implement {@link
- * #configure()}, and call the inherited methods which mirror those found in
- * {@link Binder}. For example:
+ * A support class for {@link Module}s which reduces repetition and results in a more readable
+ * configuration. Simply extend this class, implement {@link #configure()}, and call the inherited
+ * methods which mirror those found in {@link Binder}. For example:
  *
  * <pre>
  * public class MyModule extends AbstractModule {
@@ -54,84 +52,63 @@
 
   Binder binder;
 
+  @Override
   public final synchronized void configure(Binder builder) {
     checkState(this.binder == null, "Re-entry is not allowed.");
 
     this.binder = checkNotNull(builder, "builder");
     try {
       configure();
-    }
-    finally {
+    } finally {
       this.binder = null;
     }
   }
 
-  /**
-   * Configures a {@link Binder} via the exposed methods.
-   */
-  protected abstract void configure();
+  /** Configures a {@link Binder} via the exposed methods. */
+  protected void configure() {}
 
-  /**
-   * Gets direct access to the underlying {@code Binder}.
-   */
+  /** Gets direct access to the underlying {@code Binder}. */
   protected Binder binder() {
     checkState(binder != null, "The binder can only be used inside configure()");
     return binder;
   }
 
-  /**
-   * @see Binder#bindScope(Class, Scope)
-   */
-  protected void bindScope(Class<? extends Annotation> scopeAnnotation,
-      Scope scope) {
+  /** @see Binder#bindScope(Class, Scope) */
+  protected void bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) {
     binder().bindScope(scopeAnnotation, scope);
   }
 
-  /**
-   * @see Binder#bind(Key)
-   */
+  /** @see Binder#bind(Key) */
   protected <T> LinkedBindingBuilder<T> bind(Key<T> key) {
     return binder().bind(key);
   }
 
-  /**
-   * @see Binder#bind(TypeLiteral)
-   */
+  /** @see Binder#bind(TypeLiteral) */
   protected <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
     return binder().bind(typeLiteral);
   }
 
-  /**
-   * @see Binder#bind(Class)
-   */
+  /** @see Binder#bind(Class) */
   protected <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
     return binder().bind(clazz);
   }
 
-  /**
-   * @see Binder#bindConstant()
-   */
+  /** @see Binder#bindConstant() */
   protected AnnotatedConstantBindingBuilder bindConstant() {
     return binder().bindConstant();
   }
 
-  /**
-   * @see Binder#install(Module)
-   */
+  /** @see Binder#install(Module) */
   protected void install(Module module) {
     binder().install(module);
   }
 
-  /**
-   * @see Binder#addError(String, Object[])
-   */
+  /** @see Binder#addError(String, Object[]) */
   protected void addError(String message, Object... arguments) {
     binder().addError(message, arguments);
   }
 
-  /**
-   * @see Binder#addError(Throwable) 
-   */
+  /** @see Binder#addError(Throwable) */
   protected void addError(Throwable t) {
     binder().addError(t);
   }
@@ -152,9 +129,7 @@
     binder().requestInjection(instance);
   }
 
-  /**
-   * @see Binder#requestStaticInjection(Class[])
-   */
+  /** @see Binder#requestStaticInjection(Class[]) */
   protected void requestStaticInjection(Class<?>... types) {
     binder().requestStaticInjection(types);
   }
@@ -162,10 +137,10 @@
   /*if[AOP]*/
   /**
    * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher,
-   *  com.google.inject.matcher.Matcher,
-   *  org.aopalliance.intercept.MethodInterceptor[])
+   *     com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
    */
-  protected void bindInterceptor(Matcher<? super Class<?>> classMatcher,
+  protected void bindInterceptor(
+      Matcher<? super Class<?>> classMatcher,
       Matcher<? super Method> methodMatcher,
       org.aopalliance.intercept.MethodInterceptor... interceptors) {
     binder().bindInterceptor(classMatcher, methodMatcher, interceptors);
@@ -173,10 +148,9 @@
   /*end[AOP]*/
 
   /**
-   * Adds a dependency from this module to {@code key}. When the injector is
-   * created, Guice will report an error if {@code key} cannot be injected.
-   * Note that this requirement may be satisfied by implicit binding, such as
-   * a public no-arguments constructor.
+   * Adds a dependency from this module to {@code key}. When the injector is created, Guice will
+   * report an error if {@code key} cannot be injected. Note that this requirement may be satisfied
+   * by implicit binding, such as a public no-arguments constructor.
    *
    * @since 2.0
    */
@@ -185,10 +159,9 @@
   }
 
   /**
-   * Adds a dependency from this module to {@code type}. When the injector is
-   * created, Guice will report an error if {@code type} cannot be injected.
-   * Note that this requirement may be satisfied by implicit binding, such as
-   * a public no-arguments constructor.
+   * Adds a dependency from this module to {@code type}. When the injector is created, Guice will
+   * report an error if {@code type} cannot be injected. Note that this requirement may be satisfied
+   * by implicit binding, such as a public no-arguments constructor.
    *
    * @since 2.0
    */
@@ -216,13 +189,13 @@
    * @see Binder#convertToTypes
    * @since 2.0
    */
-  protected void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
-      TypeConverter converter) {
+  protected void convertToTypes(
+      Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) {
     binder().convertToTypes(typeMatcher, converter);
   }
 
   /**
-   * @see Binder#currentStage() 
+   * @see Binder#currentStage()
    * @since 2.0
    */
   protected Stage currentStage() {
@@ -246,21 +219,19 @@
   }
 
   /**
-   * @see Binder#bindListener(com.google.inject.matcher.Matcher,
-   *  com.google.inject.spi.TypeListener)
+   * @see Binder#bindListener(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeListener)
    * @since 2.0
    */
-  protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
-      TypeListener listener) {
+  protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) {
     binder().bindListener(typeMatcher, listener);
   }
-  
+
   /**
    * @see Binder#bindListener(Matcher, ProvisionListener...)
    * @since 4.0
    */
-  protected void bindListener(Matcher<? super Binding<?>> bindingMatcher,
-      ProvisionListener... listener) {
+  protected void bindListener(
+      Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listener) {
     binder().bindListener(bindingMatcher, listener);
   }
 }
diff --git a/core/src/com/google/inject/Binder.java b/core/src/com/google/inject/Binder.java
index e930c3b..e3fab86 100644
--- a/core/src/com/google/inject/Binder.java
+++ b/core/src/com/google/inject/Binder.java
@@ -26,129 +26,111 @@
 import com.google.inject.spi.ProvisionListener;
 import com.google.inject.spi.TypeConverter;
 import com.google.inject.spi.TypeListener;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
 
 /**
- * Collects configuration information (primarily <i>bindings</i>) which will be
- * used to create an {@link Injector}. Guice provides this object to your
- * application's {@link Module} implementors so they may each contribute
- * their own bindings and other registrations.
+ * Collects configuration information (primarily <i>bindings</i>) which will be used to create an
+ * {@link Injector}. Guice provides this object to your application's {@link Module} implementors so
+ * they may each contribute their own bindings and other registrations.
  *
  * <h3>The Guice Binding EDSL</h3>
  *
- * Guice uses an <i>embedded domain-specific language</i>, or EDSL, to help you
- * create bindings simply and readably.  This approach is great for overall
- * usability, but it does come with a small cost: <b>it is difficult to
- * learn how to use the Binding EDSL by reading
- * method-level javadocs</b>.  Instead, you should consult the series of
- * examples below.  To save space, these examples omit the opening
- * {@code binder}, just as you will if your module extends
- * {@link AbstractModule}.
+ * Guice uses an <i>embedded domain-specific language</i>, or EDSL, to help you create bindings
+ * simply and readably. This approach is great for overall usability, but it does come with a small
+ * cost: <b>it is difficult to learn how to use the Binding EDSL by reading method-level
+ * javadocs</b>. Instead, you should consult the series of examples below. To save space, these
+ * examples omit the opening {@code binder}, just as you will if your module extends {@link
+ * AbstractModule}.
  *
  * <pre>
  *     bind(ServiceImpl.class);</pre>
  *
- * This statement does essentially nothing; it "binds the {@code ServiceImpl}
- * class to itself" and does not change Guice's default behavior.  You may still
- * want to use this if you prefer your {@link Module} class to serve as an
- * explicit <i>manifest</i> for the services it provides.  Also, in rare cases,
- * Guice may be unable to validate a binding at injector creation time unless it
- * is given explicitly.
+ * This statement does essentially nothing; it "binds the {@code ServiceImpl} class to itself" and
+ * does not change Guice's default behavior. You may still want to use this if you prefer your
+ * {@link Module} class to serve as an explicit <i>manifest</i> for the services it provides. Also,
+ * in rare cases, Guice may be unable to validate a binding at injector creation time unless it is
+ * given explicitly.
  *
  * <pre>
  *     bind(Service.class).to(ServiceImpl.class);</pre>
  *
- * Specifies that a request for a {@code Service} instance with no binding
- * annotations should be treated as if it were a request for a
- * {@code ServiceImpl} instance. This <i>overrides</i> the function of any
- * {@link ImplementedBy @ImplementedBy} or {@link ProvidedBy @ProvidedBy}
- * annotations found on {@code Service}, since Guice will have already
- * "moved on" to {@code ServiceImpl} before it reaches the point when it starts
- * looking for these annotations.
+ * Specifies that a request for a {@code Service} instance with no binding annotations should be
+ * treated as if it were a request for a {@code ServiceImpl} instance. This <i>overrides</i> the
+ * function of any {@link ImplementedBy @ImplementedBy} or {@link ProvidedBy @ProvidedBy}
+ * annotations found on {@code Service}, since Guice will have already "moved on" to {@code
+ * ServiceImpl} before it reaches the point when it starts looking for these annotations.
  *
  * <pre>
  *     bind(Service.class).toProvider(ServiceProvider.class);</pre>
  *
- * In this example, {@code ServiceProvider} must extend or implement
- * {@code Provider<Service>}. This binding specifies that Guice should resolve
- * an unannotated injection request for {@code Service} by first resolving an
- * instance of {@code ServiceProvider} in the regular way, then calling
- * {@link Provider#get get()} on the resulting Provider instance to obtain the
- * {@code Service} instance.
+ * In this example, {@code ServiceProvider} must extend or implement {@code Provider<Service>}. This
+ * binding specifies that Guice should resolve an unannotated injection request for {@code Service}
+ * by first resolving an instance of {@code ServiceProvider} in the regular way, then calling {@link
+ * Provider#get get()} on the resulting Provider instance to obtain the {@code Service} instance.
  *
- * <p>The {@link Provider} you use here does not have to be a "factory"; that
- * is, a provider which always <i>creates</i> each instance it provides.
- * However, this is generally a good practice to follow.  You can then use
- * Guice's concept of {@link Scope scopes} to guide when creation should happen
- * -- "letting Guice work for you".
+ * <p>The {@link Provider} you use here does not have to be a "factory"; that is, a provider which
+ * always <i>creates</i> each instance it provides. However, this is generally a good practice to
+ * follow. You can then use Guice's concept of {@link Scope scopes} to guide when creation should
+ * happen -- "letting Guice work for you".
  *
  * <pre>
  *     bind(Service.class).annotatedWith(Red.class).to(ServiceImpl.class);</pre>
  *
- * Like the previous example, but only applies to injection requests that use
- * the binding annotation {@code @Red}.  If your module also includes bindings
- * for particular <i>values</i> of the {@code @Red} annotation (see below),
- * then this binding will serve as a "catch-all" for any values of {@code @Red}
- * that have no exact match in the bindings.
- * 
+ * Like the previous example, but only applies to injection requests that use the binding annotation
+ * {@code @Red}. If your module also includes bindings for particular <i>values</i> of the
+ * {@code @Red} annotation (see below), then this binding will serve as a "catch-all" for any values
+ * of {@code @Red} that have no exact match in the bindings.
+ *
  * <pre>
  *     bind(ServiceImpl.class).in(Singleton.class);
  *     // or, alternatively
  *     bind(ServiceImpl.class).in(Scopes.SINGLETON);</pre>
  *
- * Either of these statements places the {@code ServiceImpl} class into
- * singleton scope.  Guice will create only one instance of {@code ServiceImpl}
- * and will reuse it for all injection requests of this type.  Note that it is
- * still possible to bind another instance of {@code ServiceImpl} if the second
- * binding is qualified by an annotation as in the previous example.  Guice is
- * not overly concerned with <i>preventing</i> you from creating multiple
- * instances of your "singletons", only with <i>enabling</i> your application to
- * share only one instance if that's all you tell Guice you need.
+ * Either of these statements places the {@code ServiceImpl} class into singleton scope. Guice will
+ * create only one instance of {@code ServiceImpl} and will reuse it for all injection requests of
+ * this type. Note that it is still possible to bind another instance of {@code ServiceImpl} if the
+ * second binding is qualified by an annotation as in the previous example. Guice is not overly
+ * concerned with <i>preventing</i> you from creating multiple instances of your "singletons", only
+ * with <i>enabling</i> your application to share only one instance if that's all you tell Guice you
+ * need.
  *
- * <p><b>Note:</b> a scope specified in this way <i>overrides</i> any scope that
- * was specified with an annotation on the {@code ServiceImpl} class.
- * 
- * <p>Besides {@link Singleton}/{@link Scopes#SINGLETON}, there are
- * servlet-specific scopes available in
- * {@code com.google.inject.servlet.ServletScopes}, and your Modules can
- * contribute their own custom scopes for use here as well.
+ * <p><b>Note:</b> a scope specified in this way <i>overrides</i> any scope that was specified with
+ * an annotation on the {@code ServiceImpl} class.
+ *
+ * <p>Besides {@link Singleton}/{@link Scopes#SINGLETON}, there are servlet-specific scopes
+ * available in {@code com.google.inject.servlet.ServletScopes}, and your Modules can contribute
+ * their own custom scopes for use here as well.
  *
  * <pre>
  *     bind(new TypeLiteral&lt;PaymentService&lt;CreditCard>>() {})
  *         .to(CreditCardPaymentService.class);</pre>
  *
- * This admittedly odd construct is the way to bind a parameterized type. It
- * tells Guice how to honor an injection request for an element of type
- * {@code PaymentService<CreditCard>}. The class
- * {@code CreditCardPaymentService} must implement the
- * {@code PaymentService<CreditCard>} interface.  Guice cannot currently bind or
- * inject a generic type, such as {@code Set<E>}; all type parameters must be
- * fully specified.
+ * This admittedly odd construct is the way to bind a parameterized type. It tells Guice how to
+ * honor an injection request for an element of type {@code PaymentService<CreditCard>}. The class
+ * {@code CreditCardPaymentService} must implement the {@code PaymentService<CreditCard>} interface.
+ * Guice cannot currently bind or inject a generic type, such as {@code Set<E>}; all type parameters
+ * must be fully specified.
  *
  * <pre>
  *     bind(Service.class).toInstance(new ServiceImpl());
  *     // or, alternatively
  *     bind(Service.class).toInstance(SomeLegacyRegistry.getService());</pre>
  *
- * In this example, your module itself, <i>not Guice</i>, takes responsibility
- * for obtaining a {@code ServiceImpl} instance, then asks Guice to always use
- * this single instance to fulfill all {@code Service} injection requests.  When
- * the {@link Injector} is created, it will automatically perform field
- * and method injection for this instance, but any injectable constructor on
- * {@code ServiceImpl} is simply ignored.  Note that using this approach results
- * in "eager loading" behavior that you can't control.
+ * In this example, your module itself, <i>not Guice</i>, takes responsibility for obtaining a
+ * {@code ServiceImpl} instance, then asks Guice to always use this single instance to fulfill all
+ * {@code Service} injection requests. When the {@link Injector} is created, it will automatically
+ * perform field and method injection for this instance, but any injectable constructor on {@code
+ * ServiceImpl} is simply ignored. Note that using this approach results in "eager loading" behavior
+ * that you can't control.
  *
  * <pre>
  *     bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre>
  *
- * Sets up a constant binding. Constant injections must always be annotated.
- * When a constant binding's value is a string, it is eligile for conversion to
- * all primitive types, to {@link Enum#valueOf(Class, String) all enums}, and to
- * {@link Class#forName class literals}. Conversions for other types can be
- * configured using {@link #convertToTypes(Matcher, TypeConverter)
+ * Sets up a constant binding. Constant injections must always be annotated. When a constant
+ * binding's value is a string, it is eligile for conversion to all primitive types, to {@link
+ * Enum#valueOf(Class, String) all enums}, and to {@link Class#forName class literals}. Conversions
+ * for other types can be configured using {@link #convertToTypes(Matcher, TypeConverter)
  * convertToTypes()}.
  *
  * <pre>
@@ -157,46 +139,42 @@
  *     red = MyModule.class.getDeclaredField("red").getAnnotation(Color.class);
  *     bind(Service.class).annotatedWith(red).to(RedService.class);</pre>
  *
- * If your binding annotation has parameters you can apply different bindings to
- * different specific values of your annotation.  Getting your hands on the
- * right instance of the annotation is a bit of a pain -- one approach, shown
- * above, is to apply a prototype annotation to a field in your module class, so
- * that you can read this annotation instance and give it to Guice.
+ * If your binding annotation has parameters you can apply different bindings to different specific
+ * values of your annotation. Getting your hands on the right instance of the annotation is a bit of
+ * a pain -- one approach, shown above, is to apply a prototype annotation to a field in your module
+ * class, so that you can read this annotation instance and give it to Guice.
  *
  * <pre>
  *     bind(Service.class)
  *         .annotatedWith(Names.named("blue"))
  *         .to(BlueService.class);</pre>
  *
- * Differentiating by names is a common enough use case that we provided a
- * standard annotation, {@link com.google.inject.name.Named @Named}.  Because of
- * Guice's library support, binding by name is quite easier than in the
- * arbitrary binding annotation case we just saw.  However, remember that these
- * names will live in a single flat namespace with all the other names used in
- * your application.
+ * Differentiating by names is a common enough use case that we provided a standard annotation,
+ * {@link com.google.inject.name.Named @Named}. Because of Guice's library support, binding by name
+ * is quite easier than in the arbitrary binding annotation case we just saw. However, remember that
+ * these names will live in a single flat namespace with all the other names used in your
+ * application.
  *
  * <pre>
  *     Constructor<T> loneCtor = getLoneCtorFromServiceImplViaReflection();
  *     bind(ServiceImpl.class)
  *         .toConstructor(loneCtor);</pre>
  *
- * In this example, we directly tell Guice which constructor to use in a concrete
- * class implementation. It means that we do not need to place {@literal @}Inject
- * on any of the constructors and that Guice treats the provided constructor as though
- * it were annotated so. It is useful for cases where you cannot modify existing
- * classes and is a bit simpler than using a {@link Provider}.
+ * In this example, we directly tell Guice which constructor to use in a concrete class
+ * implementation. It means that we do not need to place {@literal @}Inject on any of the
+ * constructors and that Guice treats the provided constructor as though it were annotated so. It is
+ * useful for cases where you cannot modify existing classes and is a bit simpler than using a
+ * {@link Provider}.
  *
- * <p>The above list of examples is far from exhaustive.  If you can think of
- * how the concepts of one example might coexist with the concepts from another,
- * you can most likely weave the two together.  If the two concepts make no
- * sense with each other, you most likely won't be able to do it.  In a few
- * cases Guice will let something bogus slip by, and will then inform you of
- * the problems at runtime, as soon as you try to create your Injector.
+ * <p>The above list of examples is far from exhaustive. If you can think of how the concepts of one
+ * example might coexist with the concepts from another, you can most likely weave the two together.
+ * If the two concepts make no sense with each other, you most likely won't be able to do it. In a
+ * few cases Guice will let something bogus slip by, and will then inform you of the problems at
+ * runtime, as soon as you try to create your Injector.
  *
- * <p>The other methods of Binder such as {@link #bindScope},
- * {@link #bindInterceptor}, {@link #install}, {@link #requestStaticInjection},
- * {@link #addError} and {@link #currentStage} are not part of the Binding EDSL;
- * you can learn how to use these in the usual way, from the method
+ * <p>The other methods of Binder such as {@link #bindScope}, {@link #bindInterceptor}, {@link
+ * #install}, {@link #requestStaticInjection}, {@link #addError} and {@link #currentStage} are not
+ * part of the Binding EDSL; you can learn how to use these in the usual way, from the method
  * documentation.
  *
  * @author crazybob@google.com (Bob Lee)
@@ -211,51 +189,41 @@
    * eligible for interception if:
    *
    * <ul>
-   *  <li>Guice created the instance the method is on</li>
-   *  <li>Neither the enclosing type nor the method is final</li>
-   *  <li>And the method is package-private, protected, or public</li>
+   * <li>Guice created the instance the method is on
+   * <li>Neither the enclosing type nor the method is final
+   * <li>And the method is package-private, protected, or public
    * </ul>
    *
-   * @param classMatcher matches classes the interceptor should apply to. For
-   *     example: {@code only(Runnable.class)}.
-   * @param methodMatcher matches methods the interceptor should apply to. For
-   *     example: {@code annotatedWith(Transactional.class)}.
-   * @param interceptors to bind.  The interceptors are called in the order they
-   *     are given.
+   * @param classMatcher matches classes the interceptor should apply to. For example: {@code
+   *     only(Runnable.class)}.
+   * @param methodMatcher matches methods the interceptor should apply to. For example: {@code
+   *     annotatedWith(Transactional.class)}.
+   * @param interceptors to bind. The interceptors are called in the order they are given.
    */
-  void bindInterceptor(Matcher<? super Class<?>> classMatcher,
+  void bindInterceptor(
+      Matcher<? super Class<?>> classMatcher,
       Matcher<? super Method> methodMatcher,
       org.aopalliance.intercept.MethodInterceptor... interceptors);
   /*end[AOP]*/
 
-  /**
-   * Binds a scope to an annotation.
-   */
+  /** Binds a scope to an annotation. */
   void bindScope(Class<? extends Annotation> annotationType, Scope scope);
 
-  /**
-   * See the EDSL examples at {@link Binder}.
-   */
+  /** See the EDSL examples at {@link Binder}. */
   <T> LinkedBindingBuilder<T> bind(Key<T> key);
 
-  /**
-   * See the EDSL examples at {@link Binder}.
-   */
+  /** See the EDSL examples at {@link Binder}. */
   <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral);
 
-  /**
-   * See the EDSL examples at {@link Binder}.
-   */
+  /** See the EDSL examples at {@link Binder}. */
   <T> AnnotatedBindingBuilder<T> bind(Class<T> type);
 
-  /**
-   * See the EDSL examples at {@link Binder}.
-   */
+  /** See the EDSL examples at {@link Binder}. */
   AnnotatedConstantBindingBuilder bindConstant();
 
   /**
-   * Upon successful creation, the {@link Injector} will inject instance fields
-   * and methods of the given object.
+   * Upon successful creation, the {@link Injector} will inject instance fields and methods of the
+   * given object.
    *
    * @param type of instance
    * @param instance for which members will be injected
@@ -264,8 +232,8 @@
   <T> void requestInjection(TypeLiteral<T> type, T instance);
 
   /**
-   * Upon successful creation, the {@link Injector} will inject instance fields
-   * and methods of the given object.
+   * Upon successful creation, the {@link Injector} will inject instance fields and methods of the
+   * given object.
    *
    * @param instance for which members will be injected
    * @since 2.0
@@ -273,37 +241,30 @@
   void requestInjection(Object instance);
 
   /**
-   * Upon successful creation, the {@link Injector} will inject static fields
-   * and methods in the given classes.
+   * Upon successful creation, the {@link Injector} will inject static fields and methods in the
+   * given classes.
    *
    * @param types for which static members will be injected
    */
   void requestStaticInjection(Class<?>... types);
 
-  /**
-   * Uses the given module to configure more bindings.
-   */
+  /** Uses the given module to configure more bindings. */
   void install(Module module);
 
-  /**
-   * Gets the current stage.
-   */
+  /** Gets the current stage. */
   Stage currentStage();
 
   /**
-   * Records an error message which will be presented to the user at a later
-   * time. Unlike throwing an exception, this enable us to continue
-   * configuring the Injector and discover more errors. Uses {@link
-   * String#format(String, Object[])} to insert the arguments into the
-   * message.
+   * Records an error message which will be presented to the user at a later time. Unlike throwing
+   * an exception, this enable us to continue configuring the Injector and discover more errors.
+   * Uses {@link String#format(String, Object[])} to insert the arguments into the message.
    */
   void addError(String message, Object... arguments);
 
   /**
-   * Records an exception, the full details of which will be logged, and the
-   * message of which will be presented to the user at a later
-   * time. If your Module calls something that you worry may fail, you should
-   * catch the exception and pass it into this.
+   * Records an exception, the full details of which will be logged, and the message of which will
+   * be presented to the user at a later time. If your Module calls something that you worry may
+   * fail, you should catch the exception and pass it into this.
    */
   void addError(Throwable t);
 
@@ -315,32 +276,29 @@
   void addError(Message message);
 
   /**
-   * Returns the provider used to obtain instances for the given injection key.
-   * The returned provider will not be valid until the {@link Injector} has been
-   * created. The provider will throw an {@code IllegalStateException} if you
-   * try to use it beforehand.
+   * Returns the provider used to obtain instances for the given injection key. The returned
+   * provider will not be valid until the {@link Injector} has been created. The provider will throw
+   * an {@code IllegalStateException} if you try to use it beforehand.
    *
    * @since 2.0
    */
   <T> Provider<T> getProvider(Key<T> key);
 
   /**
-   * Returns the provider used to obtain instances for the given injection key.
-   * The returned provider will be attached to the injection point and will
-   * follow the nullability specified in the dependency.
-   * Additionally, the returned provider will not be valid until the {@link Injector} 
-   * has been created. The provider will throw an {@code IllegalStateException} if you
-   * try to use it beforehand.
+   * Returns the provider used to obtain instances for the given injection key. The returned
+   * provider will be attached to the injection point and will follow the nullability specified in
+   * the dependency. Additionally, the returned provider will not be valid until the {@link
+   * Injector} has been created. The provider will throw an {@code IllegalStateException} if you try
+   * to use it beforehand.
    *
    * @since 4.0
    */
   <T> Provider<T> getProvider(Dependency<T> dependency);
 
   /**
-   * Returns the provider used to obtain instances for the given injection type.
-   * The returned provider will not be valid until the {@link Injector} has been
-   * created. The provider will throw an {@code IllegalStateException} if you
-   * try to use it beforehand.
+   * Returns the provider used to obtain instances for the given injection type. The returned
+   * provider will not be valid until the {@link Injector} has been created. The provider will throw
+   * an {@code IllegalStateException} if you try to use it beforehand.
    *
    * @since 2.0
    */
@@ -369,15 +327,14 @@
   <T> MembersInjector<T> getMembersInjector(Class<T> type);
 
   /**
-   * Binds a type converter. The injector will use the given converter to
-   * convert string constants to matching types as needed.
+   * Binds a type converter. The injector will use the given converter to convert string constants
+   * to matching types as needed.
    *
    * @param typeMatcher matches types the converter can handle
    * @param converter converts values
    * @since 2.0
    */
-  void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
-      TypeConverter converter);
+  void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter);
 
   /**
    * Registers a listener for injectable types. Guice will notify the listener when it encounters
@@ -387,43 +344,38 @@
    * @param listener for injectable types matched by typeMatcher
    * @since 2.0
    */
-  void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
-      TypeListener listener);
+  void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener);
 
   /**
-   * Registers listeners for provisioned objects. Guice will notify the
-   * listeners just before and after the object is provisioned. Provisioned
-   * objects that are also injectable (everything except objects provided
-   * through Providers) can also be notified through TypeListeners registered in
-   * {@link #bindListener}.
-   * 
-   * @param bindingMatcher that matches bindings of provisioned objects the listener
-   *          should be notified of
-   * @param listeners for provisioned objects matched by bindingMatcher 
+   * Registers listeners for provisioned objects. Guice will notify the listeners just before and
+   * after the object is provisioned. Provisioned objects that are also injectable (everything
+   * except objects provided through Providers) can also be notified through TypeListeners
+   * registered in {@link #bindListener}.
+   *
+   * @param bindingMatcher that matches bindings of provisioned objects the listener should be
+   *     notified of
+   * @param listeners for provisioned objects matched by bindingMatcher
    * @since 4.0
    */
   void bindListener(Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners);
 
   /**
-   * Returns a binder that uses {@code source} as the reference location for
-   * configuration errors. This is typically a {@link StackTraceElement}
-   * for {@code .java} source but it could any binding source, such as the
-   * path to a {@code .properties} file.
+   * Returns a binder that uses {@code source} as the reference location for configuration errors.
+   * This is typically a {@link StackTraceElement} for {@code .java} source but it could any binding
+   * source, such as the path to a {@code .properties} file.
    *
-   * @param source any object representing the source location and has a
-   *     concise {@link Object#toString() toString()} value
+   * @param source any object representing the source location and has a concise {@link
+   *     Object#toString() toString()} value
    * @return a binder that shares its configuration with this binder
    * @since 2.0
    */
   Binder withSource(Object source);
 
   /**
-   * Returns a binder that skips {@code classesToSkip} when identify the
-   * calling code. The caller's {@link StackTraceElement} is used to locate
-   * the source of configuration errors.
+   * Returns a binder that skips {@code classesToSkip} when identify the calling code. The caller's
+   * {@link StackTraceElement} is used to locate the source of configuration errors.
    *
-   * @param classesToSkip library classes that create bindings on behalf of
-   *      their clients.
+   * @param classesToSkip library classes that create bindings on behalf of their clients.
    * @return a binder that shares its configuration with this binder.
    * @since 2.0
    */
@@ -435,75 +387,69 @@
    * PrivateModule} for details.
    *
    * @return a binder that inherits configuration from this binder. Only exposed configuration on
-   *      the returned binder will be visible to this binder.
+   *     the returned binder will be visible to this binder.
    * @since 2.0
    */
   PrivateBinder newPrivateBinder();
 
   /**
-   * Instructs the Injector that bindings must be listed in a Module in order to
-   * be injected. Classes that are not explicitly bound in a module cannot be
-   * injected. Bindings created through a linked binding
-   * (<code>bind(Foo.class).to(FooImpl.class)</code>) are allowed, but the
-   * implicit binding (<code>FooImpl</code>) cannot be directly injected unless
-   * it is also explicitly bound (<code>bind(FooImpl.class)</code>).
-   * <p>
-   * Tools can still retrieve bindings for implicit bindings (bindings created
-   * through a linked binding) if explicit bindings are required, however
-   * {@link Binding#getProvider} will fail.
-   * <p>
-   * By default, explicit bindings are not required.
-   * <p>
-   * If a parent injector requires explicit bindings, then all child injectors
-   * (and private modules within that injector) also require explicit bindings.
-   * If a parent does not require explicit bindings, a child injector or private
-   * module may optionally declare itself as requiring explicit bindings. If it
-   * does, the behavior is limited only to that child or any grandchildren. No
-   * siblings of the child will require explicit bindings.
-   * <p>
-   * In the absence of an explicit binding for the target, linked bindings in
-   * child injectors create a binding for the target in the parent. Since this
-   * behavior can be surprising, it causes an error instead if explicit bindings
-   * are required. To avoid this error, add an explicit binding for the target,
-   * either in the child or the parent.
-   * 
+   * Instructs the Injector that bindings must be listed in a Module in order to be injected.
+   * Classes that are not explicitly bound in a module cannot be injected. Bindings created through
+   * a linked binding (<code>bind(Foo.class).to(FooImpl.class)</code>) are allowed, but the implicit
+   * binding (<code>FooImpl</code>) cannot be directly injected unless it is also explicitly bound (
+   * <code>bind(FooImpl.class)</code>).
+   *
+   * <p>Tools can still retrieve bindings for implicit bindings (bindings created through a linked
+   * binding) if explicit bindings are required, however {@link Binding#getProvider} will fail.
+   *
+   * <p>By default, explicit bindings are not required.
+   *
+   * <p>If a parent injector requires explicit bindings, then all child injectors (and private
+   * modules within that injector) also require explicit bindings. If a parent does not require
+   * explicit bindings, a child injector or private module may optionally declare itself as
+   * requiring explicit bindings. If it does, the behavior is limited only to that child or any
+   * grandchildren. No siblings of the child will require explicit bindings.
+   *
+   * <p>In the absence of an explicit binding for the target, linked bindings in child injectors
+   * create a binding for the target in the parent. Since this behavior can be surprising, it causes
+   * an error instead if explicit bindings are required. To avoid this error, add an explicit
+   * binding for the target, either in the child or the parent.
+   *
    * @since 3.0
    */
   void requireExplicitBindings();
-  
+
   /**
-   * Prevents Guice from constructing a {@link Proxy} when a circular dependency
-   * is found.  By default, circular proxies are not disabled.
-   * <p>
-   * If a parent injector disables circular proxies, then all child injectors
-   * (and private modules within that injector) also disable circular proxies.
-   * If a parent does not disable circular proxies, a child injector or private
-   * module may optionally declare itself as disabling circular proxies. If it
-   * does, the behavior is limited only to that child or any grandchildren. No
-   * siblings of the child will disable circular proxies.
-   * 
+   * Prevents Guice from injecting dependencies that form a cycle, unless broken by a {@link
+   * Provider}. By default, circular dependencies are not disabled.
+   *
+   * <p>If a parent injector disables circular dependencies, then all child injectors (and private
+   * modules within that injector) also disable circular dependencies. If a parent does not disable
+   * circular dependencies, a child injector or private module may optionally declare itself as
+   * disabling circular dependencies. If it does, the behavior is limited only to that child or any
+   * grandchildren. No siblings of the child will disable circular dependencies.
+   *
    * @since 3.0
    */
   void disableCircularProxies();
-  
+
   /**
    * Requires that a {@literal @}{@link Inject} annotation exists on a constructor in order for
    * Guice to consider it an eligible injectable class. By default, Guice will inject classes that
    * have a no-args constructor if no {@literal @}{@link Inject} annotation exists on any
    * constructor.
-   * <p>
-   * If the class is bound using {@link LinkedBindingBuilder#toConstructor}, Guice will still inject
-   * that constructor regardless of annotations.
+   *
+   * <p>If the class is bound using {@link LinkedBindingBuilder#toConstructor}, Guice will still
+   * inject that constructor regardless of annotations.
    *
    * @since 4.0
    */
   void requireAtInjectOnConstructors();
 
   /**
-   * Requires that Guice finds an exactly matching binding annotation.  This disables the
-   * error-prone feature in Guice where it can substitute a binding for
-   * <code>{@literal @}Named Foo</code> when attempting to inject
-   * <code>{@literal @}Named("foo") Foo</code>.
+   * Requires that Guice finds an exactly matching binding annotation. This disables the error-prone
+   * feature in Guice where it can substitute a binding for <code>{@literal @}Named Foo</code> when
+   * attempting to inject <code>{@literal @}Named("foo") Foo</code>.
    *
    * @since 4.0
    */
diff --git a/core/src/com/google/inject/Binding.java b/core/src/com/google/inject/Binding.java
index 332237e..caf52f0 100644
--- a/core/src/com/google/inject/Binding.java
+++ b/core/src/com/google/inject/Binding.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,55 +22,50 @@
 
 /**
  * A mapping from a key (type and optional annotation) to the strategy for getting instances of the
- * type. This interface is part of the introspection API and is intended primarily for use by 
- * tools.
+ * type. This interface is part of the introspection API and is intended primarily for use by tools.
  *
  * <p>Bindings are created in several ways:
+ *
  * <ul>
- *     <li>Explicitly in a module, via {@code bind()} and {@code bindConstant()}
- *         statements:
- * <pre>
+ * <li>Explicitly in a module, via {@code bind()} and {@code bindConstant()} statements:
+ *     <pre>
  *     bind(Service.class).annotatedWith(Red.class).to(ServiceImpl.class);
- *     bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre></li>
- *     <li>Implicitly by the Injector by following a type's {@link ImplementedBy
- *         pointer} {@link ProvidedBy annotations} or by using its {@link Inject annotated} or
- *         default constructor.</li>
- *     <li>By converting a bound instance to a different type.</li>
- *     <li>For {@link Provider providers}, by delegating to the binding for the provided type.</li>
+ *     bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre>
+ *
+ * <li>Implicitly by the Injector by following a type's {@link ImplementedBy pointer} {@link
+ *     ProvidedBy annotations} or by using its {@link Inject annotated} or default constructor.
+ * <li>By converting a bound instance to a different type.
+ * <li>For {@link Provider providers}, by delegating to the binding for the provided type.
  * </ul>
  *
- *
  * <p>They exist on both modules and on injectors, and their behaviour is different for each:
+ *
  * <ul>
- *     <li><strong>Module bindings</strong> are incomplete and cannot be used to provide instances.
- *         This is because the applicable scopes and interceptors may not be known until an injector
- *         is created. From a tool's perspective, module bindings are like the injector's source
- *         code. They can be inspected or rewritten, but this analysis must be done statically.</li>
- *     <li><strong>Injector bindings</strong> are complete and valid and can be used to provide
- *         instances. From a tools' perspective, injector bindings are like reflection for an
- *         injector. They have full runtime information, including the complete graph of injections
- *         necessary to satisfy a binding.</li>
+ * <li><strong>Module bindings</strong> are incomplete and cannot be used to provide instances. This
+ *     is because the applicable scopes and interceptors may not be known until an injector is
+ *     created. From a tool's perspective, module bindings are like the injector's source code. They
+ *     can be inspected or rewritten, but this analysis must be done statically.
+ * <li><strong>Injector bindings</strong> are complete and valid and can be used to provide
+ *     instances. From a tools' perspective, injector bindings are like reflection for an injector.
+ *     They have full runtime information, including the complete graph of injections necessary to
+ *     satisfy a binding.
  * </ul>
  *
  * @param <T> the bound type. The injected is always assignable to this type.
- *
  * @author crazybob@google.com (Bob Lee)
  * @author jessewilson@google.com (Jesse Wilson)
  */
 public interface Binding<T> extends Element {
 
-  /**
-   * Returns the key for this binding.
-   */
+  /** Returns the key for this binding. */
   Key<T> getKey();
 
   /**
-   * Returns the scoped provider guice uses to fulfill requests for this
-   * binding.
+   * Returns the scoped provider guice uses to fulfill requests for this binding.
    *
-   * @throws UnsupportedOperationException when invoked on a {@link Binding}
-   *      created via {@link com.google.inject.spi.Elements#getElements}. This
-   *      method is only supported on {@link Binding}s returned from an injector.
+   * @throws UnsupportedOperationException when invoked on a {@link Binding} created via {@link
+   *     com.google.inject.spi.Elements#getElements}. This method is only supported on {@link
+   *     Binding}s returned from an injector.
    */
   Provider<T> getProvider();
 
diff --git a/core/src/com/google/inject/BindingAnnotation.java b/core/src/com/google/inject/BindingAnnotation.java
index 2d373e4..5a2050e 100644
--- a/core/src/com/google/inject/BindingAnnotation.java
+++ b/core/src/com/google/inject/BindingAnnotation.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,9 +23,9 @@
 import java.lang.annotation.Target;
 
 /**
- * Annotates annotations which are used for binding. Only one such annotation
- * may apply to a single injection point. You must also annotate binder
- * annotations with {@code @Retention(RUNTIME)}. For example:
+ * Annotates annotations which are used for binding. Only one such annotation may apply to a single
+ * injection point. You must also annotate binder annotations with {@code @Retention(RUNTIME)}. For
+ * example:
  *
  * <pre>
  *   {@code @}Retention(RUNTIME)
diff --git a/core/src/com/google/inject/ConfigurationException.java b/core/src/com/google/inject/ConfigurationException.java
index e298cff..3d3b73c 100644
--- a/core/src/com/google/inject/ConfigurationException.java
+++ b/core/src/com/google/inject/ConfigurationException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,8 @@
 
 import static com.google.common.base.Preconditions.checkState;
 
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.internal.Errors;
+import com.google.inject.internal.Messages;
 import com.google.inject.spi.Message;
-
 import java.util.Collection;
 
 /**
@@ -33,13 +31,13 @@
  */
 public final class ConfigurationException extends RuntimeException {
 
-  private final ImmutableSet<Message> messages;
+  private final com.google.common.collect.ImmutableSet<Message> messages;
   private Object partialValue = null;
 
   /** Creates a ConfigurationException containing {@code messages}. */
   public ConfigurationException(Iterable<Message> messages) {
-    this.messages = ImmutableSet.copyOf(messages); 
-    initCause(Errors.getOnlyCause(this.messages));
+    this.messages = com.google.common.collect.ImmutableSet.copyOf(messages);
+    initCause(Messages.getOnlyCause(this.messages));
   }
 
   /** Returns a copy of this configuration exception with the specified partial value. */
@@ -57,20 +55,23 @@
   }
 
   /**
-   * Returns a value that was only partially computed due to this exception. The caller can use
-   * this while collecting additional configuration problems.
+   * Returns a value that was only partially computed due to this exception. The caller can use this
+   * while collecting additional configuration problems.
    *
    * @return the partial value, or {@code null} if none was set. The type of the partial value is
-   *      specified by the throwing method.
+   *     specified by the throwing method.
    */
-  @SuppressWarnings("unchecked") // this is *extremely* unsafe. We trust the caller here.
+  @SuppressWarnings({
+    "unchecked",
+    "TypeParameterUnusedInFormals"
+  }) // this is *extremely* unsafe. We trust the caller here.
   public <E> E getPartialValue() {
     return (E) partialValue;
   }
 
   @Override public String getMessage() {
-    return Errors.format("Guice configuration errors", messages);
+    return Messages.formatMessages("Guice configuration errors", messages);
   }
 
   private static final long serialVersionUID = 0;
-}
\ No newline at end of file
+}
diff --git a/core/src/com/google/inject/CreationException.java b/core/src/com/google/inject/CreationException.java
index 4f84c22..38e8281 100644
--- a/core/src/com/google/inject/CreationException.java
+++ b/core/src/com/google/inject/CreationException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,8 @@
 import static com.google.common.base.Preconditions.checkArgument;
 
 import com.google.common.collect.ImmutableSet;
-import com.google.inject.internal.Errors;
+import com.google.inject.internal.Messages;
 import com.google.inject.spi.Message;
-
 import java.util.Collection;
 
 /**
@@ -38,7 +37,7 @@
   public CreationException(Collection<Message> messages) {
     this.messages = ImmutableSet.copyOf(messages);
     checkArgument(!this.messages.isEmpty());
-    initCause(Errors.getOnlyCause(this.messages));
+    initCause(Messages.getOnlyCause(this.messages));
   }
 
   /** Returns messages for the errors that caused this exception. */
@@ -46,8 +45,9 @@
     return messages;
   }
 
-  @Override public String getMessage() {
-    return Errors.format("Unable to create injector, see the following errors", messages);
+  @Override
+  public String getMessage() {
+    return Messages.formatMessages("Unable to create injector, see the following errors", messages);
   }
 
   private static final long serialVersionUID = 0;
diff --git a/core/src/com/google/inject/Exposed.java b/core/src/com/google/inject/Exposed.java
index 45a448f..9e2e441 100644
--- a/core/src/com/google/inject/Exposed.java
+++ b/core/src/com/google/inject/Exposed.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,5 +30,7 @@
  * @author jessewilson@google.com (Jesse Wilson)
  * @since 2.0
  */
-@Target(ElementType.METHOD) @Retention(RUNTIME) @Documented
+@Target(ElementType.METHOD)
+@Retention(RUNTIME)
+@Documented
 public @interface Exposed {}
diff --git a/core/src/com/google/inject/Guice.java b/core/src/com/google/inject/Guice.java
index 703187f..ae8d43b 100644
--- a/core/src/com/google/inject/Guice.java
+++ b/core/src/com/google/inject/Guice.java
@@ -17,19 +17,17 @@
 package com.google.inject;
 
 import com.google.inject.internal.InternalInjectorCreator;
-
 import java.util.Arrays;
 
 /**
- * The entry point to the Guice framework. Creates {@link Injector}s from
- * {@link Module}s.
+ * The entry point to the Guice framework. Creates {@link Injector}s from {@link Module}s.
  *
- * <p>Guice supports a model of development that draws clear boundaries between
- * APIs, Implementations of these APIs, Modules which configure these
- * implementations, and finally Applications which consist of a collection of
- * Modules. It is the Application, which typically defines your {@code main()}
- * method, that bootstraps the Guice Injector using the {@code Guice} class, as
- * in this example:
+ * <p>Guice supports a model of development that draws clear boundaries between APIs,
+ * Implementations of these APIs, Modules which configure these implementations, and finally
+ * Applications which consist of a collection of Modules. It is the Application, which typically
+ * defines your {@code main()} method, that bootstraps the Guice Injector using the {@code Guice}
+ * class, as in this example:
+ *
  * <pre>
  *     public class FooApplication {
  *       public static void main(String[] args) {
@@ -52,50 +50,40 @@
   private Guice() {}
 
   /**
-   * Creates an injector for the given set of modules. This is equivalent to
-   * calling {@link #createInjector(Stage, Module...)} with Stage.DEVELOPMENT.
+   * Creates an injector for the given set of modules. This is equivalent to calling {@link
+   * #createInjector(Stage, Module...)} with Stage.DEVELOPMENT.
    *
-   * @throws CreationException if one or more errors occur during injector
-   *     construction
+   * @throws CreationException if one or more errors occur during injector construction
    */
   public static Injector createInjector(Module... modules) {
     return createInjector(Arrays.asList(modules));
   }
 
   /**
-   * Creates an injector for the given set of modules. This is equivalent to
-   * calling {@link #createInjector(Stage, Iterable)} with Stage.DEVELOPMENT.
+   * Creates an injector for the given set of modules. This is equivalent to calling {@link
+   * #createInjector(Stage, Iterable)} with Stage.DEVELOPMENT.
    *
-   * @throws CreationException if one or more errors occur during injector
-   *     creation
+   * @throws CreationException if one or more errors occur during injector creation
    */
   public static Injector createInjector(Iterable<? extends Module> modules) {
     return createInjector(Stage.DEVELOPMENT, modules);
   }
 
   /**
-   * Creates an injector for the given set of modules, in a given development
-   * stage.
+   * Creates an injector for the given set of modules, in a given development stage.
    *
-   * @throws CreationException if one or more errors occur during injector
-   *     creation.
+   * @throws CreationException if one or more errors occur during injector creation.
    */
   public static Injector createInjector(Stage stage, Module... modules) {
     return createInjector(stage, Arrays.asList(modules));
   }
 
   /**
-   * Creates an injector for the given set of modules, in a given development
-   * stage.
+   * Creates an injector for the given set of modules, in a given development stage.
    *
-   * @throws CreationException if one or more errors occur during injector
-   *     construction
+   * @throws CreationException if one or more errors occur during injector construction
    */
-  public static Injector createInjector(Stage stage,
-      Iterable<? extends Module> modules) {
-    return new InternalInjectorCreator()
-        .stage(stage)
-        .addModules(modules)
-        .build();
+  public static Injector createInjector(Stage stage, Iterable<? extends Module> modules) {
+    return new InternalInjectorCreator().stage(stage).addModules(modules).build();
   }
 }
diff --git a/core/src/com/google/inject/ImplementedBy.java b/core/src/com/google/inject/ImplementedBy.java
index 464a279..f19bb86 100644
--- a/core/src/com/google/inject/ImplementedBy.java
+++ b/core/src/com/google/inject/ImplementedBy.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,8 +31,6 @@
 @Target(TYPE)
 public @interface ImplementedBy {
 
-  /**
-   * The implementation type.
-   */
+  /** The implementation type. */
   Class<?> value();
 }
diff --git a/core/src/com/google/inject/Inject.java b/core/src/com/google/inject/Inject.java
index 535c0a4..3c4b396 100644
--- a/core/src/com/google/inject/Inject.java
+++ b/core/src/com/google/inject/Inject.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,44 +26,37 @@
 import java.lang.annotation.Target;
 
 /**
- * Annotates members of your implementation class (constructors, methods
- * and fields) into which the {@link Injector} should inject values.
- * The Injector fulfills injection requests for:
+ * Annotates members of your implementation class (constructors, methods and fields) into which the
+ * {@link Injector} should inject values. The Injector fulfills injection requests for:
  *
  * <ul>
- * <li>Every instance it constructs. The class being constructed must have
- * exactly one of its constructors marked with {@code @Inject} or must have a
- * constructor taking no parameters. The Injector then proceeds to perform
- * field and method injections.
- * 
- * <li>Pre-constructed instances passed to {@link Injector#injectMembers},
- * {@link com.google.inject.binder.LinkedBindingBuilder#toInstance(Object)} and
- * {@link com.google.inject.binder.LinkedBindingBuilder#toProvider(javax.inject.Provider)}.
- * In this case all constructors are, of course, ignored.
- *
- * <li>Static fields and methods of classes which any {@link Module} has
- * specifically requested static injection for, using
- * {@link Binder#requestStaticInjection}.
+ * <li>Every instance it constructs. The class being constructed must have exactly one of its
+ *     constructors marked with {@code @Inject} or must have a constructor taking no parameters. The
+ *     Injector then proceeds to perform field and method injections.
+ * <li>Pre-constructed instances passed to {@link Injector#injectMembers}, {@link
+ *     com.google.inject.binder.LinkedBindingBuilder#toInstance(Object)} and {@link
+ *     com.google.inject.binder.LinkedBindingBuilder#toProvider(javax.inject.Provider)}. In this
+ *     case all constructors are, of course, ignored.
+ * <li>Static fields and methods of classes which any {@link Module} has specifically requested
+ *     static injection for, using {@link Binder#requestStaticInjection}.
  * </ul>
  *
- * In all cases, a member can be injected regardless of its Java access
- * specifier (private, default, protected, public).
+ * In all cases, a member can be injected regardless of its Java access specifier (private, default,
+ * protected, public).
  *
  * @author crazybob@google.com (Bob Lee)
  */
-@Target({ METHOD, CONSTRUCTOR, FIELD })
+@Target({METHOD, CONSTRUCTOR, FIELD})
 @Retention(RUNTIME)
 @Documented
 public @interface Inject {
 
   /**
-   * If true, and the appropriate binding is not found,
-   * the Injector will skip injection of this method or field rather than
-   * produce an error. When applied to a field, any default value already
-   * assigned to the field will remain (guice will not actively null out the
-   * field). When applied to a method, the method will only be invoked if
-   * bindings for <i>all</i> parameters are found. When applied to a
-   * constructor, an error will result upon Injector creation.
+   * If true, and the appropriate binding is not found, the Injector will skip injection of this
+   * method or field rather than produce an error. When applied to a field, any default value
+   * already assigned to the field will remain (guice will not actively null out the field). When
+   * applied to a method, the method will only be invoked if bindings for <i>all</i> parameters are
+   * found. When applied to a constructor, an error will result upon Injector creation.
    */
   boolean optional() default false;
 }
diff --git a/core/src/com/google/inject/Injector.java b/core/src/com/google/inject/Injector.java
index 42c7331..d2ac498 100644
--- a/core/src/com/google/inject/Injector.java
+++ b/core/src/com/google/inject/Injector.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
 package com.google.inject;
 
 import com.google.inject.spi.TypeConverterBinding;
-
 import java.lang.annotation.Annotation;
 import java.util.List;
 import java.util.Map;
@@ -64,9 +63,8 @@
    * you, you'll never need to use this method.
    *
    * @param instance to inject members on
-   *
    * @see Binder#getMembersInjector(Class) for a preferred alternative that supports checks before
-   *  run time
+   *     run time
    */
   void injectMembers(Object instance);
 
@@ -76,7 +74,7 @@
    *
    * @param typeLiteral type to get members injector for
    * @see Binder#getMembersInjector(TypeLiteral) for an alternative that offers up front error
-   *  detection
+   *     detection
    * @since 2.0
    */
   <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral);
@@ -87,8 +85,7 @@
    * instead to get increased up front error detection.
    *
    * @param type type to get members injector for
-   * @see Binder#getMembersInjector(Class) for an alternative that offers up front error
-   *  detection
+   * @see Binder#getMembersInjector(Class) for an alternative that offers up front error detection
    * @since 2.0
    */
   <T> MembersInjector<T> getMembersInjector(Class<T> type);
@@ -97,9 +94,9 @@
    * Returns this injector's <strong>explicit</strong> bindings.
    *
    * <p>The returned map does not include bindings inherited from a {@link #getParent() parent
-   * injector}, should one exist. The returned map is guaranteed to iterate (for example, with
-   * its {@link Map#entrySet()} iterator) in the order of insertion. In other words, the order in
-   * which bindings appear in user Modules.
+   * injector}, should one exist. The returned map is guaranteed to iterate (for example, with its
+   * {@link Map#entrySet()} iterator) in the order of insertion. In other words, the order in which
+   * bindings appear in user Modules.
    *
    * <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
    */
@@ -108,14 +105,15 @@
   /**
    * Returns a snapshot of this injector's bindings, <strong>both explicit and
    * just-in-time</strong>. The returned map is immutable; it contains only the bindings that were
-   * present when {@code getAllBindings()} was invoked. Subsequent calls may return a map with
-   * additional just-in-time bindings.
+   * present when {@code getAllBindings()} was invoked. Just-in-time bindings are only present if
+   * they have been requested at least once. Subsequent calls may return a map with additional
+   * just-in-time bindings.
    *
    * <p>The returned map does not include bindings inherited from a {@link #getParent() parent
    * injector}, should one exist.
    *
    * <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
-   * 
+   *
    * @since 3.0
    */
   Map<Key<?>, Binding<?>> getAllBindings();
@@ -142,17 +140,17 @@
    * @since 2.0
    */
   <T> Binding<T> getBinding(Class<T> type);
-  
+
   /**
-   * Returns the binding if it already exists, or null if does not exist. Unlike
-   * {@link #getBinding(Key)}, this does not attempt to create just-in-time bindings
-   * for keys that aren't bound.
-   * 
-   * <p> This method is part of the Guice SPI and is intended for use by tools and extensions.
-   * 
+   * Returns the binding if it already exists, or null if does not exist. Unlike {@link
+   * #getBinding(Key)}, this does not attempt to create just-in-time bindings for keys that aren't
+   * bound.
+   *
+   * <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
+   *
    * @since 3.0
    */
-  <T> Binding<T> getExistingBinding(Key<T> key);  
+  <T> Binding<T> getExistingBinding(Key<T> key);
 
   /**
    * Returns all explicit bindings for {@code type}.
@@ -171,8 +169,8 @@
   <T> Provider<T> getProvider(Key<T> key);
 
   /**
-   * Returns the provider used to obtain instances for the given type. When feasible, avoid
-   * using this method, in favor of having Guice inject your dependencies ahead of time.
+   * Returns the provider used to obtain instances for the given type. When feasible, avoid using
+   * this method, in favor of having Guice inject your dependencies ahead of time.
    *
    * @throws ConfigurationException if this injector cannot find or create the provider.
    * @see Binder#getProvider(Class) for an alternative that offers up front error detection
@@ -213,9 +211,9 @@
    *
    * <p>Just-in-time bindings created for child injectors will be created in an ancestor injector
    * whenever possible. This allows for scoped instances to be shared between injectors. Use
-   * explicit bindings to prevent bindings from being shared with the parent injector.  Optional
-   * injections in just-in-time bindings (created in the parent injector) may be silently
-   * ignored if the optional dependencies are from the child injector.
+   * explicit bindings to prevent bindings from being shared with the parent injector. Optional
+   * injections in just-in-time bindings (created in the parent injector) may be silently ignored if
+   * the optional dependencies are from the child injector.
    *
    * <p>No key may be bound by both an injector and one of its ancestors. This includes just-in-time
    * bindings. The lone exception is the key for {@code Injector.class}, which is bound by each
@@ -243,12 +241,12 @@
   Injector createChildInjector(Module... modules);
 
   /**
-   * Returns a map containing all scopes in the injector. The maps keys are scoping annotations
-   * like {@code Singleton.class}, and the values are scope instances, such as {@code
-   * Scopes.SINGLETON}. The returned map is immutable.
+   * Returns a map containing all scopes in the injector. The maps keys are scoping annotations like
+   * {@code Singleton.class}, and the values are scope instances, such as {@code Scopes.SINGLETON}.
+   * The returned map is immutable.
    *
    * <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
-   * 
+   *
    * @since 3.0
    */
   Map<Class<? extends Annotation>, Scope> getScopeBindings();
@@ -258,7 +256,7 @@
    * immutable.
    *
    * <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
-   * 
+   *
    * @since 3.0
    */
   Set<TypeConverterBinding> getTypeConverterBindings();
diff --git a/core/src/com/google/inject/Key.java b/core/src/com/google/inject/Key.java
index c93dabf..55779f3 100644
--- a/core/src/com/google/inject/Key.java
+++ b/core/src/com/google/inject/Key.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,20 +21,16 @@
 import static com.google.inject.internal.Annotations.generateAnnotation;
 import static com.google.inject.internal.Annotations.isAllDefaultMethods;
 
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
 import com.google.inject.internal.Annotations;
 import com.google.inject.internal.MoreTypes;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 
 /**
- * Binding key consisting of an injection type and an optional annotation.
- * Matches the type and annotation at a point of injection.
+ * Binding key consisting of an injection type and an optional annotation. Matches the type and
+ * annotation at a point of injection.
  *
- * <p>For example, {@code Key.get(Service.class, Transactional.class)} will
- * match:
+ * <p>For example, {@code Key.get(Service.class, Transactional.class)} will match:
  *
  * <pre>
  *   {@literal @}Inject
@@ -43,12 +39,11 @@
  *   }
  * </pre>
  *
- * <p>{@code Key} supports generic types via subclassing just like {@link
- * TypeLiteral}.
+ * <p>{@code Key} supports generic types via subclassing just like {@link TypeLiteral}.
  *
- * <p>Keys do not differentiate between primitive types (int, char, etc.) and
- * their corresponding wrapper types (Integer, Character, etc.). Primitive
- * types will be replaced with their wrapper types when keys are created.
+ * <p>Keys do not differentiate between primitive types (int, char, etc.) and their corresponding
+ * wrapper types (Integer, Character, etc.). Primitive types will be replaced with their wrapper
+ * types when keys are created.
  *
  * @author crazybob@google.com (Bob Lee)
  */
@@ -58,38 +53,37 @@
 
   private final TypeLiteral<T> typeLiteral;
   private final int hashCode;
-  private final Supplier<String> toStringSupplier;
+  // This field is updated using the 'Data-Race-Ful' lazy intialization pattern
+  // See http://jeremymanson.blogspot.com/2008/12/benign-data-races-in-java.html for a detailed
+  // explanation.
+  private String toString;
 
   /**
    * Constructs a new key. Derives the type from this class's type parameter.
    *
-   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
-   * parameter in the anonymous class's type hierarchy so we can reconstitute it
-   * at runtime despite erasure.
+   * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
+   * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
    *
-   * <p>Example usage for a binding of type {@code Foo} annotated with
-   * {@code @Bar}:
+   * <p>Example usage for a binding of type {@code Foo} annotated with {@code @Bar}:
    *
    * <p>{@code new Key<Foo>(Bar.class) {}}.
    */
   @SuppressWarnings("unchecked")
   protected Key(Class<? extends Annotation> annotationType) {
     this.annotationStrategy = strategyFor(annotationType);
-    this.typeLiteral = MoreTypes.canonicalizeForKey(
-        (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
+    this.typeLiteral =
+        MoreTypes.canonicalizeForKey(
+            (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
     this.hashCode = computeHashCode();
-    this.toStringSupplier = createToStringSupplier();
   }
 
   /**
    * Constructs a new key. Derives the type from this class's type parameter.
    *
-   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
-   * parameter in the anonymous class's type hierarchy so we can reconstitute it
-   * at runtime despite erasure.
+   * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
+   * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
    *
-   * <p>Example usage for a binding of type {@code Foo} annotated with
-   * {@code @Bar}:
+   * <p>Example usage for a binding of type {@code Foo} annotated with {@code @Bar}:
    *
    * <p>{@code new Key<Foo>(new Bar()) {}}.
    */
@@ -97,18 +91,17 @@
   protected Key(Annotation annotation) {
     // no usages, not test-covered
     this.annotationStrategy = strategyFor(annotation);
-    this.typeLiteral = MoreTypes.canonicalizeForKey(
-        (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
+    this.typeLiteral =
+        MoreTypes.canonicalizeForKey(
+            (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
     this.hashCode = computeHashCode();
-    this.toStringSupplier = createToStringSupplier();
   }
 
   /**
    * Constructs a new key. Derives the type from this class's type parameter.
    *
-   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
-   * parameter in the anonymous class's type hierarchy so we can reconstitute it
-   * at runtime despite erasure.
+   * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
+   * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
    *
    * <p>Example usage for a binding of type {@code Foo}:
    *
@@ -117,21 +110,18 @@
   @SuppressWarnings("unchecked")
   protected Key() {
     this.annotationStrategy = NullAnnotationStrategy.INSTANCE;
-    this.typeLiteral = MoreTypes.canonicalizeForKey(
-        (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
+    this.typeLiteral =
+        MoreTypes.canonicalizeForKey(
+            (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
     this.hashCode = computeHashCode();
-    this.toStringSupplier = createToStringSupplier();
   }
 
-  /**
-   * Unsafe. Constructs a key from a manually specified type.
-   */
+  /** Unsafe. Constructs a key from a manually specified type. */
   @SuppressWarnings("unchecked")
   private Key(Type type, AnnotationStrategy annotationStrategy) {
     this.annotationStrategy = annotationStrategy;
     this.typeLiteral = MoreTypes.canonicalizeForKey((TypeLiteral<T>) TypeLiteral.get(type));
     this.hashCode = computeHashCode();
-    this.toStringSupplier = createToStringSupplier();
   }
 
   /** Constructs a key from a manually specified type. */
@@ -139,46 +129,24 @@
     this.annotationStrategy = annotationStrategy;
     this.typeLiteral = MoreTypes.canonicalizeForKey(typeLiteral);
     this.hashCode = computeHashCode();
-    this.toStringSupplier = createToStringSupplier();
   }
 
-  /**
-   * Computes the hash code for this key.
-   */
+  /** Computes the hash code for this key. */
   private int computeHashCode() {
     return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode();
   }
 
-  /**
-   * @return a {@link Supplier} which memoizes the value for lazy initialization.
-   */
-  private Supplier<String> createToStringSupplier() {
-    // The performance hit on access is acceptable since the intended use is for non-performance-
-    // critical applications such as debugging and logging.
-    return Suppliers.memoize(new Supplier<String>() {
-      @Override public String get() {
-        return "Key[type=" + typeLiteral + ", annotation=" + annotationStrategy + "]";
-      }
-    });
-  }
-  
-  /**
-   * Gets the key type.
-   */
+  /** Gets the key type. */
   public final TypeLiteral<T> getTypeLiteral() {
     return typeLiteral;
   }
 
-  /**
-   * Gets the annotation type.
-   */
+  /** Gets the annotation type. */
   public final Class<? extends Annotation> getAnnotationType() {
     return annotationStrategy.getAnnotationType();
   }
 
-  /**
-   * Gets the annotation.
-   */
+  /** Gets the annotation. */
   public final Annotation getAnnotation() {
     return annotationStrategy.getAnnotation();
   }
@@ -201,14 +169,13 @@
     return typeLiteral.getRawType();
   }
 
-  /**
-   * Gets the key of this key's provider.
-   */
+  /** Gets the key of this key's provider. */
   Key<Provider<T>> providerKey() {
     return ofType(typeLiteral.providerType());
   }
 
-  @Override public final boolean equals(Object o) {
+  @Override
+  public final boolean equals(Object o) {
     if (o == this) {
       return true;
     }
@@ -220,92 +187,76 @@
         && typeLiteral.equals(other.typeLiteral);
   }
 
-  @Override public final int hashCode() {
+  @Override
+  public final int hashCode() {
     return this.hashCode;
   }
 
-  @Override public final String toString() {
-    return toStringSupplier.get();
+  @Override
+  public final String toString() {
+    // Note: to not introduce dangerous data races the field should only be read once in this
+    // method.
+    String local = toString;
+    if (local == null) {
+      local = "Key[type=" + typeLiteral + ", annotation=" + annotationStrategy + "]";
+      toString = local;
+    }
+    return local;
   }
 
-  /**
-   * Gets a key for an injection type and an annotation strategy.
-   */
-  static <T> Key<T> get(Class<T> type,
-      AnnotationStrategy annotationStrategy) {
+  /** Gets a key for an injection type and an annotation strategy. */
+  static <T> Key<T> get(Class<T> type, AnnotationStrategy annotationStrategy) {
     return new Key<T>(type, annotationStrategy);
   }
 
-  /**
-   * Gets a key for an injection type.
-   */
+  /** Gets a key for an injection type. */
   public static <T> Key<T> get(Class<T> type) {
     return new Key<T>(type, NullAnnotationStrategy.INSTANCE);
   }
 
-  /**
-   * Gets a key for an injection type and an annotation type.
-   */
-  public static <T> Key<T> get(Class<T> type,
-      Class<? extends Annotation> annotationType) {
+  /** Gets a key for an injection type and an annotation type. */
+  public static <T> Key<T> get(Class<T> type, Class<? extends Annotation> annotationType) {
     return new Key<T>(type, strategyFor(annotationType));
   }
 
-  /**
-   * Gets a key for an injection type and an annotation.
-   */
+  /** Gets a key for an injection type and an annotation. */
   public static <T> Key<T> get(Class<T> type, Annotation annotation) {
     return new Key<T>(type, strategyFor(annotation));
   }
 
-  /**
-   * Gets a key for an injection type.
-   */
+  /** Gets a key for an injection type. */
   public static Key<?> get(Type type) {
     return new Key<Object>(type, NullAnnotationStrategy.INSTANCE);
   }
 
-  /**
-   * Gets a key for an injection type and an annotation type.
-   */
-  public static Key<?> get(Type type,
-      Class<? extends Annotation> annotationType) {
+  /** Gets a key for an injection type and an annotation type. */
+  public static Key<?> get(Type type, Class<? extends Annotation> annotationType) {
     return new Key<Object>(type, strategyFor(annotationType));
   }
 
-  /**
-   * Gets a key for an injection type and an annotation.
-   */
+  /** Gets a key for an injection type and an annotation. */
   public static Key<?> get(Type type, Annotation annotation) {
     return new Key<Object>(type, strategyFor(annotation));
   }
 
-  /**
-   * Gets a key for an injection type.
-   */
+  /** Gets a key for an injection type. */
   public static <T> Key<T> get(TypeLiteral<T> typeLiteral) {
     return new Key<T>(typeLiteral, NullAnnotationStrategy.INSTANCE);
   }
 
-  /**
-   * Gets a key for an injection type and an annotation type.
-   */
-  public static <T> Key<T> get(TypeLiteral<T> typeLiteral,
-      Class<? extends Annotation> annotationType) {
+  /** Gets a key for an injection type and an annotation type. */
+  public static <T> Key<T> get(
+      TypeLiteral<T> typeLiteral, Class<? extends Annotation> annotationType) {
     return new Key<T>(typeLiteral, strategyFor(annotationType));
   }
 
-  /**
-   * Gets a key for an injection type and an annotation.
-   */
-  public static <T> Key<T> get(TypeLiteral<T> typeLiteral,
-      Annotation annotation) {
+  /** Gets a key for an injection type and an annotation. */
+  public static <T> Key<T> get(TypeLiteral<T> typeLiteral, Annotation annotation) {
     return new Key<T>(typeLiteral, strategyFor(annotation));
   }
 
   /**
-   * Returns a new key of the specified type with the same annotation as this
-   * key.
+   * Returns a new key of the specified type with the same annotation as this key.
    *
    * @since 3.0
    */
@@ -314,8 +265,7 @@
   }
 
   /**
-   * Returns a new key of the specified type with the same annotation as this
-   * key.
+   * Returns a new key of the specified type with the same annotation as this key.
    *
    * @since 3.0
    */
@@ -324,8 +274,7 @@
   }
 
   /**
-   * Returns a new key of the specified type with the same annotation as this
-   * key.
+   * Returns a new key of the specified type with the same annotation as this key.
    *
    * @since 3.0
    */
@@ -343,8 +292,7 @@
   }
 
   /**
-   * Returns this key without annotation attributes, i.e. with only the
-   * annotation type.
+   * Returns this key without annotation attributes, i.e. with only the annotation type.
    *
    * @since 3.0
    */
@@ -354,14 +302,15 @@
 
   interface AnnotationStrategy {
     Annotation getAnnotation();
+
     Class<? extends Annotation> getAnnotationType();
+
     boolean hasAttributes();
+
     AnnotationStrategy withoutAttributes();
   }
 
-  /**
-   * Gets the strategy for an annotation.
-   */
+  /** Gets the strategy for an annotation. */
   static AnnotationStrategy strategyFor(Annotation annotation) {
     checkNotNull(annotation, "annotation");
     Class<? extends Annotation> annotationType = annotation.annotationType();
@@ -375,9 +324,7 @@
     return new AnnotationInstanceStrategy(Annotations.canonicalizeIfNamed(annotation));
   }
 
-  /**
-   * Gets the strategy for an annotation type.
-   */
+  /** Gets the strategy for an annotation type. */
   static AnnotationStrategy strategyFor(Class<? extends Annotation> annotationType) {
     annotationType = Annotations.canonicalizeIfNamed(annotationType);
     if (isAllDefaultMethods(annotationType)) {
@@ -388,18 +335,18 @@
     ensureRetainedAtRuntime(annotationType);
     ensureIsBindingAnnotation(annotationType);
     return new AnnotationTypeStrategy(annotationType, null);
-
   }
 
-  private static void ensureRetainedAtRuntime(
-      Class<? extends Annotation> annotationType) {
-    checkArgument(Annotations.isRetainedAtRuntime(annotationType),
+  private static void ensureRetainedAtRuntime(Class<? extends Annotation> annotationType) {
+    checkArgument(
+        Annotations.isRetainedAtRuntime(annotationType),
         "%s is not retained at runtime. Please annotate it with @Retention(RUNTIME).",
         annotationType.getName());
   }
 
   private static void ensureIsBindingAnnotation(Class<? extends Annotation> annotationType) {
-    checkArgument(Annotations.isBindingAnnotation(annotationType),
+    checkArgument(
+        Annotations.isBindingAnnotation(annotationType),
         "%s is not a binding annotation. Please annotate it with @BindingAnnotation.",
         annotationType.getName());
   }
@@ -407,23 +354,28 @@
   static enum NullAnnotationStrategy implements AnnotationStrategy {
     INSTANCE;
 
+    @Override
     public boolean hasAttributes() {
       return false;
     }
 
+    @Override
     public AnnotationStrategy withoutAttributes() {
       throw new UnsupportedOperationException("Key already has no attributes.");
     }
 
+    @Override
     public Annotation getAnnotation() {
       return null;
     }
 
+    @Override
     public Class<? extends Annotation> getAnnotationType() {
       return null;
     }
 
-    @Override public String toString() {
+    @Override
+    public String toString() {
       return "[none]";
     }
   }
@@ -437,23 +389,28 @@
       this.annotation = checkNotNull(annotation, "annotation");
     }
 
+    @Override
     public boolean hasAttributes() {
       return true;
     }
 
+    @Override
     public AnnotationStrategy withoutAttributes() {
       return new AnnotationTypeStrategy(getAnnotationType(), annotation);
     }
 
+    @Override
     public Annotation getAnnotation() {
       return annotation;
     }
 
+    @Override
     public Class<? extends Annotation> getAnnotationType() {
       return annotation.annotationType();
     }
 
-    @Override public boolean equals(Object o) {
+    @Override
+    public boolean equals(Object o) {
       if (!(o instanceof AnnotationInstanceStrategy)) {
         return false;
       }
@@ -462,11 +419,13 @@
       return annotation.equals(other.annotation);
     }
 
-    @Override public int hashCode() {
+    @Override
+    public int hashCode() {
       return annotation.hashCode();
     }
 
-    @Override public String toString() {
+    @Override
+    public String toString() {
       return annotation.toString();
     }
   }
@@ -478,29 +437,33 @@
     // Keep the instance around if we have it so the client can request it.
     final Annotation annotation;
 
-    AnnotationTypeStrategy(Class<? extends Annotation> annotationType,
-        Annotation annotation) {
+    AnnotationTypeStrategy(Class<? extends Annotation> annotationType, Annotation annotation) {
       this.annotationType = checkNotNull(annotationType, "annotation type");
       this.annotation = annotation;
     }
 
+    @Override
     public boolean hasAttributes() {
       return false;
     }
 
+    @Override
     public AnnotationStrategy withoutAttributes() {
       throw new UnsupportedOperationException("Key already has no attributes.");
     }
 
+    @Override
     public Annotation getAnnotation() {
       return annotation;
     }
 
+    @Override
     public Class<? extends Annotation> getAnnotationType() {
       return annotationType;
     }
 
-    @Override public boolean equals(Object o) {
+    @Override
+    public boolean equals(Object o) {
       if (!(o instanceof AnnotationTypeStrategy)) {
         return false;
       }
@@ -509,11 +472,13 @@
       return annotationType.equals(other.annotationType);
     }
 
-    @Override public int hashCode() {
+    @Override
+    public int hashCode() {
       return annotationType.hashCode();
     }
 
-    @Override public String toString() {
+    @Override
+    public String toString() {
       return "@" + annotationType.getName();
     }
   }
diff --git a/core/src/com/google/inject/MembersInjector.java b/core/src/com/google/inject/MembersInjector.java
index b50dedb..349eb0d 100644
--- a/core/src/com/google/inject/MembersInjector.java
+++ b/core/src/com/google/inject/MembersInjector.java
@@ -21,7 +21,6 @@
  * presence or absence of an injectable constructor.
  *
  * @param <T> type to inject members of
- *
  * @author crazybob@google.com (Bob Lee)
  * @author jessewilson@google.com (Jesse Wilson)
  * @since 2.0
diff --git a/core/src/com/google/inject/Module.java b/core/src/com/google/inject/Module.java
index f22d93f..52cdd30 100644
--- a/core/src/com/google/inject/Module.java
+++ b/core/src/com/google/inject/Module.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,16 @@
 package com.google.inject;
 
 /**
- * A module contributes configuration information, typically interface
- * bindings, which will be used to create an {@link Injector}. A Guice-based
- * application is ultimately composed of little more than a set of
- * {@code Module}s and some bootstrapping code.
+ * A module contributes configuration information, typically interface bindings, which will be used
+ * to create an {@link Injector}. A Guice-based application is ultimately composed of little more
+ * than a set of {@code Module}s and some bootstrapping code.
  *
- * <p>Your Module classes can use a more streamlined syntax by extending
- * {@link AbstractModule} rather than implementing this interface directly.
+ * <p>Your Module classes can use a more streamlined syntax by extending {@link AbstractModule}
+ * rather than implementing this interface directly.
  *
- * <p>In addition to the bindings configured via {@link #configure}, bindings
- * will be created for all methods annotated with {@literal @}{@link Provides}.
- * Use scope and binding annotations on these methods to configure the
- * bindings.
+ * <p>In addition to the bindings configured via {@link #configure}, bindings will be created for
+ * all methods annotated with {@literal @}{@link Provides}. Use scope and binding annotations on
+ * these methods to configure the bindings.
  */
 public interface Module {
 
diff --git a/core/src/com/google/inject/OutOfScopeException.java b/core/src/com/google/inject/OutOfScopeException.java
index 430fa23..7199b6b 100644
--- a/core/src/com/google/inject/OutOfScopeException.java
+++ b/core/src/com/google/inject/OutOfScopeException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 package com.google.inject;
 
 /**
- * Thrown from {@link Provider#get} when an attempt is made to access a scoped
- * object while the scope in question is not currently active.
+ * Thrown from {@link Provider#get} when an attempt is made to access a scoped object while the
+ * scope in question is not currently active.
  *
  * @author kevinb@google.com (Kevin Bourrillion)
  * @since 2.0
diff --git a/core/src/com/google/inject/PrivateBinder.java b/core/src/com/google/inject/PrivateBinder.java
index 21a833f..9e7fcd3 100644
--- a/core/src/com/google/inject/PrivateBinder.java
+++ b/core/src/com/google/inject/PrivateBinder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,7 +21,7 @@
 /**
  * Returns a binder whose configuration information is hidden from its environment by default. See
  * {@link com.google.inject.PrivateModule PrivateModule} for details.
- * 
+ *
  * @author jessewilson@google.com (Jesse Wilson)
  * @since 2.0
  */
@@ -32,8 +32,8 @@
 
   /**
    * Makes a binding for {@code type} available to the enclosing environment. Use {@link
-   * com.google.inject.binder.AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type} with a
-   * binding annotation.
+   * com.google.inject.binder.AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to
+   * expose {@code type} with a binding annotation.
    */
   AnnotatedElementBuilder expose(Class<?> type);
 
@@ -44,7 +44,9 @@
    */
   AnnotatedElementBuilder expose(TypeLiteral<?> type);
 
+  @Override
   PrivateBinder withSource(Object source);
 
+  @Override
   PrivateBinder skipSources(Class... classesToSkip);
 }
diff --git a/core/src/com/google/inject/PrivateModule.java b/core/src/com/google/inject/PrivateModule.java
index ba2f722..e43e1f9 100644
--- a/core/src/com/google/inject/PrivateModule.java
+++ b/core/src/com/google/inject/PrivateModule.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,6 @@
 import com.google.inject.spi.ProvisionListener;
 import com.google.inject.spi.TypeConverter;
 import com.google.inject.spi.TypeListener;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 
@@ -37,14 +36,14 @@
  * This module may expose the bindings it creates and the bindings of the modules it installs.
  *
  * <p>A private module can be nested within a regular module or within another private module using
- * {@link Binder#install install()}.  Its bindings live in a new environment that inherits bindings,
- * type converters, scopes, and interceptors from the surrounding ("parent") environment.  When you
+ * {@link Binder#install install()}. Its bindings live in a new environment that inherits bindings,
+ * type converters, scopes, and interceptors from the surrounding ("parent") environment. When you
  * nest multiple private modules, the result is a tree of environments where the injector's
  * environment is the root.
  *
  * <p>Guice EDSL bindings can be exposed with {@link #expose(Class) expose()}. {@literal @}{@link
- * com.google.inject.Provides Provides} bindings can be exposed with the {@literal @}{@link
- * Exposed} annotation:
+ * com.google.inject.Provides Provides} bindings can be exposed with the {@literal @}{@link Exposed}
+ * annotation:
  *
  * <pre>
  * public class FooBarBazModule extends PrivateModule {
@@ -69,7 +68,7 @@
  * <p>Private modules are implemented using {@link Injector#createChildInjector(Module[]) parent
  * injectors}. When it can satisfy their dependencies, just-in-time bindings will be created in the
  * root environment. Such bindings are shared among all environments in the tree.
- * 
+ *
  * <p>The scope of a binding is constrained to its environment. A singleton bound in a private
  * module will be unique to its environment. But a binding for the same type in a different private
  * module will yield a different instance.
@@ -79,6 +78,7 @@
  * gets access to all bindings in the child environment.
  *
  * <p>To promote a just-in-time binding to an explicit binding, bind it:
+ *
  * <pre>
  *   bind(FooImpl.class);
  * </pre>
@@ -91,6 +91,7 @@
   /** Like abstract module, the binder of the current private module */
   private PrivateBinder binder;
 
+  @Override
   public final synchronized void configure(Binder binder) {
     checkState(this.binder == null, "Re-entry is not allowed.");
 
@@ -134,155 +135,120 @@
 
   // everything below is copied from AbstractModule
 
-  /**
-   * Returns the current binder.
-   */
+  /** Returns the current binder. */
   protected final PrivateBinder binder() {
     checkState(binder != null, "The binder can only be used inside configure()");
     return binder;
   }
 
-  /**
-   * @see Binder#bindScope(Class, Scope)
-   */
+  /** @see Binder#bindScope(Class, Scope) */
   protected final void bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) {
     binder().bindScope(scopeAnnotation, scope);
   }
 
-  /**
-   * @see Binder#bind(Key)
-   */
+  /** @see Binder#bind(Key) */
   protected final <T> LinkedBindingBuilder<T> bind(Key<T> key) {
     return binder().bind(key);
   }
 
-  /**
-   * @see Binder#bind(TypeLiteral)
-   */
+  /** @see Binder#bind(TypeLiteral) */
   protected final <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
     return binder().bind(typeLiteral);
   }
 
-  /**
-   * @see Binder#bind(Class)  
-   */
+  /** @see Binder#bind(Class) */
   protected final <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
     return binder().bind(clazz);
   }
 
-  /**
-   * @see Binder#bindConstant()
-   */
+  /** @see Binder#bindConstant() */
   protected final AnnotatedConstantBindingBuilder bindConstant() {
     return binder().bindConstant();
   }
 
-  /**
-   * @see Binder#install(Module)
-   */
+  /** @see Binder#install(Module) */
   protected final void install(Module module) {
     binder().install(module);
   }
 
-  /**
-   * @see Binder#addError(String, Object[])
-   */
+  /** @see Binder#addError(String, Object[]) */
   protected final void addError(String message, Object... arguments) {
     binder().addError(message, arguments);
   }
 
-  /**
-   * @see Binder#addError(Throwable)
-   */
+  /** @see Binder#addError(Throwable) */
   protected final void addError(Throwable t) {
     binder().addError(t);
   }
 
-  /**
-   * @see Binder#addError(Message)
-   */
+  /** @see Binder#addError(Message) */
   protected final void addError(Message message) {
     binder().addError(message);
   }
 
-  /**
-   * @see Binder#requestInjection(Object)
-   */
+  /** @see Binder#requestInjection(Object) */
   protected final void requestInjection(Object instance) {
     binder().requestInjection(instance);
   }
 
-  /**
-   * @see Binder#requestStaticInjection(Class[])
-   */
+  /** @see Binder#requestStaticInjection(Class[]) */
   protected final void requestStaticInjection(Class<?>... types) {
     binder().requestStaticInjection(types);
   }
 
   /*if[AOP]*/
   /**
-   * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher, com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
+   * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher,
+   *     com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
    */
-  protected final void bindInterceptor(Matcher<? super Class<?>> classMatcher,
+  protected final void bindInterceptor(
+      Matcher<? super Class<?>> classMatcher,
       Matcher<? super Method> methodMatcher,
       org.aopalliance.intercept.MethodInterceptor... interceptors) {
     binder().bindInterceptor(classMatcher, methodMatcher, interceptors);
   }
   /*end[AOP]*/
 
-  /**
-   * Instructs Guice to require a binding to the given key.
-   */
+  /** Instructs Guice to require a binding to the given key. */
   protected final void requireBinding(Key<?> key) {
     binder().getProvider(key);
   }
 
-  /**
-   * Instructs Guice to require a binding to the given type.
-   */
+  /** Instructs Guice to require a binding to the given type. */
   protected final void requireBinding(Class<?> type) {
     binder().getProvider(type);
   }
 
-  /**
-   * @see Binder#getProvider(Key)
-   */
+  /** @see Binder#getProvider(Key) */
   protected final <T> Provider<T> getProvider(Key<T> key) {
     return binder().getProvider(key);
   }
-  
-  /**
-   * @see Binder#getProvider(Class)
-   */
+
+  /** @see Binder#getProvider(Class) */
   protected final <T> Provider<T> getProvider(Class<T> type) {
     return binder().getProvider(type);
   }
 
   /**
-   * @see Binder#convertToTypes(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeConverter)
+   * @see Binder#convertToTypes(com.google.inject.matcher.Matcher,
+   *     com.google.inject.spi.TypeConverter)
    */
-  protected final void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
-      TypeConverter converter) {
+  protected final void convertToTypes(
+      Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) {
     binder().convertToTypes(typeMatcher, converter);
   }
 
-  /**
-   * @see Binder#currentStage()
-   */
+  /** @see Binder#currentStage() */
   protected final Stage currentStage() {
     return binder().currentStage();
   }
 
-  /**
-   * @see Binder#getMembersInjector(Class)
-   */
+  /** @see Binder#getMembersInjector(Class) */
   protected <T> MembersInjector<T> getMembersInjector(Class<T> type) {
     return binder().getMembersInjector(type);
   }
 
-  /**
-   * @see Binder#getMembersInjector(TypeLiteral)
-   */
+  /** @see Binder#getMembersInjector(TypeLiteral) */
   protected <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
     return binder().getMembersInjector(type);
   }
@@ -290,17 +256,16 @@
   /**
    * @see Binder#bindListener(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeListener)
    */
-  protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
-      TypeListener listener) {
+  protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) {
     binder().bindListener(typeMatcher, listener);
   }
-  
+
   /**
    * @see Binder#bindListener(Matcher, ProvisionListener...)
    * @since 4.0
    */
-  protected void bindListener(Matcher<? super Binding<?>> bindingMatcher,
-      ProvisionListener... listeners) {
+  protected void bindListener(
+      Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners) {
     binder().bindListener(bindingMatcher, listeners);
   }
 }
diff --git a/core/src/com/google/inject/ProvidedBy.java b/core/src/com/google/inject/ProvidedBy.java
index 7ad12f7..bb92431 100644
--- a/core/src/com/google/inject/ProvidedBy.java
+++ b/core/src/com/google/inject/ProvidedBy.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,8 +31,6 @@
 @Target(TYPE)
 public @interface ProvidedBy {
 
-  /**
-   * The implementation type.
-   */
-  Class<? extends Provider<?>> value();
+  /** The implementation type. */
+  Class<? extends javax.inject.Provider<?>> value();
 }
diff --git a/core/src/com/google/inject/Provider.java b/core/src/com/google/inject/Provider.java
index 3295a2b..4ce1e31 100644
--- a/core/src/com/google/inject/Provider.java
+++ b/core/src/com/google/inject/Provider.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,35 +22,32 @@
  *
  * <ul>
  * <li>When the default means for obtaining instances (an injectable or parameterless constructor)
- * is insufficient for a particular binding, the module can specify a custom {@code Provider}
- * instead, to control exactly how Guice creates or obtains instances for the binding.
- *
+ *     is insufficient for a particular binding, the module can specify a custom {@code Provider}
+ *     instead, to control exactly how Guice creates or obtains instances for the binding.
  * <li>An implementation class may always choose to have a {@code Provider<T>} instance injected,
- * rather than having a {@code T} injected directly.  This may give you access to multiple
- * instances, instances you wish to safely mutate and discard, instances which are out of scope
- * (e.g. using a {@code @RequestScoped} object from within a {@code @SessionScoped} object), or
- * instances that will be initialized lazily.
- *
+ *     rather than having a {@code T} injected directly. This may give you access to multiple
+ *     instances, instances you wish to safely mutate and discard, instances which are out of scope
+ *     (e.g. using a {@code @RequestScoped} object from within a {@code @SessionScoped} object), or
+ *     instances that will be initialized lazily.
  * <li>A custom {@link Scope} is implemented as a decorator of {@code Provider<T>}, which decides
- * when to delegate to the backing provider and when to provide the instance some other way.
- *
- * <li>The {@link Injector} offers access to the {@code Provider<T>} it uses to fulfill requests
- * for a given key, via the {@link Injector#getProvider} methods.
+ *     when to delegate to the backing provider and when to provide the instance some other way.
+ * <li>The {@link Injector} offers access to the {@code Provider<T>} it uses to fulfill requests for
+ *     a given key, via the {@link Injector#getProvider} methods.
  * </ul>
  *
  * @param <T> the type of object this provides
- *
  * @author crazybob@google.com (Bob Lee)
  */
 public interface Provider<T> extends javax.inject.Provider<T> {
 
   /**
-   * Provides an instance of {@code T}. Must never return {@code null}.
+   * Provides an instance of {@code T}.
    *
    * @throws OutOfScopeException when an attempt is made to access a scoped object while the scope
    *     in question is not currently active
    * @throws ProvisionException if an instance cannot be provided. Such exceptions include messages
    *     and throwables to describe why provision failed.
    */
+  @Override
   T get();
 }
diff --git a/core/src/com/google/inject/Provides.java b/core/src/com/google/inject/Provides.java
index c66a428..ba8f72b 100644
--- a/core/src/com/google/inject/Provides.java
+++ b/core/src/com/google/inject/Provides.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,5 +30,7 @@
  * @author crazybob@google.com (Bob Lee)
  * @since 2.0
  */
-@Documented @Target(METHOD) @Retention(RUNTIME)
+@Documented
+@Target(METHOD)
+@Retention(RUNTIME)
 public @interface Provides {}
diff --git a/core/src/com/google/inject/ProvisionException.java b/core/src/com/google/inject/ProvisionException.java
index 3c590b9..0c132c5 100644
--- a/core/src/com/google/inject/ProvisionException.java
+++ b/core/src/com/google/inject/ProvisionException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,14 +19,14 @@
 import static com.google.common.base.Preconditions.checkArgument;
 
 import com.google.common.collect.ImmutableSet;
-import com.google.inject.internal.Errors;
+import com.google.inject.internal.Messages;
 import com.google.inject.spi.Message;
-
 import java.util.Collection;
 
 /**
  * Indicates that there was a runtime failure while providing an instance.
  *
+ *
  * @author kevinb@google.com (Kevin Bourrillion)
  * @author jessewilson@google.com (Jesse Wilson)
  * @since 2.0
@@ -39,7 +39,7 @@
   public ProvisionException(Iterable<Message> messages) {
     this.messages = ImmutableSet.copyOf(messages);
     checkArgument(!this.messages.isEmpty());
-    initCause(Errors.getOnlyCause(this.messages));
+    initCause(Messages.getOnlyCause(this.messages));
   }
 
   public ProvisionException(String message, Throwable cause) {
@@ -56,8 +56,9 @@
     return messages;
   }
 
-  @Override public String getMessage() {
-    return Errors.format("Unable to provision, see the following errors", messages);
+  @Override
+  public String getMessage() {
+    return Messages.formatMessages("Unable to provision, see the following errors", messages);
   }
 
   private static final long serialVersionUID = 0;
diff --git a/core/src/com/google/inject/Scope.java b/core/src/com/google/inject/Scope.java
index 949270c..331d9c3 100644
--- a/core/src/com/google/inject/Scope.java
+++ b/core/src/com/google/inject/Scope.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,13 +17,11 @@
 package com.google.inject;
 
 /**
- * A scope is a level of visibility that instances provided by Guice may have.
- * By default, an instance created by the {@link Injector} has <i>no scope</i>,
- * meaning it has no state from the framework's perspective -- the
- * {@code Injector} creates it, injects it once into the class that required it,
- * and then immediately forgets it. Associating a scope with a particular
- * binding allows the created instance to be "remembered" and possibly used
- * again for other injections.
+ * A scope is a level of visibility that instances provided by Guice may have. By default, an
+ * instance created by the {@link Injector} has <i>no scope</i>, meaning it has no state from the
+ * framework's perspective -- the {@code Injector} creates it, injects it once into the class that
+ * required it, and then immediately forgets it. Associating a scope with a particular binding
+ * allows the created instance to be "remembered" and possibly used again for other injections.
  *
  * <p>An example of a scope is {@link Scopes#SINGLETON}.
  *
@@ -32,28 +30,24 @@
 public interface Scope {
 
   /**
-   * Scopes a provider. The returned provider returns objects from this scope.
-   * If an object does not exist in this scope, the provider can use the given
-   * unscoped provider to retrieve one.
+   * Scopes a provider. The returned provider returns objects from this scope. If an object does not
+   * exist in this scope, the provider can use the given unscoped provider to retrieve one.
    *
-   * <p>Scope implementations are strongly encouraged to override
-   * {@link Object#toString} in the returned provider and include the backing
-   * provider's {@code toString()} output.
+   * <p>Scope implementations are strongly encouraged to override {@link Object#toString} in the
+   * returned provider and include the backing provider's {@code toString()} output.
    *
    * @param key binding key
-   * @param unscoped locates an instance when one doesn't already exist in this
-   *  scope.
-   * @return a new provider which only delegates to the given unscoped provider
-   *  when an instance of the requested object doesn't already exist in this
-   *  scope
+   * @param unscoped locates an instance when one doesn't already exist in this scope.
+   * @return a new provider which only delegates to the given unscoped provider when an instance of
+   *     the requested object doesn't already exist in this scope
    */
   public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped);
 
   /**
-   * A short but useful description of this scope.  For comparison, the standard
-   * scopes that ship with guice use the descriptions
-   * {@code "Scopes.SINGLETON"}, {@code "ServletScopes.SESSION"} and
+   * A short but useful description of this scope. For comparison, the standard scopes that ship
+   * with guice use the descriptions {@code "Scopes.SINGLETON"}, {@code "ServletScopes.SESSION"} and
    * {@code "ServletScopes.REQUEST"}.
    */
+  @Override
   String toString();
 }
diff --git a/core/src/com/google/inject/ScopeAnnotation.java b/core/src/com/google/inject/ScopeAnnotation.java
index 8f869a0..c0b651a 100644
--- a/core/src/com/google/inject/ScopeAnnotation.java
+++ b/core/src/com/google/inject/ScopeAnnotation.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,9 +23,9 @@
 import java.lang.annotation.Target;
 
 /**
- * Annotates annotations which are used for scoping. Only one such annotation
- * may apply to a single implementation class. You must also annotate scope
- * annotations with {@code @Retention(RUNTIME)}. For example:
+ * Annotates annotations which are used for scoping. Only one such annotation may apply to a single
+ * implementation class. You must also annotate scope annotations with {@code @Retention(RUNTIME)}.
+ * For example:
  *
  * <pre>
  *   {@code @}Retention(RUNTIME)
diff --git a/core/src/com/google/inject/Scopes.java b/core/src/com/google/inject/Scopes.java
index 6c893e5..20be102 100644
--- a/core/src/com/google/inject/Scopes.java
+++ b/core/src/com/google/inject/Scopes.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,7 +21,6 @@
 import com.google.inject.internal.SingletonScope;
 import com.google.inject.spi.BindingScopingVisitor;
 import com.google.inject.spi.ExposedBinding;
-
 import java.lang.annotation.Annotation;
 
 /**
@@ -33,47 +32,51 @@
 
   private Scopes() {}
 
-  /**
-   * One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
-   */
+  /** One instance per {@link Injector}. Also see {@code @}{@link Singleton}. */
   public static final Scope SINGLETON = new SingletonScope();
 
   /**
-   * No scope; the same as not applying any scope at all.  Each time the
-   * Injector obtains an instance of an object with "no scope", it injects this
-   * instance then immediately forgets it.  When the next request for the same
-   * binding arrives it will need to obtain the instance over again.
+   * No scope; the same as not applying any scope at all. Each time the Injector obtains an instance
+   * of an object with "no scope", it injects this instance then immediately forgets it. When the
+   * next request for the same binding arrives it will need to obtain the instance over again.
    *
-   * <p>This exists only in case a class has been annotated with a scope
-   * annotation such as {@link Singleton @Singleton}, and you need to override
-   * this to "no scope" in your binding.
+   * <p>This exists only in case a class has been annotated with a scope annotation such as {@link
+   * Singleton @Singleton}, and you need to override this to "no scope" in your binding.
    *
    * @since 2.0
    */
-  public static final Scope NO_SCOPE = new Scope() {
-    public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
-      return unscoped;
-    }
-    @Override public String toString() {
-      return "Scopes.NO_SCOPE";
-    }
-  };
+  public static final Scope NO_SCOPE =
+      new Scope() {
+        @Override
+        public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
+          return unscoped;
+        }
 
-  private static final BindingScopingVisitor<Boolean> IS_SINGLETON_VISITOR
-      = new BindingScopingVisitor<Boolean>() {
+        @Override
+        public String toString() {
+          return "Scopes.NO_SCOPE";
+        }
+      };
+
+  private static final BindingScopingVisitor<Boolean> IS_SINGLETON_VISITOR =
+      new BindingScopingVisitor<Boolean>() {
+        @Override
         public Boolean visitNoScoping() {
           return false;
         }
 
+        @Override
         public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
           return scopeAnnotation == Singleton.class
               || scopeAnnotation == javax.inject.Singleton.class;
         }
 
+        @Override
         public Boolean visitScope(Scope scope) {
           return scope == Scopes.SINGLETON;
         }
 
+        @Override
         public Boolean visitEagerSingleton() {
           return true;
         }
@@ -101,8 +104,8 @@
           binding = injector.getBinding(linkedBinding.getLinkedKey());
           continue;
         }
-      } else if(binding instanceof ExposedBinding) {
-        ExposedBinding<?> exposedBinding = (ExposedBinding)binding;
+      } else if (binding instanceof ExposedBinding) {
+        ExposedBinding<?> exposedBinding = (ExposedBinding) binding;
         Injector injector = exposedBinding.getPrivateElements().getInjector();
         if (injector != null) {
           binding = injector.getBinding(exposedBinding.getKey());
@@ -115,7 +118,6 @@
   }
 
   /**
-
    * Returns true if {@code binding} has the given scope. If the binding is a {@link
    * com.google.inject.spi.LinkedKeyBinding linked key binding} and belongs to an injector (ie. it
    * was retrieved via {@link Injector#getBinding Injector.getBinding()}), then this method will
@@ -126,26 +128,32 @@
    * @param scopeAnnotation scope annotation class
    * @since 4.0
    */
-  public static boolean isScoped(Binding<?> binding, final Scope scope,
-      final Class<? extends Annotation> scopeAnnotation) {
+  public static boolean isScoped(
+      Binding<?> binding, final Scope scope, final Class<? extends Annotation> scopeAnnotation) {
     do {
-      boolean matches = binding.acceptScopingVisitor(new BindingScopingVisitor<Boolean>() {
-        public Boolean visitNoScoping() {
-          return false;
-        }
+      boolean matches =
+          binding.acceptScopingVisitor(
+              new BindingScopingVisitor<Boolean>() {
+                @Override
+                public Boolean visitNoScoping() {
+                  return false;
+                }
 
-        public Boolean visitScopeAnnotation(Class<? extends Annotation> visitedAnnotation) {
-          return visitedAnnotation == scopeAnnotation;
-        }
+                @Override
+                public Boolean visitScopeAnnotation(Class<? extends Annotation> visitedAnnotation) {
+                  return visitedAnnotation == scopeAnnotation;
+                }
 
-        public Boolean visitScope(Scope visitedScope) {
-          return visitedScope == scope;
-        }
+                @Override
+                public Boolean visitScope(Scope visitedScope) {
+                  return visitedScope == scope;
+                }
 
-        public Boolean visitEagerSingleton() {
-          return false;
-        }
-      });
+                @Override
+                public Boolean visitEagerSingleton() {
+                  return false;
+                }
+              });
 
       if (matches) {
         return true;
@@ -158,8 +166,8 @@
           binding = injector.getBinding(linkedBinding.getLinkedKey());
           continue;
         }
-      } else if(binding instanceof ExposedBinding) {
-        ExposedBinding<?> exposedBinding = (ExposedBinding)binding;
+      } else if (binding instanceof ExposedBinding) {
+        ExposedBinding<?> exposedBinding = (ExposedBinding) binding;
         Injector injector = exposedBinding.getPrivateElements().getInjector();
         if (injector != null) {
           binding = injector.getBinding(exposedBinding.getKey());
@@ -172,12 +180,11 @@
   }
 
   /**
-   * Returns true if the object is a proxy for a circular dependency,
-   * constructed by Guice because it encountered a circular dependency. Scope
-   * implementations should be careful to <b>not cache circular proxies</b>,
-   * because the proxies are not intended for general purpose use. (They are
-   * designed just to fulfill the immediate injection, not all injections.
-   * Caching them can lead to IllegalArgumentExceptions or ClassCastExceptions.)
+   * Returns true if the object is a proxy for a circular dependency, constructed by Guice because
+   * it encountered a circular dependency. Scope implementations should be careful to <b>not cache
+   * circular proxies</b>, because the proxies are not intended for general purpose use. (They are
+   * designed just to fulfill the immediate injection, not all injections. Caching them can lead to
+   * IllegalArgumentExceptions or ClassCastExceptions.)
    *
    * @since 4.0
    */
diff --git a/core/src/com/google/inject/Singleton.java b/core/src/com/google/inject/Singleton.java
index 0ea9a14..59a2b44 100644
--- a/core/src/com/google/inject/Singleton.java
+++ b/core/src/com/google/inject/Singleton.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,12 +23,12 @@
 import java.lang.annotation.Target;
 
 /**
- * Apply this to implementation classes when you want only one instance
- * (per {@link Injector}) to be reused for all injections for that binding.
+ * Apply this to implementation classes when you want only one instance (per {@link Injector}) to be
+ * reused for all injections for that binding.
  *
  * @author crazybob@google.com (Bob Lee)
  */
-@Target({ ElementType.TYPE, ElementType.METHOD })
+@Target({ElementType.TYPE, ElementType.METHOD})
 @Retention(RUNTIME)
 @ScopeAnnotation
 public @interface Singleton {}
diff --git a/core/src/com/google/inject/Stage.java b/core/src/com/google/inject/Stage.java
index f9b4e35..19f256e 100644
--- a/core/src/com/google/inject/Stage.java
+++ b/core/src/com/google/inject/Stage.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,8 +26,8 @@
   /**
    * We're running in a tool (an IDE plugin for example). We need binding meta data but not a
    * functioning Injector. Do not inject members of instances. Do not load eager singletons. Do as
-   * little as possible so our tools run nice and snappy. Injectors created in this stage cannot
-   * be used to satisfy injections.
+   * little as possible so our tools run nice and snappy. Injectors created in this stage cannot be
+   * used to satisfy injections.
    */
   TOOL,
 
@@ -37,8 +37,6 @@
    */
   DEVELOPMENT,
 
-  /**
-   * We want to catch errors as early as possible and take performance hits up front.
-   */
+  /** We want to catch errors as early as possible and take performance hits up front. */
   PRODUCTION
 }
diff --git a/core/src/com/google/inject/TypeLiteral.java b/core/src/com/google/inject/TypeLiteral.java
index d18087d..0f928da 100644
--- a/core/src/com/google/inject/TypeLiteral.java
+++ b/core/src/com/google/inject/TypeLiteral.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.inject.internal.MoreTypes;
 import com.google.inject.util.Types;
-
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.GenericArrayType;
@@ -36,26 +35,25 @@
 import java.util.List;
 
 /**
- * Represents a generic type {@code T}. Java doesn't yet provide a way to
- * represent generic types, so this class does. Forces clients to create a
- * subclass of this class which enables retrieval the type information even at
- * runtime.
+ * Represents a generic type {@code T}. Java doesn't yet provide a way to represent generic types,
+ * so this class does. Forces clients to create a subclass of this class which enables retrieval of
+ * the type information even at runtime.
  *
- * <p>For example, to create a type literal for {@code List<String>}, you can
- * create an empty anonymous inner class:
+ * <p>For example, to create a type literal for {@code List<String>}, you can create an empty
+ * anonymous inner class:
  *
- * <p>
- * {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};}
+ * <p>{@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};}
  *
- * <p>Along with modeling generic types, this class can resolve type parameters.
- * For example, to figure out what type {@code keySet()} returns on a {@code
- * Map<Integer, String>}, use this code:<pre>   {@code
+ * <p>Along with modeling generic types, this class can resolve type parameters. For example, to
+ * figure out what type {@code keySet()} returns on a {@code Map<Integer, String>}, use this code:
  *
- *   TypeLiteral<Map<Integer, String>> mapType
- *       = new TypeLiteral<Map<Integer, String>>() {};
- *   TypeLiteral<?> keySetType
- *       = mapType.getReturnType(Map.class.getMethod("keySet"));
- *   System.out.println(keySetType); // prints "Set<Integer>"}</pre>
+ * <pre>{@code
+ * TypeLiteral<Map<Integer, String>> mapType
+ *     = new TypeLiteral<Map<Integer, String>>() {};
+ * TypeLiteral<?> keySetType
+ *     = mapType.getReturnType(Map.class.getMethod("keySet"));
+ * System.out.println(keySetType); // prints "Set<Integer>"
+ * }</pre>
  *
  * @author crazybob@google.com (Bob Lee)
  * @author jessewilson@google.com (Jesse Wilson)
@@ -67,12 +65,10 @@
   final int hashCode;
 
   /**
-   * Constructs a new type literal. Derives represented class from type
-   * parameter.
+   * Constructs a new type literal. Derives represented class from type parameter.
    *
-   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
-   * parameter in the anonymous class's type hierarchy so we can reconstitute it
-   * at runtime despite erasure.
+   * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
+   * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
    */
   @SuppressWarnings("unchecked")
   protected TypeLiteral() {
@@ -81,9 +77,7 @@
     this.hashCode = type.hashCode();
   }
 
-  /**
-   * Unsafe. Constructs a type literal manually.
-   */
+  /** Unsafe. Constructs a type literal manually. */
   @SuppressWarnings("unchecked")
   TypeLiteral(Type type) {
     this.type = canonicalize(checkNotNull(type, "type"));
@@ -104,32 +98,26 @@
     return canonicalize(parameterized.getActualTypeArguments()[0]);
   }
 
-  /**
-   * Gets type literal from super class's type parameter.
-   */
+  /** Gets type literal from super class's type parameter. */
   static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) {
     return new TypeLiteral<Object>(getSuperclassTypeParameter(subclass));
   }
 
   /**
    * Returns the raw (non-generic) type for this type.
-   * 
+   *
    * @since 2.0
    */
   public final Class<? super T> getRawType() {
     return rawType;
   }
 
-  /**
-   * Gets underlying {@code Type} instance.
-   */
+  /** Gets underlying {@code Type} instance. */
   public final Type getType() {
     return type;
   }
 
-  /**
-   * Gets the type of this type's provider.
-   */
+  /** Gets the type of this type's provider. */
   @SuppressWarnings("unchecked")
   final TypeLiteral<Provider<T>> providerType() {
     // This cast is safe and wouldn't generate a warning if Type had a type
@@ -137,34 +125,31 @@
     return (TypeLiteral<Provider<T>>) get(Types.providerOf(getType()));
   }
 
-  @Override public final int hashCode() {
+  @Override
+  public final int hashCode() {
     return this.hashCode;
   }
 
-  @Override public final boolean equals(Object o) {
-    return o instanceof TypeLiteral<?>
-        && MoreTypes.equals(type, ((TypeLiteral) o).type);
+  @Override
+  public final boolean equals(Object o) {
+    return o instanceof TypeLiteral<?> && MoreTypes.equals(type, ((TypeLiteral) o).type);
   }
 
-  @Override public final String toString() {
+  @Override
+  public final String toString() {
     return MoreTypes.typeToString(type);
   }
 
-  /**
-   * Gets type literal for the given {@code Type} instance.
-   */
+  /** Gets type literal for the given {@code Type} instance. */
   public static TypeLiteral<?> get(Type type) {
     return new TypeLiteral<Object>(type);
   }
 
-  /**
-   * Gets type literal for the given {@code Class} instance.
-   */
+  /** Gets type literal for the given {@code Class} instance. */
   public static <T> TypeLiteral<T> get(Class<T> type) {
     return new TypeLiteral<T>(type);
   }
 
-
   /** Returns an immutable list of the resolved types. */
   private List<TypeLiteral<?>> resolveAll(Type[] types) {
     TypeLiteral<?>[] result = new TypeLiteral<?>[types.length];
@@ -174,9 +159,7 @@
     return ImmutableList.copyOf(result);
   }
 
-  /**
-   * Resolves known type parameters in {@code toResolve} and returns the result.
-   */
+  /** Resolves known type parameters in {@code toResolve} and returns the result. */
   TypeLiteral<?> resolve(Type toResolve) {
     return TypeLiteral.get(resolveType(toResolve));
   }
@@ -195,9 +178,7 @@
         GenericArrayType original = (GenericArrayType) toResolve;
         Type componentType = original.getGenericComponentType();
         Type newComponentType = resolveType(componentType);
-        return componentType == newComponentType
-            ? original
-            : Types.arrayOf(newComponentType);
+        return componentType == newComponentType ? original : Types.arrayOf(newComponentType);
 
       } else if (toResolve instanceof ParameterizedType) {
         ParameterizedType original = (ParameterizedType) toResolve;
@@ -254,8 +235,8 @@
    * @since 2.0
    */
   public TypeLiteral<?> getSupertype(Class<?> supertype) {
-    checkArgument(supertype.isAssignableFrom(rawType),
-        "%s is not a supertype of %s", supertype, this.type);
+    checkArgument(
+        supertype.isAssignableFrom(rawType), "%s is not a supertype of %s", supertype, this.type);
     return resolve(MoreTypes.getGenericSupertype(type, rawType, supertype));
   }
 
@@ -266,8 +247,11 @@
    * @since 2.0
    */
   public TypeLiteral<?> getFieldType(Field field) {
-    checkArgument(field.getDeclaringClass().isAssignableFrom(rawType),
-        "%s is not defined by a supertype of %s", field, type);
+    checkArgument(
+        field.getDeclaringClass().isAssignableFrom(rawType),
+        "%s is not defined by a supertype of %s",
+        field,
+        type);
     return resolve(field.getGenericType());
   }
 
@@ -282,14 +266,20 @@
 
     if (methodOrConstructor instanceof Method) {
       Method method = (Method) methodOrConstructor;
-      checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
-          "%s is not defined by a supertype of %s", method, type);
+      checkArgument(
+          method.getDeclaringClass().isAssignableFrom(rawType),
+          "%s is not defined by a supertype of %s",
+          method,
+          type);
       genericParameterTypes = method.getGenericParameterTypes();
 
     } else if (methodOrConstructor instanceof Constructor) {
       Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
-      checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType),
-          "%s does not construct a supertype of %s", constructor, type);
+      checkArgument(
+          constructor.getDeclaringClass().isAssignableFrom(rawType),
+          "%s does not construct a supertype of %s",
+          constructor,
+          type);
       genericParameterTypes = constructor.getGenericParameterTypes();
 
     } else {
@@ -310,14 +300,20 @@
 
     if (methodOrConstructor instanceof Method) {
       Method method = (Method) methodOrConstructor;
-      checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
-          "%s is not defined by a supertype of %s", method, type);
+      checkArgument(
+          method.getDeclaringClass().isAssignableFrom(rawType),
+          "%s is not defined by a supertype of %s",
+          method,
+          type);
       genericExceptionTypes = method.getGenericExceptionTypes();
 
     } else if (methodOrConstructor instanceof Constructor) {
       Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
-      checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType),
-          "%s does not construct a supertype of %s", constructor, type);
+      checkArgument(
+          constructor.getDeclaringClass().isAssignableFrom(rawType),
+          "%s does not construct a supertype of %s",
+          constructor,
+          type);
       genericExceptionTypes = constructor.getGenericExceptionTypes();
 
     } else {
@@ -334,8 +330,11 @@
    * @since 2.0
    */
   public TypeLiteral<?> getReturnType(Method method) {
-    checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
-        "%s is not defined by a supertype of %s", method, type);
+    checkArgument(
+        method.getDeclaringClass().isAssignableFrom(rawType),
+        "%s is not defined by a supertype of %s",
+        method,
+        type);
     return resolve(method.getGenericReturnType());
   }
 }
diff --git a/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java b/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java
index 5b430c3..62ac3d4 100644
--- a/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java
+++ b/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,14 +25,9 @@
  */
 public interface AnnotatedBindingBuilder<T> extends LinkedBindingBuilder<T> {
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
-  LinkedBindingBuilder<T> annotatedWith(
-      Class<? extends Annotation> annotationType);
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
+  LinkedBindingBuilder<T> annotatedWith(Class<? extends Annotation> annotationType);
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
   LinkedBindingBuilder<T> annotatedWith(Annotation annotation);
 }
diff --git a/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java b/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java
index 417027f..fa57d78 100644
--- a/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java
+++ b/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,14 +25,9 @@
  */
 public interface AnnotatedConstantBindingBuilder {
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
-  ConstantBindingBuilder annotatedWith(
-      Class<? extends Annotation> annotationType);
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
+  ConstantBindingBuilder annotatedWith(Class<? extends Annotation> annotationType);
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
   ConstantBindingBuilder annotatedWith(Annotation annotation);
 }
diff --git a/core/src/com/google/inject/binder/AnnotatedElementBuilder.java b/core/src/com/google/inject/binder/AnnotatedElementBuilder.java
index f6feddf..04b2281 100644
--- a/core/src/com/google/inject/binder/AnnotatedElementBuilder.java
+++ b/core/src/com/google/inject/binder/AnnotatedElementBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,13 +26,9 @@
  */
 public interface AnnotatedElementBuilder {
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
   void annotatedWith(Class<? extends Annotation> annotationType);
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
   void annotatedWith(Annotation annotation);
 }
diff --git a/core/src/com/google/inject/binder/ConstantBindingBuilder.java b/core/src/com/google/inject/binder/ConstantBindingBuilder.java
index 7ddbcf9..cf1274b 100644
--- a/core/src/com/google/inject/binder/ConstantBindingBuilder.java
+++ b/core/src/com/google/inject/binder/ConstantBindingBuilder.java
@@ -16,65 +16,43 @@
 
 package com.google.inject.binder;
 
-/**
- * Binds to a constant value.
- */
+/** Binds to a constant value. */
 public interface ConstantBindingBuilder {
 
-  /**
-   * Binds constant to the given value.
-   */
+  /** Binds constant to the given value. */
   void to(String value);
 
-  /**
-   * Binds constant to the given value.
-   */
+  /** Binds constant to the given value. */
   void to(int value);
 
-  /**
-   * Binds constant to the given value.
-   */
+  /** Binds constant to the given value. */
   void to(long value);
 
-  /**
-   * Binds constant to the given value.
-   */
+  /** Binds constant to the given value. */
   void to(boolean value);
 
-  /**
-   * Binds constant to the given value.
-   */
+  /** Binds constant to the given value. */
   void to(double value);
 
-  /**
-   * Binds constant to the given value.
-   */
+  /** Binds constant to the given value. */
   void to(float value);
 
-  /**
-   * Binds constant to the given value.
-   */
+  /** Binds constant to the given value. */
   void to(short value);
 
-  /**
-   * Binds constant to the given value.
-   */
+  /** Binds constant to the given value. */
   void to(char value);
 
   /**
    * Binds constant to the given value.
-   * 
+   *
    * @since 3.0
    */
   void to(byte value);
 
-  /**
-   * Binds constant to the given value.
-   */
+  /** Binds constant to the given value. */
   void to(Class<?> value);
 
-  /**
-   * Binds constant to the given value.
-   */
+  /** Binds constant to the given value. */
   <E extends Enum<E>> void to(E value);
 }
diff --git a/core/src/com/google/inject/binder/LinkedBindingBuilder.java b/core/src/com/google/inject/binder/LinkedBindingBuilder.java
index 99ea185..219e145 100644
--- a/core/src/com/google/inject/binder/LinkedBindingBuilder.java
+++ b/core/src/com/google/inject/binder/LinkedBindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,6 @@
 import com.google.inject.Key;
 import com.google.inject.Provider;
 import com.google.inject.TypeLiteral;
-
 import java.lang.reflect.Constructor;
 
 /**
@@ -29,19 +28,13 @@
  */
 public interface LinkedBindingBuilder<T> extends ScopedBindingBuilder {
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
   ScopedBindingBuilder to(Class<? extends T> implementation);
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
   ScopedBindingBuilder to(TypeLiteral<? extends T> implementation);
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
   ScopedBindingBuilder to(Key<? extends T> targetKey);
 
   /**
@@ -57,7 +50,7 @@
    * @see com.google.inject.Injector#injectMembers
    */
   ScopedBindingBuilder toProvider(Provider<? extends T> provider);
-  
+
   /**
    * See the EDSL examples at {@link com.google.inject.Binder}.
    *
@@ -66,34 +59,26 @@
    */
   ScopedBindingBuilder toProvider(javax.inject.Provider<? extends T> provider);
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
-  ScopedBindingBuilder toProvider(
-      Class<? extends javax.inject.Provider<? extends T>> providerType);
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
+  ScopedBindingBuilder toProvider(Class<? extends javax.inject.Provider<? extends T>> providerType);
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
   ScopedBindingBuilder toProvider(
       TypeLiteral<? extends javax.inject.Provider<? extends T>> providerType);
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
-  ScopedBindingBuilder toProvider(
-      Key<? extends javax.inject.Provider<? extends T>> providerKey);
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
+  ScopedBindingBuilder toProvider(Key<? extends javax.inject.Provider<? extends T>> providerKey);
 
   /**
    * See the EDSL examples at {@link com.google.inject.Binder}.
-   * 
+   *
    * @since 3.0
    */
   <S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor);
 
   /**
    * See the EDSL examples at {@link com.google.inject.Binder}.
-   * 
+   *
    * @since 3.0
    */
   <S extends T> ScopedBindingBuilder toConstructor(
diff --git a/core/src/com/google/inject/binder/ScopedBindingBuilder.java b/core/src/com/google/inject/binder/ScopedBindingBuilder.java
index ceb8497..e907362 100644
--- a/core/src/com/google/inject/binder/ScopedBindingBuilder.java
+++ b/core/src/com/google/inject/binder/ScopedBindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
 package com.google.inject.binder;
 
 import com.google.inject.Scope;
-
 import java.lang.annotation.Annotation;
 
 /**
@@ -27,20 +26,15 @@
  */
 public interface ScopedBindingBuilder {
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
   void in(Class<? extends Annotation> scopeAnnotation);
 
-  /**
-   * See the EDSL examples at {@link com.google.inject.Binder}.
-   */
+  /** See the EDSL examples at {@link com.google.inject.Binder}. */
   void in(Scope scope);
 
   /**
-   * Instructs the {@link com.google.inject.Injector} to eagerly initialize this
-   * singleton-scoped binding upon creation. Useful for application
-   * initialization logic.  See the EDSL examples at
+   * Instructs the {@link com.google.inject.Injector} to eagerly initialize this singleton-scoped
+   * binding upon creation. Useful for application initialization logic. See the EDSL examples at
    * {@link com.google.inject.Binder}.
    */
   void asEagerSingleton();
diff --git a/core/src/com/google/inject/binder/package-info.java b/core/src/com/google/inject/binder/package-info.java
index 57ed875..14e701f 100644
--- a/core/src/com/google/inject/binder/package-info.java
+++ b/core/src/com/google/inject/binder/package-info.java
@@ -14,8 +14,5 @@
  * limitations under the License.
  */
 
-/**
- * Interfaces which make up {@link com.google.inject.Binder}'s
- * expression language.
- */
-package com.google.inject.binder;
\ No newline at end of file
+/** Interfaces which make up {@link com.google.inject.Binder}'s expression language. */
+package com.google.inject.binder;
diff --git a/core/src/com/google/inject/internal/AbstractBindingBuilder.java b/core/src/com/google/inject/internal/AbstractBindingBuilder.java
index e803b75..6eb07e7 100644
--- a/core/src/com/google/inject/internal/AbstractBindingBuilder.java
+++ b/core/src/com/google/inject/internal/AbstractBindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@
 import com.google.inject.Scope;
 import com.google.inject.spi.Element;
 import com.google.inject.spi.InstanceBinding;
-
 import java.lang.annotation.Annotation;
 import java.util.List;
 
@@ -35,14 +34,15 @@
 public abstract class AbstractBindingBuilder<T> {
 
   public static final String IMPLEMENTATION_ALREADY_SET = "Implementation is set more than once.";
-  public static final String SINGLE_INSTANCE_AND_SCOPE
-      = "Setting the scope is not permitted when binding to a single instance.";
+  public static final String SINGLE_INSTANCE_AND_SCOPE =
+      "Setting the scope is not permitted when binding to a single instance.";
   public static final String SCOPE_ALREADY_SET = "Scope is set more than once.";
-  public static final String BINDING_TO_NULL = "Binding to null instances is not allowed. "
-      + "Use toProvider(Providers.of(null)) if this is your intended behaviour.";
+  public static final String BINDING_TO_NULL =
+      "Binding to null instances is not allowed. "
+          + "Use toProvider(Providers.of(null)) if this is your intended behaviour.";
   public static final String CONSTANT_VALUE_ALREADY_SET = "Constant value is set more than once.";
-  public static final String ANNOTATION_ALREADY_SPECIFIED
-      = "More than one annotation is specified for this binding.";
+  public static final String ANNOTATION_ALREADY_SPECIFIED =
+      "More than one annotation is specified for this binding.";
 
   protected static final Key<?> NULL_KEY = Key.get(Void.class);
 
@@ -55,7 +55,7 @@
     this.binder = binder;
     this.elements = elements;
     this.position = elements.size();
-    this.binding = new UntargettedBindingImpl<T>(source, key, Scoping.UNSCOPED);
+    this.binding = new UntargettedBindingImpl<>(source, key, Scoping.UNSCOPED);
     elements.add(position, this.binding);
   }
 
@@ -73,16 +73,15 @@
   protected BindingImpl<T> annotatedWithInternal(Class<? extends Annotation> annotationType) {
     checkNotNull(annotationType, "annotationType");
     checkNotAnnotated();
-    return setBinding(binding.withKey(
-        Key.get(this.binding.getKey().getTypeLiteral(), annotationType)));
+    return setBinding(
+        binding.withKey(Key.get(this.binding.getKey().getTypeLiteral(), annotationType)));
   }
 
   /** Sets the binding to a copy with the specified annotation on the bound key */
   protected BindingImpl<T> annotatedWithInternal(Annotation annotation) {
     checkNotNull(annotation, "annotation");
     checkNotAnnotated();
-    return setBinding(binding.withKey(
-        Key.get(this.binding.getKey().getTypeLiteral(), annotation)));
+    return setBinding(binding.withKey(Key.get(this.binding.getKey().getTypeLiteral(), annotation)));
   }
 
   public void in(final Class<? extends Annotation> scopeAnnotation) {
@@ -129,4 +128,4 @@
       binder.addError(SCOPE_ALREADY_SET);
     }
   }
-}
\ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/AbstractBindingProcessor.java b/core/src/com/google/inject/internal/AbstractBindingProcessor.java
index e1a0bba..5d2640d 100644
--- a/core/src/com/google/inject/internal/AbstractBindingProcessor.java
+++ b/core/src/com/google/inject/internal/AbstractBindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,11 +30,9 @@
 import com.google.inject.TypeLiteral;
 import com.google.inject.spi.DefaultBindingTargetVisitor;
 
-import java.util.Set;
-
 /**
  * Guarantees that processing of Binding elements happens in a sane way.
- * 
+ *
  * @author sameb@google.com (Sam Berlin)
  */
 abstract class AbstractBindingProcessor extends AbstractProcessor {
@@ -42,21 +40,22 @@
   // It's unfortunate that we have to maintain a blacklist of specific
   // classes, but we can't easily block the whole package because of
   // all our unit tests.
-  private static final Set<Class<?>> FORBIDDEN_TYPES = ImmutableSet.<Class<?>>of(
-      AbstractModule.class,
-      Binder.class,
-      Binding.class,
-      Injector.class,
-      Key.class,
-      MembersInjector.class,
-      Module.class,
-      Provider.class,
-      Scope.class,
-      Stage.class,
-      TypeLiteral.class);
-  
+  private static final ImmutableSet<Class<?>> FORBIDDEN_TYPES =
+      ImmutableSet.<Class<?>>of(
+          AbstractModule.class,
+          Binder.class,
+          Binding.class,
+          Injector.class,
+          Key.class,
+          MembersInjector.class,
+          Module.class,
+          Provider.class,
+          Scope.class,
+          Stage.class,
+          TypeLiteral.class);
+
   protected final ProcessedBindingData bindingData;
-  
+
   AbstractBindingProcessor(Errors errors, ProcessedBindingData bindingData) {
     super(errors);
     this.bindingData = bindingData;
@@ -66,7 +65,7 @@
       InjectorImpl injector, Key<T> key, Object source) {
     return new UntargettedBindingImpl<T>(injector, key, source);
   }
-  
+
   protected void putBinding(BindingImpl<?> binding) {
     Key<?> key = binding.getKey();
 
@@ -81,11 +80,11 @@
       // If it failed because of an explicit duplicate binding...
       if (injector.state.getExplicitBinding(key) != null) {
         try {
-          if(!isOkayDuplicate(original, binding, injector.state)) {
+          if (!isOkayDuplicate(original, binding, injector.state)) {
             errors.bindingAlreadySet(key, original.getSource());
             return;
           }
-        } catch(Throwable t) {
+        } catch (Throwable t) {
           errors.errorCheckingDuplicateBinding(key, original.getSource(), t);
           return;
         }
@@ -103,8 +102,8 @@
   }
 
   /**
-   * We tolerate duplicate bindings if one exposes the other or if the two bindings
-   * are considered duplicates (see {@link Bindings#areDuplicates(BindingImpl, BindingImpl)}.
+   * We tolerate duplicate bindings if one exposes the other or if the two bindings are considered
+   * duplicates (see {@link Bindings#areDuplicates(BindingImpl, BindingImpl)}.
    *
    * @param original the binding in the parent injector (candidate for an exposing binding)
    * @param binding the binding to check (candidate for the exposed binding)
@@ -115,46 +114,63 @@
       InjectorImpl exposedFrom = (InjectorImpl) exposed.getPrivateElements().getInjector();
       return (exposedFrom == binding.getInjector());
     } else {
-      original = (BindingImpl<?>)state.getExplicitBindingsThisLevel().get(binding.getKey());
+      original = (BindingImpl<?>) state.getExplicitBindingsThisLevel().get(binding.getKey());
       // If no original at this level, the original was on a parent, and we don't
       // allow deduplication between parents & children.
-      if(original == null) {
+      if (original == null) {
         return false;
       } else {
         return original.equals(binding);
       }
     }
   }
-  
+
   private <T> void validateKey(Object source, Key<T> key) {
     Annotations.checkForMisplacedScopeAnnotations(
         key.getTypeLiteral().getRawType(), source, errors);
   }
-  
-  /** 
-   * Processor for visiting bindings.  Each overriden method that wants to
-   * actually process the binding should call prepareBinding first.
+
+  /**
+   * Processor for visiting bindings. Each overriden method that wants to actually process the
+   * binding should call prepareBinding first.
    */
   abstract class Processor<T, V> extends DefaultBindingTargetVisitor<T, V> {
     final Object source;
     final Key<T> key;
     final Class<? super T> rawType;
     Scoping scoping;
-    
+
     Processor(BindingImpl<T> binding) {
       source = binding.getSource();
       key = binding.getKey();
       rawType = key.getTypeLiteral().getRawType();
       scoping = binding.getScoping();
     }
-    
-    protected void prepareBinding() {      
+
+    protected void prepareBinding() {
       validateKey(source, key);
       scoping = Scoping.makeInjectable(scoping, injector, errors);
     }
 
-    protected void scheduleInitialization(final BindingImpl<?> binding) {
-      bindingData.addUninitializedBinding(new Runnable() {
+    /**
+     * Schedule initialization of this binding to occur immediately after all bindings have been
+     * initialially processed.
+     */
+    protected void scheduleInitialization(BindingImpl<?> binding) {
+      bindingData.addUninitializedBinding(asRunnable(binding));
+    }
+
+    /**
+     * Schedule initialization for this binding to occur after all other static initialization of
+     * bindings.
+     */
+    protected void scheduleDelayedInitialization(BindingImpl<?> binding) {
+      bindingData.addDelayedUninitializedBinding(asRunnable(binding));
+    }
+
+    private Runnable asRunnable(final BindingImpl<?> binding) {
+      return new Runnable() {
+        @Override
         public void run() {
           try {
             binding.getInjector().initializeBinding(binding, errors.withSource(source));
@@ -162,7 +178,7 @@
             errors.merge(e.getErrors());
           }
         }
-      });
+      };
     }
   }
 }
diff --git a/core/src/com/google/inject/internal/AbstractProcessor.java b/core/src/com/google/inject/internal/AbstractProcessor.java
index 2697a99..6132dd3 100644
--- a/core/src/com/google/inject/internal/AbstractProcessor.java
+++ b/core/src/com/google/inject/internal/AbstractProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,16 +18,14 @@
 
 import com.google.inject.spi.DefaultElementVisitor;
 import com.google.inject.spi.Element;
-
 import java.util.Iterator;
 import java.util.List;
 
 /**
  * Abstract base class for creating an injector from module elements.
  *
- * <p>Extending classes must return {@code true} from any overridden
- * {@code visit*()} methods, in order for the element processor to remove the
- * handled element.
+ * <p>Extending classes must return {@code true} from any overridden {@code visit*()} methods, in
+ * order for the element processor to remove the handled element.
  *
  * @author jessewilson@google.com (Jesse Wilson)
  */
@@ -63,7 +61,7 @@
       this.injector = null;
     }
   }
-  
+
   @Override
   protected Boolean visitOther(Element element) {
     return false;
diff --git a/core/src/com/google/inject/internal/Annotations.java b/core/src/com/google/inject/internal/Annotations.java
index 4c994a9..c815973 100644
--- a/core/src/com/google/inject/internal/Annotations.java
+++ b/core/src/com/google/inject/internal/Annotations.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,8 @@
 
 package com.google.inject.internal;
 
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
 import com.google.common.base.Joiner.MapJoiner;
@@ -32,7 +34,6 @@
 import com.google.inject.internal.util.Classes;
 import com.google.inject.name.Named;
 import com.google.inject.name.Names;
-
 import java.lang.annotation.Annotation;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -43,7 +44,6 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Map;
-
 import javax.inject.Qualifier;
 
 /**
@@ -53,9 +53,7 @@
  */
 public class Annotations {
 
-  /**
-   * Returns {@code true} if the given annotation type has no attributes.
-   */
+  /** Returns {@code true} if the given annotation type has no attributes. */
   public static boolean isMarker(Class<? extends Annotation> annotationType) {
     return annotationType.getDeclaredMethods().length == 0;
   }
@@ -72,13 +70,15 @@
   }
 
   private static final LoadingCache<Class<? extends Annotation>, Annotation> cache =
-      CacheBuilder.newBuilder().weakKeys().build(
-          new CacheLoader<Class<? extends Annotation>, Annotation>() {
-            @Override
-            public Annotation load(Class<? extends Annotation> input) {
-              return generateAnnotationImpl(input);
-            }
-          });
+      CacheBuilder.newBuilder()
+          .weakKeys()
+          .build(
+              new CacheLoader<Class<? extends Annotation>, Annotation>() {
+                @Override
+                public Annotation load(Class<? extends Annotation> input) {
+                  return generateAnnotationImpl(input);
+                }
+              });
 
   /**
    * Generates an Annotation for the annotation class. Requires that the annotation is all
@@ -87,31 +87,32 @@
   public static <T extends Annotation> T generateAnnotation(Class<T> annotationType) {
     Preconditions.checkState(
         isAllDefaultMethods(annotationType), "%s is not all default methods", annotationType);
-    return (T)cache.getUnchecked(annotationType);
+    return (T) cache.getUnchecked(annotationType);
   }
 
   private static <T extends Annotation> T generateAnnotationImpl(final Class<T> annotationType) {
     final Map<String, Object> members = resolveMembers(annotationType);
-    return annotationType.cast(Proxy.newProxyInstance(
-        annotationType.getClassLoader(),
-        new Class<?>[] { annotationType },
-        new InvocationHandler() {
-          @Override
-          public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
-            String name = method.getName();
-            if (name.equals("annotationType")) {
-              return annotationType;
-            } else if (name.equals("toString")) {
-              return annotationToString(annotationType, members);
-            } else if (name.equals("hashCode")) {
-              return annotationHashCode(annotationType, members);
-            } else if (name.equals("equals")) {
-              return annotationEquals(annotationType, members, args[0]);
-            } else {
-              return members.get(name);
-            }
-          }
-        }));
+    return annotationType.cast(
+        Proxy.newProxyInstance(
+            annotationType.getClassLoader(),
+            new Class<?>[] {annotationType},
+            new InvocationHandler() {
+              @Override
+              public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
+                String name = method.getName();
+                if (name.equals("annotationType")) {
+                  return annotationType;
+                } else if (name.equals("toString")) {
+                  return annotationToString(annotationType, members);
+                } else if (name.equals("hashCode")) {
+                  return annotationHashCode(annotationType, members);
+                } else if (name.equals("equals")) {
+                  return annotationEquals(annotationType, members, args[0]);
+                } else {
+                  return members.get(name);
+                }
+              }
+            }));
   }
 
   private static ImmutableMap<String, Object> resolveMembers(
@@ -124,8 +125,9 @@
   }
 
   /** Implements {@link Annotation#equals}. */
-  private static boolean annotationEquals(Class<? extends Annotation> type,
-      Map<String, Object> members, Object other) throws Exception {
+  private static boolean annotationEquals(
+      Class<? extends Annotation> type, Map<String, Object> members, Object other)
+      throws Exception {
     if (!type.isInstance(other)) {
       return false;
     }
@@ -140,8 +142,8 @@
   }
 
   /** Implements {@link Annotation#hashCode}. */
-  private static int annotationHashCode(Class<? extends Annotation> type,
-      Map<String, Object> members) throws Exception {
+  private static int annotationHashCode(
+      Class<? extends Annotation> type, Map<String, Object> members) throws Exception {
     int result = 0;
     for (Method method : type.getDeclaredMethods()) {
       String name = method.getName();
@@ -153,25 +155,24 @@
 
   private static final MapJoiner JOINER = Joiner.on(", ").withKeyValueSeparator("=");
 
-  private static final Function<Object, String> DEEP_TO_STRING_FN = new Function<Object, String>() {
-    @Override
-    public String apply(Object arg) {
-      String s = Arrays.deepToString(new Object[] {arg});
-      return s.substring(1, s.length() - 1); // cut off brackets
-    }
-  };
+  private static final Function<Object, String> DEEP_TO_STRING_FN =
+      new Function<Object, String>() {
+        @Override
+        public String apply(Object arg) {
+          String s = Arrays.deepToString(new Object[] {arg});
+          return s.substring(1, s.length() - 1); // cut off brackets
+        }
+      };
 
   /** Implements {@link Annotation#toString}. */
-  private static String annotationToString(Class<? extends Annotation> type,
-      Map<String, Object> members) throws Exception {
+  private static String annotationToString(
+      Class<? extends Annotation> type, Map<String, Object> members) throws Exception {
     StringBuilder sb = new StringBuilder().append("@").append(type.getName()).append("(");
     JOINER.appendTo(sb, Maps.transformValues(members, DEEP_TO_STRING_FN));
     return sb.append(")").toString();
   }
 
-  /**
-   * Returns true if the given annotation is retained at runtime.
-   */
+  /** Returns true if the given annotation is retained at runtime. */
   public static boolean isRetainedAtRuntime(Class<? extends Annotation> annotationType) {
     Retention retention = annotationType.getAnnotation(Retention.class);
     return retention != null && retention.value() == RetentionPolicy.RUNTIME;
@@ -184,7 +185,8 @@
   }
 
   /** Returns the scoping annotation, or null if there isn't one. */
-  public static Class<? extends Annotation> findScopeAnnotation(Errors errors, Annotation[] annotations) {
+  public static Class<? extends Annotation> findScopeAnnotation(
+      Errors errors, Annotation[] annotations) {
     Class<? extends Annotation> found = null;
 
     for (Annotation annotation : annotations) {
@@ -212,53 +214,77 @@
     return false;
   }
 
+  private static final boolean QUOTE_MEMBER_VALUES = determineWhetherToQuote();
+
   /**
-   * Checks for the presence of annotations. Caches results because Android doesn't.
+   * Returns {@code value}, quoted if annotation implementations quote their member values. In Java
+   * 9, annotations quote their string members.
    */
+  public static String memberValueString(String value) {
+    return QUOTE_MEMBER_VALUES ? "\"" + value + "\"" : value;
+  }
+
+  @Retention(RUNTIME)
+  private @interface TestAnnotation {
+    String value();
+  }
+
+  @TestAnnotation("determineWhetherToQuote")
+  private static boolean determineWhetherToQuote() {
+    try {
+      String annotation =
+          Annotations.class
+              .getDeclaredMethod("determineWhetherToQuote")
+              .getAnnotation(TestAnnotation.class)
+              .toString();
+      return annotation.contains("\"determineWhetherToQuote\"");
+    } catch (NoSuchMethodException e) {
+      throw new AssertionError(e);
+    }
+  }
+
+  /** Checks for the presence of annotations. Caches results because Android doesn't. */
   static class AnnotationChecker {
     private final Collection<Class<? extends Annotation>> annotationTypes;
 
     /** Returns true if the given class has one of the desired annotations. */
     private CacheLoader<Class<? extends Annotation>, Boolean> hasAnnotations =
         new CacheLoader<Class<? extends Annotation>, Boolean>() {
-      public Boolean load(Class<? extends Annotation> annotationType) {
-        for (Annotation annotation : annotationType.getAnnotations()) {
-          if (annotationTypes.contains(annotation.annotationType())) {
-            return true;
+          @Override
+          public Boolean load(Class<? extends Annotation> annotationType) {
+            for (Annotation annotation : annotationType.getAnnotations()) {
+              if (annotationTypes.contains(annotation.annotationType())) {
+                return true;
+              }
+            }
+            return false;
           }
-        }
-        return false;
-      }
-    };
+        };
 
-    final LoadingCache<Class<? extends Annotation>, Boolean> cache = CacheBuilder.newBuilder().weakKeys()
-        .build(hasAnnotations);
+    final LoadingCache<Class<? extends Annotation>, Boolean> cache =
+        CacheBuilder.newBuilder().weakKeys().build(hasAnnotations);
 
-    /**
-     * Constructs a new checker that looks for annotations of the given types.
-     */
+    /** Constructs a new checker that looks for annotations of the given types. */
     AnnotationChecker(Collection<Class<? extends Annotation>> annotationTypes) {
       this.annotationTypes = annotationTypes;
     }
 
-    /**
-     * Returns true if the given type has one of the desired annotations.
-     */
+    /** Returns true if the given type has one of the desired annotations. */
     boolean hasAnnotations(Class<? extends Annotation> annotated) {
       return cache.getUnchecked(annotated);
     }
   }
 
-  private static final AnnotationChecker scopeChecker = new AnnotationChecker(
-      Arrays.asList(ScopeAnnotation.class, javax.inject.Scope.class));
+  private static final AnnotationChecker scopeChecker =
+      new AnnotationChecker(Arrays.asList(ScopeAnnotation.class, javax.inject.Scope.class));
 
   public static boolean isScopeAnnotation(Class<? extends Annotation> annotationType) {
     return scopeChecker.hasAnnotations(annotationType);
   }
 
   /**
-   * Adds an error if there is a misplaced annotations on {@code type}. Scoping
-   * annotations are not allowed on abstract classes or interfaces.
+   * Adds an error if there is a misplaced annotations on {@code type}. Scoping annotations are not
+   * allowed on abstract classes or interfaces.
    */
   public static void checkForMisplacedScopeAnnotations(
       Class<?> type, Object source, Errors errors) {
@@ -274,18 +300,20 @@
     }
   }
 
+  // NOTE: getKey/findBindingAnnotation are used by Gin which is abandoned.  So changing this API
+  // will prevent Gin users from upgrading Guice version.
+
   /** Gets a key for the given type, member and annotations. */
-  public static Key<?> getKey(TypeLiteral<?> type, Member member, Annotation[] annotations,
-      Errors errors) throws ErrorsException {
+  public static Key<?> getKey(
+      TypeLiteral<?> type, Member member, Annotation[] annotations, Errors errors)
+      throws ErrorsException {
     int numErrorsBefore = errors.size();
     Annotation found = findBindingAnnotation(errors, member, annotations);
     errors.throwIfNewErrors(numErrorsBefore);
     return found == null ? Key.get(type) : Key.get(type, found);
   }
 
-  /**
-   * Returns the binding annotation on {@code member}, or null if there isn't one.
-   */
+  /** Returns the binding annotation on {@code member}, or null if there isn't one. */
   public static Annotation findBindingAnnotation(
       Errors errors, Member member, Annotation[] annotations) {
     Annotation found = null;
@@ -304,23 +332,21 @@
     return found;
   }
 
-  private static final AnnotationChecker bindingAnnotationChecker = new AnnotationChecker(
-      Arrays.asList(BindingAnnotation.class, Qualifier.class));
+  private static final AnnotationChecker bindingAnnotationChecker =
+      new AnnotationChecker(Arrays.asList(BindingAnnotation.class, Qualifier.class));
 
-  /**
-   * Returns true if annotations of the specified type are binding annotations.
-   */
+  /** Returns true if annotations of the specified type are binding annotations. */
   public static boolean isBindingAnnotation(Class<? extends Annotation> annotationType) {
     return bindingAnnotationChecker.hasAnnotations(annotationType);
   }
 
   /**
    * If the annotation is an instance of {@code javax.inject.Named}, canonicalizes to
-   * com.google.guice.name.Named.  Returns the given annotation otherwise.
+   * com.google.guice.name.Named. Returns the given annotation otherwise.
    */
   public static Annotation canonicalizeIfNamed(Annotation annotation) {
-    if(annotation instanceof javax.inject.Named) {
-      return Names.named(((javax.inject.Named)annotation).value());
+    if (annotation instanceof javax.inject.Named) {
+      return Names.named(((javax.inject.Named) annotation).value());
     } else {
       return annotation;
     }
@@ -338,4 +364,22 @@
       return annotationType;
     }
   }
+
+  /**
+   * Returns the name the binding should use. This is based on the annotation. If the annotation has
+   * an instance and is not a marker annotation, we ask the annotation for its toString. If it was a
+   * marker annotation or just an annotation type, we use the annotation's name. Otherwise, the name
+   * is the empty string.
+   */
+  public static String nameOf(Key<?> key) {
+    Annotation annotation = key.getAnnotation();
+    Class<? extends Annotation> annotationType = key.getAnnotationType();
+    if (annotation != null && !isMarker(annotationType)) {
+      return key.getAnnotation().toString();
+    } else if (key.getAnnotationType() != null) {
+      return "@" + key.getAnnotationType().getName();
+    } else {
+      return "";
+    }
+  }
 }
diff --git a/core/src/com/google/inject/internal/BindingBuilder.java b/core/src/com/google/inject/internal/BindingBuilder.java
index 36c31ff..100137e 100644
--- a/core/src/com/google/inject/internal/BindingBuilder.java
+++ b/core/src/com/google/inject/internal/BindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,7 +29,6 @@
 import com.google.inject.spi.Element;
 import com.google.inject.spi.InjectionPoint;
 import com.google.inject.spi.Message;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.util.List;
@@ -47,33 +46,39 @@
     super(binder, elements, source, key);
   }
 
+  @Override
   public BindingBuilder<T> annotatedWith(Class<? extends Annotation> annotationType) {
     annotatedWithInternal(annotationType);
     return this;
   }
 
+  @Override
   public BindingBuilder<T> annotatedWith(Annotation annotation) {
     annotatedWithInternal(annotation);
     return this;
   }
 
+  @Override
   public BindingBuilder<T> to(Class<? extends T> implementation) {
     return to(Key.get(implementation));
   }
 
+  @Override
   public BindingBuilder<T> to(TypeLiteral<? extends T> implementation) {
     return to(Key.get(implementation));
   }
 
+  @Override
   public BindingBuilder<T> to(Key<? extends T> linkedKey) {
     checkNotNull(linkedKey, "linkedKey");
     checkNotTargetted();
     BindingImpl<T> base = getBinding();
-    setBinding(new LinkedBindingImpl<T>(
-        base.getSource(), base.getKey(), base.getScoping(), linkedKey));
+    setBinding(
+        new LinkedBindingImpl<T>(base.getSource(), base.getKey(), base.getScoping(), linkedKey));
     return this;
   }
 
+  @Override
   public void toInstance(T instance) {
     checkNotTargetted();
 
@@ -92,14 +97,17 @@
     }
 
     BindingImpl<T> base = getBinding();
-    setBinding(new InstanceBindingImpl<T>(
-        base.getSource(), base.getKey(), Scoping.EAGER_SINGLETON, injectionPoints, instance));
+    setBinding(
+        new InstanceBindingImpl<T>(
+            base.getSource(), base.getKey(), Scoping.EAGER_SINGLETON, injectionPoints, instance));
   }
 
+  @Override
   public BindingBuilder<T> toProvider(Provider<? extends T> provider) {
     return toProvider((javax.inject.Provider<T>) provider);
   }
 
+  @Override
   public BindingBuilder<T> toProvider(javax.inject.Provider<? extends T> provider) {
     checkNotNull(provider, "provider");
     checkNotTargetted();
@@ -114,38 +122,45 @@
     }
 
     BindingImpl<T> base = getBinding();
-    setBinding(new ProviderInstanceBindingImpl<T>(
-        base.getSource(), base.getKey(), base.getScoping(), injectionPoints, provider));
+    setBinding(
+        new ProviderInstanceBindingImpl<T>(
+            base.getSource(), base.getKey(), base.getScoping(), injectionPoints, provider));
     return this;
   }
 
+  @Override
   public BindingBuilder<T> toProvider(
       Class<? extends javax.inject.Provider<? extends T>> providerType) {
     return toProvider(Key.get(providerType));
   }
 
+  @Override
   public BindingBuilder<T> toProvider(
       TypeLiteral<? extends javax.inject.Provider<? extends T>> providerType) {
     return toProvider(Key.get(providerType));
   }
 
+  @Override
   public BindingBuilder<T> toProvider(
       Key<? extends javax.inject.Provider<? extends T>> providerKey) {
     checkNotNull(providerKey, "providerKey");
     checkNotTargetted();
 
     BindingImpl<T> base = getBinding();
-    setBinding(new LinkedProviderBindingImpl<T>(
-        base.getSource(), base.getKey(), base.getScoping(), providerKey));
+    setBinding(
+        new LinkedProviderBindingImpl<T>(
+            base.getSource(), base.getKey(), base.getScoping(), providerKey));
     return this;
   }
 
+  @Override
   public <S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor) {
     return toConstructor(constructor, TypeLiteral.get(constructor.getDeclaringClass()));
   }
 
-  public <S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor,
-      TypeLiteral<? extends S> type) {
+  @Override
+  public <S extends T> ScopedBindingBuilder toConstructor(
+      Constructor<S> constructor, TypeLiteral<? extends S> type) {
     checkNotNull(constructor, "constructor");
     checkNotNull(type, "type");
     checkNotTargetted();
@@ -162,16 +177,22 @@
 
     try {
       InjectionPoint constructorPoint = InjectionPoint.forConstructor(constructor, type);
-      setBinding(new ConstructorBindingImpl<T>(base.getKey(), base.getSource(), base.getScoping(),
-          constructorPoint, injectionPoints));
+      setBinding(
+          new ConstructorBindingImpl<T>(
+              base.getKey(),
+              base.getSource(),
+              base.getScoping(),
+              constructorPoint,
+              injectionPoints));
     } catch (ConfigurationException e) {
       copyErrorsToBinder(e);
     }
 
     return this;
   }
-  
-  @Override public String toString() {
+
+  @Override
+  public String toString() {
     return "BindingBuilder<" + getBinding().getKey().getTypeLiteral() + ">";
   }
 
diff --git a/core/src/com/google/inject/internal/BindingImpl.java b/core/src/com/google/inject/internal/BindingImpl.java
index 3228e3d..4259296 100644
--- a/core/src/com/google/inject/internal/BindingImpl.java
+++ b/core/src/com/google/inject/internal/BindingImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 
 package com.google.inject.internal;
 
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.inject.Binding;
 import com.google.inject.Key;
 import com.google.inject.Provider;
@@ -24,9 +24,7 @@
 import com.google.inject.spi.ElementVisitor;
 import com.google.inject.spi.InstanceBinding;
 
-/**
- * @author crazybob@google.com (Bob Lee)
- */
+/** @author crazybob@google.com (Bob Lee) */
 public abstract class BindingImpl<T> implements Binding<T> {
 
   private final InjectorImpl injector;
@@ -35,8 +33,12 @@
   private final Scoping scoping;
   private final InternalFactory<? extends T> internalFactory;
 
-  public BindingImpl(InjectorImpl injector, Key<T> key, Object source,
-      InternalFactory<? extends T> internalFactory, Scoping scoping) {
+  public BindingImpl(
+      InjectorImpl injector,
+      Key<T> key,
+      Object source,
+      InternalFactory<? extends T> internalFactory,
+      Scoping scoping) {
     this.injector = injector;
     this.key = key;
     this.source = source;
@@ -52,16 +54,19 @@
     this.scoping = scoping;
   }
 
+  @Override
   public Key<T> getKey() {
     return key;
   }
 
+  @Override
   public Object getSource() {
     return source;
   }
 
   private volatile Provider<T> provider;
 
+  @Override
   public Provider<T> getProvider() {
     if (provider == null) {
       if (injector == null) {
@@ -82,17 +87,19 @@
   }
 
   /**
-   * Is this a constant binding? This returns true for constant bindings as
-   * well as toInstance() bindings.
+   * Is this a constant binding? This returns true for constant bindings as well as toInstance()
+   * bindings.
    */
   public boolean isConstant() {
     return this instanceof InstanceBinding;
   }
 
+  @Override
   public <V> V acceptVisitor(ElementVisitor<V> visitor) {
     return visitor.visit(this);
   }
 
+  @Override
   public <V> V acceptScopingVisitor(BindingScopingVisitor<V> visitor) {
     return scoping.acceptVisitor(visitor);
   }
@@ -104,9 +111,10 @@
   protected BindingImpl<T> withKey(Key<T> key) {
     throw new AssertionError();
   }
-  
-  @Override public String toString() {
-    return Objects.toStringHelper(Binding.class)
+
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(Binding.class)
         .add("key", key)
         .add("scope", scoping)
         .add("source", source)
diff --git a/core/src/com/google/inject/internal/BindingProcessor.java b/core/src/com/google/inject/internal/BindingProcessor.java
index b3c869e..e9c52b4 100644
--- a/core/src/com/google/inject/internal/BindingProcessor.java
+++ b/core/src/com/google/inject/internal/BindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,7 +31,6 @@
 import com.google.inject.spi.ProviderInstanceBinding;
 import com.google.inject.spi.ProviderKeyBinding;
 import com.google.inject.spi.UntargettedBinding;
-
 import java.util.Set;
 
 /**
@@ -49,7 +48,8 @@
     this.initializer = initializer;
   }
 
-  @Override public <T> Boolean visit(Binding<T> command) {
+  @Override
+  public <T> Boolean visit(Binding<T> command) {
     Class<?> rawType = command.getKey().getTypeLiteral().getRawType();
     if (Void.class.equals(rawType)) {
       if (command instanceof ProviderInstanceBinding
@@ -61,127 +61,183 @@
       }
       return true;
     }
-    
+
     if (rawType == Provider.class) {
       errors.bindingToProvider();
       return true;
     }
-    
-    return command.acceptTargetVisitor(new Processor<T, Boolean>((BindingImpl<T>)command) {
-      @Override
-      public Boolean visit(ConstructorBinding<? extends T> binding) {
-        prepareBinding();
-        try {
-          ConstructorBindingImpl<T> onInjector = ConstructorBindingImpl.create(injector, key, 
-              binding.getConstructor(), source, scoping, errors, false, false);
-          scheduleInitialization(onInjector);
-          putBinding(onInjector);
-        } catch (ErrorsException e) {
-          errors.merge(e.getErrors());
-          putBinding(invalidBinding(injector, key, source));
-        }
-        return true;
-      }
 
-      @Override
-      public Boolean visit(InstanceBinding<? extends T> binding) {
-        prepareBinding();
-        Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
-        T instance = binding.getInstance();
-        @SuppressWarnings("unchecked") // safe to cast to binding<T> because
-                                       // the processor was constructed w/ it
-        Initializable<T> ref = initializer.requestInjection(
-            injector, instance, (Binding<T>) binding, source, injectionPoints);
-        ConstantFactory<? extends T> factory = new ConstantFactory<T>(ref);
-        InternalFactory<? extends T> scopedFactory
-            = Scoping.scope(key, injector, factory, source, scoping);
-        putBinding(new InstanceBindingImpl<T>(injector, key, source, scopedFactory, injectionPoints,
-            instance));
-        return true;
-      }
+    return command.acceptTargetVisitor(
+        new Processor<T, Boolean>((BindingImpl<T>) command) {
+          @Override
+          public Boolean visit(ConstructorBinding<? extends T> binding) {
+            prepareBinding();
+            try {
+              ConstructorBindingImpl<T> onInjector =
+                  ConstructorBindingImpl.create(
+                      injector,
+                      key,
+                      binding.getConstructor(),
+                      source,
+                      scoping,
+                      errors,
+                      false,
+                      false);
+              scheduleInitialization(onInjector);
+              putBinding(onInjector);
+            } catch (ErrorsException e) {
+              errors.merge(e.getErrors());
+              putBinding(invalidBinding(injector, key, source));
+            }
+            return true;
+          }
 
-      @Override
-      public Boolean visit(ProviderInstanceBinding<? extends T> binding) {
-        prepareBinding();
-        javax.inject.Provider<? extends T> provider = binding.getUserSuppliedProvider();
-        Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
-        Initializable<? extends javax.inject.Provider<? extends T>> initializable =
-            initializer.<javax.inject.Provider<? extends T>>requestInjection(
-                injector, provider, null, source, injectionPoints);
-        // always visited with Binding<T>
-        @SuppressWarnings("unchecked") 
-        InternalFactory<T> factory = new InternalFactoryToInitializableAdapter<T>(
-            initializable, source,
-            injector.provisionListenerStore.get((ProviderInstanceBinding<T>)binding));
-        InternalFactory<? extends T> scopedFactory
-            = Scoping.scope(key, injector, factory, source, scoping);
-        putBinding(new ProviderInstanceBindingImpl<T>(injector, key, source, scopedFactory, scoping,
-            provider, injectionPoints));
-        return true;
-      }
+          @Override
+          public Boolean visit(InstanceBinding<? extends T> binding) {
+            prepareBinding();
+            Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
+            T instance = binding.getInstance();
+            @SuppressWarnings("unchecked") // safe to cast to binding<T> because
+            // the processor was constructed w/ it
+            Initializable<T> ref =
+                initializer.requestInjection(
+                    injector, instance, (Binding<T>) binding, source, injectionPoints);
+            ConstantFactory<? extends T> factory = new ConstantFactory<>(ref);
+            InternalFactory<? extends T> scopedFactory =
+                Scoping.scope(key, injector, factory, source, scoping);
+            putBinding(
+                new InstanceBindingImpl<T>(
+                    injector, key, source, scopedFactory, injectionPoints, instance));
+            return true;
+          }
 
-      @Override
-      public Boolean visit(ProviderKeyBinding<? extends T> binding) {
-        prepareBinding();
-        Key<? extends javax.inject.Provider<? extends T>> providerKey = binding.getProviderKey();
-        // always visited with Binding<T>
-        @SuppressWarnings("unchecked") 
-        BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>(
-            injector, providerKey, source,
-            injector.provisionListenerStore.get((ProviderKeyBinding<T>) binding));
-        bindingData.addCreationListener(boundProviderFactory);
-        InternalFactory<? extends T> scopedFactory = Scoping.scope(
-            key, injector, (InternalFactory<? extends T>) boundProviderFactory, source, scoping);
-        putBinding(new LinkedProviderBindingImpl<T>(
-            injector, key, source, scopedFactory, scoping, providerKey));
-        return true;
-      }
+          @Override
+          public Boolean visit(ProviderInstanceBinding<? extends T> binding) {
+            prepareBinding();
+            javax.inject.Provider<? extends T> provider = binding.getUserSuppliedProvider();
+            if (provider instanceof InternalProviderInstanceBindingImpl.Factory) {
+              @SuppressWarnings("unchecked")
+              InternalProviderInstanceBindingImpl.Factory<T> asProviderMethod =
+                  (InternalProviderInstanceBindingImpl.Factory<T>) provider;
+              return visitInternalProviderInstanceBindingFactory(asProviderMethod);
+            }
+            Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
+            Initializable<? extends javax.inject.Provider<? extends T>> initializable =
+                initializer.<javax.inject.Provider<? extends T>>requestInjection(
+                    injector, provider, null, source, injectionPoints);
+            // always visited with Binding<T>
+            @SuppressWarnings("unchecked")
+            InternalFactory<T> factory =
+                new InternalFactoryToInitializableAdapter<T>(
+                    initializable,
+                    source,
+                    injector.provisionListenerStore.get((ProviderInstanceBinding<T>) binding));
+            InternalFactory<? extends T> scopedFactory =
+                Scoping.scope(key, injector, factory, source, scoping);
+            putBinding(
+                new ProviderInstanceBindingImpl<T>(
+                    injector, key, source, scopedFactory, scoping, provider, injectionPoints));
+            return true;
+          }
 
-      @Override
-      public Boolean visit(LinkedKeyBinding<? extends T> binding) {
-        prepareBinding();
-        Key<? extends T> linkedKey = binding.getLinkedKey();
-        if (key.equals(linkedKey)) {
-          errors.recursiveBinding();
-        }
+          @Override
+          public Boolean visit(ProviderKeyBinding<? extends T> binding) {
+            prepareBinding();
+            Key<? extends javax.inject.Provider<? extends T>> providerKey =
+                binding.getProviderKey();
+            // always visited with Binding<T>
+            @SuppressWarnings("unchecked")
+            BoundProviderFactory<T> boundProviderFactory =
+                new BoundProviderFactory<T>(
+                    injector,
+                    providerKey,
+                    source,
+                    injector.provisionListenerStore.get((ProviderKeyBinding<T>) binding));
+            bindingData.addCreationListener(boundProviderFactory);
+            InternalFactory<? extends T> scopedFactory =
+                Scoping.scope(
+                    key,
+                    injector,
+                    (InternalFactory<? extends T>) boundProviderFactory,
+                    source,
+                    scoping);
+            putBinding(
+                new LinkedProviderBindingImpl<T>(
+                    injector, key, source, scopedFactory, scoping, providerKey));
+            return true;
+          }
 
-        FactoryProxy<T> factory = new FactoryProxy<T>(injector, key, linkedKey, source);
-        bindingData.addCreationListener(factory);
-        InternalFactory<? extends T> scopedFactory
-            = Scoping.scope(key, injector, factory, source, scoping);
-        putBinding(
-            new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey));
-        return true;
-      }
+          @Override
+          public Boolean visit(LinkedKeyBinding<? extends T> binding) {
+            prepareBinding();
+            Key<? extends T> linkedKey = binding.getLinkedKey();
+            if (key.equals(linkedKey)) {
+              errors.recursiveBinding();
+            }
 
-      @Override
-      public Boolean visit(UntargettedBinding<? extends T> untargetted) {
-        return false;
-      }
+            FactoryProxy<T> factory = new FactoryProxy<>(injector, key, linkedKey, source);
+            bindingData.addCreationListener(factory);
+            InternalFactory<? extends T> scopedFactory =
+                Scoping.scope(key, injector, factory, source, scoping);
+            putBinding(
+                new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey));
+            return true;
+          }
 
-      @Override
-      public Boolean visit(ExposedBinding<? extends T> binding) {
-        throw new IllegalArgumentException("Cannot apply a non-module element");
-      }
-      
-      @Override
-      public Boolean visit(ConvertedConstantBinding<? extends T> binding) {
-        throw new IllegalArgumentException("Cannot apply a non-module element");
-      }
-      
-      @Override
-      public Boolean visit(ProviderBinding<? extends T> binding) {
-        throw new IllegalArgumentException("Cannot apply a non-module element");
-      }
-      
-      @Override
-      protected Boolean visitOther(Binding<? extends T> binding) {
-        throw new IllegalStateException("BindingProcessor should override all visitations");
-      }
-    });
+          /** Handle ProviderMethods specially. */
+          private Boolean visitInternalProviderInstanceBindingFactory(
+              InternalProviderInstanceBindingImpl.Factory<T> provider) {
+            InternalProviderInstanceBindingImpl<T> binding =
+                new InternalProviderInstanceBindingImpl<T>(
+                    injector,
+                    key,
+                    source,
+                    provider,
+                    Scoping.scope(key, injector, provider, source, scoping),
+                    scoping);
+            switch (binding.getInitializationTiming()) {
+              case DELAYED:
+                scheduleDelayedInitialization(binding);
+                break;
+              case EAGER:
+                scheduleInitialization(binding);
+                break;
+              default:
+                throw new AssertionError();
+            }
+            putBinding(binding);
+            return true;
+          }
+
+          @Override
+          public Boolean visit(UntargettedBinding<? extends T> untargetted) {
+            return false;
+          }
+
+          @Override
+          public Boolean visit(ExposedBinding<? extends T> binding) {
+            throw new IllegalArgumentException("Cannot apply a non-module element");
+          }
+
+          @Override
+          public Boolean visit(ConvertedConstantBinding<? extends T> binding) {
+            throw new IllegalArgumentException("Cannot apply a non-module element");
+          }
+
+          @Override
+          public Boolean visit(ProviderBinding<? extends T> binding) {
+            throw new IllegalArgumentException("Cannot apply a non-module element");
+          }
+
+          @Override
+          protected Boolean visitOther(Binding<? extends T> binding) {
+            throw new IllegalStateException("BindingProcessor should override all visitations");
+          }
+        });
   }
 
-  @Override public Boolean visit(PrivateElements privateElements) {
+  @Override
+  public Boolean visit(PrivateElements privateElements) {
     for (Key<?> key : privateElements.getExposedKeys()) {
       bindExposed(privateElements, key);
     }
@@ -189,9 +245,14 @@
   }
 
   private <T> void bindExposed(PrivateElements privateElements, Key<T> key) {
-    ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateElements);
+    ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<>(key, privateElements);
     bindingData.addCreationListener(exposedKeyFactory);
-    putBinding(new ExposedBindingImpl<T>(
-        injector, privateElements.getExposedSource(key), key, exposedKeyFactory, privateElements));
+    putBinding(
+        new ExposedBindingImpl<T>(
+            injector,
+            privateElements.getExposedSource(key),
+            key,
+            exposedKeyFactory,
+            privateElements));
   }
 }
diff --git a/core/src/com/google/inject/internal/BoundProviderFactory.java b/core/src/com/google/inject/internal/BoundProviderFactory.java
index 9f523df..eaaf767 100644
--- a/core/src/com/google/inject/internal/BoundProviderFactory.java
+++ b/core/src/com/google/inject/internal/BoundProviderFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,12 @@
 
 package com.google.inject.internal;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 import com.google.inject.Key;
 import com.google.inject.internal.InjectorImpl.JitLimitation;
 import com.google.inject.spi.Dependency;
-
 import javax.inject.Provider;
 
-/**
- * Delegates to a custom factory which is also bound in the injector.
- */
+/** Delegates to a custom factory which is also bound in the injector. */
 final class BoundProviderFactory<T> extends ProviderInternalFactory<T> implements CreationListener {
 
   private final ProvisionListenerStackCallback<T> provisionCallback;
@@ -40,42 +35,53 @@
       Object source,
       ProvisionListenerStackCallback<T> provisionCallback) {
     super(source);
-    this.provisionCallback = checkNotNull(provisionCallback, "provisionCallback");
+    this.provisionCallback = provisionCallback;
     this.injector = injector;
     this.providerKey = providerKey;
   }
 
+  @Override
   public void notify(Errors errors) {
     try {
-      providerFactory = injector.getInternalFactory(providerKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT);
+      providerFactory =
+          injector.getInternalFactory(
+              providerKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT);
     } catch (ErrorsException e) {
       errors.merge(e.getErrors());
     }
   }
 
-  public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
-      throws ErrorsException {
+  @Override
+  public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+      throws InternalProvisionException {
     context.pushState(providerKey, source);
+
     try {
-      errors = errors.withSource(providerKey);
-      javax.inject.Provider<? extends T> provider = providerFactory.get(errors, context, dependency, true);
-      return circularGet(provider, errors, context, dependency, provisionCallback);
-    } finally {
-      context.popState();
+      javax.inject.Provider<? extends T> provider = providerFactory.get(context, dependency, true);
+      return circularGet(provider, context, dependency, provisionCallback);
+    } catch (InternalProvisionException ipe) {
+      throw ipe.addSource(providerKey);
+      } finally {
+        context.popState();
+
     }
   }
-  
+
   @Override
-  protected T provision(Provider<? extends T> provider, Errors errors, Dependency<?> dependency,
-      ConstructionContext<T> constructionContext) throws ErrorsException {
+  protected T provision(
+      Provider<? extends T> provider,
+      Dependency<?> dependency,
+      ConstructionContext<T> constructionContext)
+      throws InternalProvisionException {
     try {
-      return super.provision(provider, errors, dependency, constructionContext);
-    } catch(RuntimeException userException) {
-      throw errors.errorInProvider(userException).toException();
-    } 
+      return super.provision(provider, dependency, constructionContext);
+    } catch (RuntimeException userException) {
+      throw InternalProvisionException.errorInProvider(userException);
+    }
   }
 
-  @Override public String toString() {
+  @Override
+  public String toString() {
     return providerKey.toString();
   }
 }
diff --git a/core/src/com/google/inject/internal/BytecodeGen.java b/core/src/com/google/inject/internal/BytecodeGen.java
index ed01cd1..2ec96cb 100644
--- a/core/src/com/google/inject/internal/BytecodeGen.java
+++ b/core/src/com/google/inject/internal/BytecodeGen.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,13 +22,13 @@
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.inject.internal.InternalFlags.CustomClassLoadingOption;
-
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
@@ -37,24 +37,26 @@
  * interceptors} and to proxy circular dependencies.
  *
  * <p>When loading classes, we need to be careful of:
+ *
  * <ul>
- *   <li><strong>Memory leaks.</strong> Generated classes need to be garbage collected in long-lived
- *       applications. Once an injector and any instances it created can be garbage collected, the
- *       corresponding generated classes should be collectable.
- *   <li><strong>Visibility.</strong> Containers like <code>OSGi</code> use class loader boundaries
- *       to enforce modularity at runtime.
+ * <li><strong>Memory leaks.</strong> Generated classes need to be garbage collected in long-lived
+ *     applications. Once an injector and any instances it created can be garbage collected, the
+ *     corresponding generated classes should be collectable.
+ * <li><strong>Visibility.</strong> Containers like <code>OSGi</code> use class loader boundaries to
+ *     enforce modularity at runtime.
  * </ul>
  *
  * <p>For each generated class, there's multiple class loaders involved:
+ *
  * <ul>
- *    <li><strong>The related class's class loader.</strong> Every generated class services exactly
- *        one user-supplied class. This class loader must be used to access members with private and
- *        package visibility.
- *    <li><strong>Guice's class loader.</strong>
- *    <li><strong>Our bridge class loader.</strong> This is a child of the user's class loader. It
- *        selectively delegates to either the user's class loader (for user classes) or the Guice
- *        class loader (for internal classes that are used by the generated classes). This class
- *        loader that owns the classes generated by Guice.
+ * <li><strong>The related class's class loader.</strong> Every generated class services exactly one
+ *     user-supplied class. This class loader must be used to access members with protected and
+ *     package visibility.
+ * <li><strong>Guice's class loader.</strong>
+ * <li><strong>Our bridge class loader.</strong> This is a child of the user's class loader. It
+ *     selectively delegates to either the user's class loader (for user classes) or the Guice class
+ *     loader (for internal classes that are used by the generated classes). This class loader that
+ *     owns the classes generated by Guice.
  * </ul>
  *
  * @author mcculls@gmail.com (Stuart McCulloch)
@@ -72,56 +74,57 @@
   }
 
   /** ie. "com.google.inject.internal" */
-  static final String GUICE_INTERNAL_PACKAGE
-      = BytecodeGen.class.getName().replaceFirst("\\.internal\\..*$", ".internal");
+  static final String GUICE_INTERNAL_PACKAGE =
+      BytecodeGen.class.getName().replaceFirst("\\.internal\\..*$", ".internal");
 
   /*if[AOP]*/
   /** either "net.sf.cglib", or "com.google.inject.internal.cglib" */
-  static final String CGLIB_PACKAGE
-      = net.sf.cglib.proxy.Enhancer.class.getName().replaceFirst("\\.cglib\\..*$", ".cglib");
+  static final String CGLIB_PACKAGE =
+      net.sf.cglib.proxy.Enhancer.class.getName().replaceFirst("\\.cglib\\..*$", ".cglib");
 
-  static final net.sf.cglib.core.NamingPolicy FASTCLASS_NAMING_POLICY
-      = new net.sf.cglib.core.DefaultNamingPolicy() {
-    @Override protected String getTag() {
-      return "ByGuice";
-    }
+  static final net.sf.cglib.core.NamingPolicy FASTCLASS_NAMING_POLICY =
+      new net.sf.cglib.core.DefaultNamingPolicy() {
+        @Override
+        protected String getTag() {
+          return "ByGuice";
+        }
 
-    @Override
-    public String getClassName(String prefix, String source, Object key,
-        net.sf.cglib.core.Predicate names) {
-      // we explicitly set the source here to "FastClass" so that our jarjar renaming
-      // to $FastClass doesn't leak into the class names.  if we did not do this,
-      // classes would end up looking like $$$FastClassByGuice$$, with the extra $
-      // at the front.
-      return super.getClassName(prefix, "FastClass", key, names);
-    }
-  };
+        @Override
+        public String getClassName(
+            String prefix, String source, Object key, net.sf.cglib.core.Predicate names) {
+          // we explicitly set the source here to "FastClass" so that our jarjar renaming
+          // to $FastClass doesn't leak into the class names.  if we did not do this,
+          // classes would end up looking like $$$FastClassByGuice$$, with the extra $
+          // at the front.
+          return super.getClassName(prefix, "FastClass", key, names);
+        }
+      };
 
-  static final net.sf.cglib.core.NamingPolicy ENHANCER_NAMING_POLICY
-      = new net.sf.cglib.core.DefaultNamingPolicy() {
-    @Override
-    protected String getTag() {
-      return "ByGuice";
-    }
+  static final net.sf.cglib.core.NamingPolicy ENHANCER_NAMING_POLICY =
+      new net.sf.cglib.core.DefaultNamingPolicy() {
+        @Override
+        protected String getTag() {
+          return "ByGuice";
+        }
 
-    @Override
-    public String getClassName(String prefix, String source, Object key,
-        net.sf.cglib.core.Predicate names) {
-      // we explicitly set the source here to "Enhancer" so that our jarjar renaming
-      // to $Enhancer doesn't leak into the class names.  if we did not do this,
-      // classes would end up looking like $$$EnhancerByGuice$$, with the extra $
-      // at the front.
-      return super.getClassName(prefix, "Enhancer", key, names);
-    }
-  };
+        @Override
+        public String getClassName(
+            String prefix, String source, Object key, net.sf.cglib.core.Predicate names) {
+          // we explicitly set the source here to "Enhancer" so that our jarjar renaming
+          // to $Enhancer doesn't leak into the class names.  if we did not do this,
+          // classes would end up looking like $$$EnhancerByGuice$$, with the extra $
+          // at the front.
+          return super.getClassName(prefix, "Enhancer", key, names);
+        }
+      };
   /*end[AOP]*/
   /*if[NO_AOP]
   private static final String CGLIB_PACKAGE = " "; // any string that's illegal in a package name
   end[NO_AOP]*/
 
   /**
-   * Weak cache of bridge class loaders that make the Guice implementation
-   * classes visible to various code-generated proxies of client classes.
+   * Weak cache of bridge class loaders that make the Guice implementation classes visible to
+   * various code-generated proxies of client classes.
    */
   private static final LoadingCache<ClassLoader, ClassLoader> CLASS_LOADER_CACHE;
 
@@ -130,30 +133,32 @@
     if (getCustomClassLoadingOption() == CustomClassLoadingOption.OFF) {
       builder.maximumSize(0);
     }
-    CLASS_LOADER_CACHE = builder.build(
-        new CacheLoader<ClassLoader, ClassLoader>() {
-          @Override public ClassLoader load(final ClassLoader typeClassLoader) {
-            logger.fine("Creating a bridge ClassLoader for " + typeClassLoader);
-            return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
-              public ClassLoader run() {
-                return new BridgeClassLoader(typeClassLoader);
+    CLASS_LOADER_CACHE =
+        builder.build(
+            new CacheLoader<ClassLoader, ClassLoader>() {
+              @Override
+              public ClassLoader load(final ClassLoader typeClassLoader) {
+                logger.fine("Creating a bridge ClassLoader for " + typeClassLoader);
+                return AccessController.doPrivileged(
+                    new PrivilegedAction<ClassLoader>() {
+                      @Override
+                      public ClassLoader run() {
+                        return new BridgeClassLoader(typeClassLoader);
+                      }
+                    });
               }
             });
-          }
-        });
   }
 
   /**
-   * Attempts to canonicalize null references to the system class loader.
-   * May return null if for some reason the system loader is unavailable.
+   * Attempts to canonicalize null references to the system class loader. May return null if for
+   * some reason the system loader is unavailable.
    */
   private static ClassLoader canonicalize(ClassLoader classLoader) {
     return classLoader != null ? classLoader : SystemBridgeHolder.SYSTEM_BRIDGE.getParent();
   }
 
-  /**
-   * Returns the class loader to host generated classes for {@code type}.
-   */
+  /** Returns the class loader to host generated classes for {@code type}. */
   public static ClassLoader getClassLoader(Class<?> type) {
     return getClassLoader(type, type.getClassLoader());
   }
@@ -191,19 +196,108 @@
   }
 
   /*if[AOP]*/
-  // use fully-qualified names so imports don't need preprocessor statements 
-  public static net.sf.cglib.reflect.FastClass newFastClass(Class<?> type, Visibility visibility) {
-    net.sf.cglib.reflect.FastClass.Generator generator
-        = new net.sf.cglib.reflect.FastClass.Generator();
-    generator.setType(type);
-    if (visibility == Visibility.PUBLIC) {
+  // use fully-qualified names so imports don't need preprocessor statements
+  /**
+   * Returns a FastClass proxy for invoking the given member or {@code null} if access rules
+   * disallow it.
+   *
+   * @see #newFastClassForMember(Class, Member) for a full description
+   */
+  public static net.sf.cglib.reflect.FastClass newFastClassForMember(Member member) {
+    return newFastClassForMember(member.getDeclaringClass(), member);
+  }
+
+  /**
+   * Returns a FastClass proxy for invoking the given member or {@code null} if access rules
+   * disallow it.
+   *
+   * <p>FastClass works by generating a type in the same package as the target {@code type}. This
+   * may or may not work depending on the access level of the class/member. It breaks down into the
+   * following cases depending on accessibility:
+   *
+   * <ul>
+   * <li>Public: This always works since we can generate the type into the {@link BridgeClassLoader}
+   *     which ensures there are no versioning issues.
+   * <li>Package private and Protected: This works as long as:
+   *     <ul>
+   *     <li>We can generate into the same classloader as the type. This is not possible for JDK
+   *         types which use the 'bootstrap' loader.
+   *     <li>The classloader of the type has the same version of {@code FastClass} as we do. This
+   *         may be violated when running in OSGI bundles.
+   *     </ul>
+   *
+   * <li>Private: This never works.
+   * </ul>
+   *
+   * If we are unable to generate the type, then we return null and callers should work around by
+   * using normal java reflection.
+   */
+  public static net.sf.cglib.reflect.FastClass newFastClassForMember(Class<?> type, Member member) {
+    if (!new net.sf.cglib.core.VisibilityPredicate(type, false).evaluate(member)) {
+      // the member cannot be indexed by fast class.  Bail out.
+      return null;
+    }
+
+    boolean publiclyCallable = isPubliclyCallable(member);
+    if (!publiclyCallable && !hasSameVersionOfCglib(type.getClassLoader())) {
+      // The type is in a classloader with a different version of cglib and is not publicly visible
+      // (so we can't use the bridge classloader to work around).  Bail out.
+      return null;
+    }
+    net.sf.cglib.reflect.FastClass.Generator generator =
+        new net.sf.cglib.reflect.FastClass.Generator();
+    if (publiclyCallable) {
+      // Use the bridge classloader if we can
       generator.setClassLoader(getClassLoader(type));
     }
+    generator.setType(type);
     generator.setNamingPolicy(FASTCLASS_NAMING_POLICY);
-    logger.fine("Loading " + type + " FastClass with " + generator.getClassLoader());
+    if (logger.isLoggable(Level.FINE)) {
+      logger.fine("Loading " + type + " FastClass with " + generator.getClassLoader());
+    }
     return generator.create();
   }
 
+  /**
+   * Returns true if the types classloader has the same version of cglib that BytecodeGen has. This
+   * only returns false in strange OSGI situations, but it prevents us from using FastClass for non
+   * public members.
+   */
+  private static boolean hasSameVersionOfCglib(ClassLoader classLoader) {
+    Class<?> fc = net.sf.cglib.reflect.FastClass.class;
+    try {
+      return classLoader.loadClass(fc.getName()) == fc;
+    } catch (ClassNotFoundException e) {
+      return false;
+    }
+  }
+
+  /**
+   * Returns true if the member can be called by a fast class generated in a different classloader.
+   */
+  private static boolean isPubliclyCallable(Member member) {
+    if (!Modifier.isPublic(member.getModifiers())) {
+      return false;
+    }
+    Class<?>[] parameterTypes;
+    if (member instanceof Constructor) {
+      parameterTypes = ((Constructor) member).getParameterTypes();
+    } else {
+      Method method = (Method) member;
+      if (!Modifier.isPublic(method.getReturnType().getModifiers())) {
+        return false;
+      }
+      parameterTypes = method.getParameterTypes();
+    }
+
+    for (Class<?> type : parameterTypes) {
+      if (!Modifier.isPublic(type.getModifiers())) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   public static net.sf.cglib.proxy.Enhancer newEnhancer(Class<?> type, Visibility visibility) {
     net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer();
     enhancer.setSuperclass(type);
@@ -298,10 +392,10 @@
       super(usersClassLoader);
     }
 
-    @Override protected Class<?> loadClass(String name, boolean resolve)
-        throws ClassNotFoundException {
+    @Override
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
 
-      if (name.startsWith("sun.reflect")) {
+      if (name.startsWith("sun.reflect") || name.startsWith("jdk.internal.reflect")) {
         // these reflection classes must be loaded from bootstrap class loader
         return SystemBridgeHolder.SYSTEM_BRIDGE.classicLoadClass(name, resolve);
       }
@@ -326,8 +420,7 @@
     }
 
     // make the classic delegating loadClass method visible
-    Class<?> classicLoadClass(String name, boolean resolve)
-      throws ClassNotFoundException {
+    Class<?> classicLoadClass(String name, boolean resolve) throws ClassNotFoundException {
       return super.loadClass(name, resolve);
     }
   }
diff --git a/core/src/com/google/inject/internal/CircularDependencyProxy.java b/core/src/com/google/inject/internal/CircularDependencyProxy.java
index fe894a4..dc12748 100644
--- a/core/src/com/google/inject/internal/CircularDependencyProxy.java
+++ b/core/src/com/google/inject/internal/CircularDependencyProxy.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,7 @@
 
 package com.google.inject.internal;
 
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
+/** @author jessewilson@google.com (Jesse Wilson) */
 public interface CircularDependencyProxy {
   // marker interface
 }
diff --git a/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java b/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java
index 8a0c5c6..1c11cfe 100644
--- a/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java
+++ b/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@
 import com.google.inject.binder.ConstantBindingBuilder;
 import com.google.inject.spi.Element;
 import com.google.inject.spi.InjectionPoint;
-
 import java.lang.annotation.Annotation;
 import java.util.List;
 
@@ -32,8 +31,7 @@
  *
  * @author jessewilson@google.com (Jesse Wilson)
  */
-public final class ConstantBindingBuilderImpl<T>
-    extends AbstractBindingBuilder<T>
+public final class ConstantBindingBuilderImpl<T> extends AbstractBindingBuilder<T>
     implements AnnotatedConstantBindingBuilder, ConstantBindingBuilder {
 
   @SuppressWarnings("unchecked") // constant bindings start out with T unknown
@@ -41,56 +39,69 @@
     super(binder, elements, source, (Key<T>) NULL_KEY);
   }
 
+  @Override
   public ConstantBindingBuilder annotatedWith(Class<? extends Annotation> annotationType) {
     annotatedWithInternal(annotationType);
     return this;
   }
 
+  @Override
   public ConstantBindingBuilder annotatedWith(Annotation annotation) {
     annotatedWithInternal(annotation);
     return this;
   }
 
+  @Override
   public void to(final String value) {
     toConstant(String.class, value);
   }
 
+  @Override
   public void to(final int value) {
     toConstant(Integer.class, value);
   }
 
+  @Override
   public void to(final long value) {
     toConstant(Long.class, value);
   }
 
+  @Override
   public void to(final boolean value) {
     toConstant(Boolean.class, value);
   }
 
+  @Override
   public void to(final double value) {
     toConstant(Double.class, value);
   }
 
+  @Override
   public void to(final float value) {
     toConstant(Float.class, value);
   }
 
+  @Override
   public void to(final short value) {
     toConstant(Short.class, value);
   }
 
+  @Override
   public void to(final char value) {
     toConstant(Character.class, value);
   }
 
+  @Override
   public void to(final byte value) {
     toConstant(Byte.class, value);
-  }  
+  }
 
+  @Override
   public void to(final Class<?> value) {
     toConstant(Class.class, value);
   }
 
+  @Override
   public <E extends Enum<E>> void to(final E value) {
     toConstant(value.getDeclaringClass(), value);
   }
@@ -121,11 +132,17 @@
       binder.addError(BINDING_TO_NULL);
     }
 
-    setBinding(new InstanceBindingImpl<T>(
-        base.getSource(), key, base.getScoping(), ImmutableSet.<InjectionPoint>of(), instanceAsT));
+    setBinding(
+        new InstanceBindingImpl<T>(
+            base.getSource(),
+            key,
+            base.getScoping(),
+            ImmutableSet.<InjectionPoint>of(),
+            instanceAsT));
   }
 
-  @Override public String toString() {
+  @Override
+  public String toString() {
     return "ConstantBindingBuilder";
   }
-}
\ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/ConstantFactory.java b/core/src/com/google/inject/internal/ConstantFactory.java
index 633d5de..d932003 100644
--- a/core/src/com/google/inject/internal/ConstantFactory.java
+++ b/core/src/com/google/inject/internal/ConstantFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,10 @@
 
 package com.google.inject.internal;
 
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.inject.spi.Dependency;
 
-/**
- * @author crazybob@google.com (Bob Lee)
- */
+/** @author crazybob@google.com (Bob Lee) */
 final class ConstantFactory<T> implements InternalFactory<T> {
 
   private final Initializable<T> initializable;
@@ -30,14 +28,14 @@
     this.initializable = initializable;
   }
 
-  public T get(Errors errors, InternalContext context, Dependency dependency, boolean linked)
-      throws ErrorsException {
-    return initializable.get(errors);
+  @Override
+  public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+      throws InternalProvisionException {
+    return initializable.get();
   }
 
+  @Override
   public String toString() {
-    return Objects.toStringHelper(ConstantFactory.class)
-        .add("value", initializable)
-        .toString();
+    return MoreObjects.toStringHelper(ConstantFactory.class).add("value", initializable).toString();
   }
 }
diff --git a/core/src/com/google/inject/internal/ConstructionContext.java b/core/src/com/google/inject/internal/ConstructionContext.java
index ced388f..25786f5 100644
--- a/core/src/com/google/inject/internal/ConstructionContext.java
+++ b/core/src/com/google/inject/internal/ConstructionContext.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
 package com.google.inject.internal;
 
 import com.google.inject.internal.InjectorImpl.InjectorOptions;
-
 import java.lang.reflect.Proxy;
 import java.util.ArrayList;
 import java.util.List;
@@ -59,28 +58,31 @@
     invocationHandlers = null;
   }
 
-  public Object createProxy(Errors errors, InjectorOptions injectorOptions,
-      Class<?> expectedType) throws ErrorsException {
+  public Object createProxy(InjectorOptions injectorOptions, Class<?> expectedType)
+      throws InternalProvisionException {
     if (injectorOptions.disableCircularProxies) {
-      throw errors.circularProxiesDisabled(expectedType).toException();
+      throw InternalProvisionException.circularDependenciesDisabled(expectedType);
     }
     if (!expectedType.isInterface()) {
-      throw errors.cannotSatisfyCircularDependency(expectedType).toException();
+      throw InternalProvisionException.cannotProxyClass(expectedType);
     }
 
     if (invocationHandlers == null) {
-      invocationHandlers = new ArrayList<DelegatingInvocationHandler<T>>();
+      invocationHandlers = new ArrayList<>();
     }
 
-    DelegatingInvocationHandler<T> invocationHandler = new DelegatingInvocationHandler<T>();
+    DelegatingInvocationHandler<T> invocationHandler = new DelegatingInvocationHandler<>();
     invocationHandlers.add(invocationHandler);
 
     // TODO: if I create a proxy which implements all the interfaces of
     // the implementation type, I'll be able to get away with one proxy
     // instance (as opposed to one per caller).
     ClassLoader classLoader = BytecodeGen.getClassLoader(expectedType);
-    return expectedType.cast(Proxy.newProxyInstance(classLoader,
-        new Class[] { expectedType, CircularDependencyProxy.class }, invocationHandler));
+    return expectedType.cast(
+        Proxy.newProxyInstance(
+            classLoader,
+            new Class[] {expectedType, CircularDependencyProxy.class},
+            invocationHandler));
   }
 
   public void setProxyDelegates(T delegate) {
diff --git a/core/src/com/google/inject/internal/ConstructionProxy.java b/core/src/com/google/inject/internal/ConstructionProxy.java
index 6c6f3fc..2f56cf0 100644
--- a/core/src/com/google/inject/internal/ConstructionProxy.java
+++ b/core/src/com/google/inject/internal/ConstructionProxy.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,28 +18,22 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.inject.spi.InjectionPoint;
-
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.List;
 
 /**
- * Proxies calls to a {@link java.lang.reflect.Constructor} for a class
- * {@code T}.
+ * Proxies calls to a {@link java.lang.reflect.Constructor} for a class {@code T}.
  *
  * @author crazybob@google.com (Bob Lee)
  */
 interface ConstructionProxy<T> {
 
-  /**
-   * Constructs an instance of {@code T} for the given arguments.
-   */
+  /** Constructs an instance of {@code T} for the given arguments. */
   T newInstance(Object... arguments) throws InvocationTargetException;
 
-  /**
-   * Returns the injection point for this constructor.
-   */
+  /** Returns the injection point for this constructor. */
   InjectionPoint getInjectionPoint();
 
   /**
@@ -49,9 +43,7 @@
   Constructor<T> getConstructor();
 
   /*if[AOP]*/
-  /**
-   * Returns the interceptors applied to each method, in order of invocation.
-   */
+  /** Returns the interceptors applied to each method, in order of invocation. */
   ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>> getMethodInterceptors();
   /*end[AOP]*/
 }
diff --git a/core/src/com/google/inject/internal/ConstructionProxyFactory.java b/core/src/com/google/inject/internal/ConstructionProxyFactory.java
index 0eca0fe..5122524 100644
--- a/core/src/com/google/inject/internal/ConstructionProxyFactory.java
+++ b/core/src/com/google/inject/internal/ConstructionProxyFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,8 +23,6 @@
  */
 interface ConstructionProxyFactory<T> {
 
-  /**
-   * Gets a construction proxy for the given constructor.
-   */
+  /** Gets a construction proxy for the given constructor. */
   ConstructionProxy<T> create() throws ErrorsException;
 }
diff --git a/core/src/com/google/inject/internal/ConstructorBindingImpl.java b/core/src/com/google/inject/internal/ConstructorBindingImpl.java
index 8fb2103..d141d65 100644
--- a/core/src/com/google/inject/internal/ConstructorBindingImpl.java
+++ b/core/src/com/google/inject/internal/ConstructorBindingImpl.java
@@ -19,6 +19,7 @@
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.inject.internal.Annotations.findScopeAnnotation;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableSet;
 import com.google.inject.Binder;
@@ -31,7 +32,6 @@
 import com.google.inject.spi.ConstructorBinding;
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.InjectionPoint;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
@@ -46,44 +46,60 @@
   private final Factory<T> factory;
   private final InjectionPoint constructorInjectionPoint;
 
-  private ConstructorBindingImpl(InjectorImpl injector, Key<T> key, Object source,
-      InternalFactory<? extends T> scopedFactory, Scoping scoping, Factory<T> factory,
+  private ConstructorBindingImpl(
+      InjectorImpl injector,
+      Key<T> key,
+      Object source,
+      InternalFactory<? extends T> scopedFactory,
+      Scoping scoping,
+      Factory<T> factory,
       InjectionPoint constructorInjectionPoint) {
     super(injector, key, source, scopedFactory, scoping);
     this.factory = factory;
     this.constructorInjectionPoint = constructorInjectionPoint;
   }
 
-  public ConstructorBindingImpl(Key<T> key, Object source, Scoping scoping,
-      InjectionPoint constructorInjectionPoint, Set<InjectionPoint> injectionPoints) {
+  public ConstructorBindingImpl(
+      Key<T> key,
+      Object source,
+      Scoping scoping,
+      InjectionPoint constructorInjectionPoint,
+      Set<InjectionPoint> injectionPoints) {
     super(source, key, scoping);
-    this.factory = new Factory<T>(false, key);
-    ConstructionProxy<T> constructionProxy
-        = new DefaultConstructionProxyFactory<T>(constructorInjectionPoint).create();
+    this.factory = new Factory<>(false, key);
+    ConstructionProxy<T> constructionProxy =
+        new DefaultConstructionProxyFactory<T>(constructorInjectionPoint).create();
     this.constructorInjectionPoint = constructorInjectionPoint;
-    factory.constructorInjector = new ConstructorInjector<T>(
-        injectionPoints, constructionProxy, null, null);
+    factory.constructorInjector =
+        new ConstructorInjector<T>(injectionPoints, constructionProxy, null, null);
   }
 
   /**
    * @param constructorInjector the constructor to use, or {@code null} to use the default.
-   * @param failIfNotLinked true if this ConstructorBindingImpl's InternalFactory should
-   *                             only succeed if retrieved from a linked binding
+   * @param failIfNotLinked true if this ConstructorBindingImpl's InternalFactory should only
+   *     succeed if retrieved from a linked binding
    */
-  static <T> ConstructorBindingImpl<T> create(InjectorImpl injector, Key<T> key,
-      InjectionPoint constructorInjector, Object source, Scoping scoping, Errors errors,
-      boolean failIfNotLinked, boolean failIfNotExplicit)
+  static <T> ConstructorBindingImpl<T> create(
+      InjectorImpl injector,
+      Key<T> key,
+      InjectionPoint constructorInjector,
+      Object source,
+      Scoping scoping,
+      Errors errors,
+      boolean failIfNotLinked,
+      boolean failIfNotExplicit)
       throws ErrorsException {
     int numErrors = errors.size();
 
     @SuppressWarnings("unchecked") // constructorBinding guarantees type is consistent
-    Class<? super T> rawType = constructorInjector == null
-        ? key.getTypeLiteral().getRawType()
-        : (Class) constructorInjector.getDeclaringType().getRawType();
+    Class<? super T> rawType =
+        constructorInjector == null
+            ? key.getTypeLiteral().getRawType()
+            : (Class) constructorInjector.getDeclaringType().getRawType();
 
     // We can't inject abstract classes.
     if (Modifier.isAbstract(rawType.getModifiers())) {
-      errors.missingImplementation(key);
+      errors.missingImplementationWithHint(key, injector);
     }
 
     // Error: Inner class.
@@ -110,16 +126,17 @@
       Class<?> annotatedType = constructorInjector.getMember().getDeclaringClass();
       Class<? extends Annotation> scopeAnnotation = findScopeAnnotation(errors, annotatedType);
       if (scopeAnnotation != null) {
-        scoping = Scoping.makeInjectable(Scoping.forAnnotation(scopeAnnotation),
-            injector, errors.withSource(rawType));
+        scoping =
+            Scoping.makeInjectable(
+                Scoping.forAnnotation(scopeAnnotation), injector, errors.withSource(rawType));
       }
     }
 
     errors.throwIfNewErrors(numErrors);
 
-    Factory<T> factoryFactory = new Factory<T>(failIfNotLinked, key);
-    InternalFactory<? extends T> scopedFactory
-        = Scoping.scope(key, injector, factoryFactory, source, scoping);
+    Factory<T> factoryFactory = new Factory<>(failIfNotLinked, key);
+    InternalFactory<? extends T> scopedFactory =
+        Scoping.scope(key, injector, factoryFactory, source, scoping);
 
     return new ConstructorBindingImpl<T>(
         injector, key, source, scopedFactory, scoping, factoryFactory, constructorInjector);
@@ -131,12 +148,12 @@
         || cxtor.isAnnotationPresent(javax.inject.Inject.class);
   }
 
+  @Override
   @SuppressWarnings("unchecked") // the result type always agrees with the ConstructorInjector type
   public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
     factory.constructorInjector =
         (ConstructorInjector<T>) injector.constructors.get(constructorInjectionPoint, errors);
-    factory.provisionCallback =
-      injector.provisionListenerStore.get(this);
+    factory.provisionCallback = injector.provisionListenerStore.get(this);
   }
 
   /** True if this binding has been initialized and is ready for use. */
@@ -146,7 +163,7 @@
 
   /** Returns an injection point that can be used to clean up the constructor store. */
   InjectionPoint getInternalConstructor() {
-    if(factory.constructorInjector != null) {
+    if (factory.constructorInjector != null) {
       return factory.constructorInjector.getConstructionProxy().getInjectionPoint();
     } else {
       return constructorInjectionPoint;
@@ -156,69 +173,87 @@
   /** Returns a set of dependencies that can be iterated over to clean up stray JIT bindings. */
   Set<Dependency<?>> getInternalDependencies() {
     ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
-    if(factory.constructorInjector == null) {
+    if (factory.constructorInjector == null) {
       builder.add(constructorInjectionPoint);
       // If the below throws, it's OK -- we just ignore those dependencies, because no one
       // could have used them anyway.
       try {
-        builder.addAll(InjectionPoint.forInstanceMethodsAndFields(constructorInjectionPoint.getDeclaringType()));
-      } catch(ConfigurationException ignored) {}
+        builder.addAll(
+            InjectionPoint.forInstanceMethodsAndFields(
+                constructorInjectionPoint.getDeclaringType()));
+      } catch (ConfigurationException ignored) {
+      }
     } else {
-      builder.add(getConstructor())
-             .addAll(getInjectableMembers());
+      builder.add(getConstructor()).addAll(getInjectableMembers());
     }
 
     return Dependency.forInjectionPoints(builder.build());
   }
 
+  @Override
   public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
     checkState(factory.constructorInjector != null, "not initialized");
     return visitor.visit(this);
   }
 
+  @Override
   public InjectionPoint getConstructor() {
     checkState(factory.constructorInjector != null, "Binding is not ready");
     return factory.constructorInjector.getConstructionProxy().getInjectionPoint();
   }
 
+  @Override
   public Set<InjectionPoint> getInjectableMembers() {
     checkState(factory.constructorInjector != null, "Binding is not ready");
     return factory.constructorInjector.getInjectableMembers();
   }
 
   /*if[AOP]*/
+  @Override
   public Map<Method, List<org.aopalliance.intercept.MethodInterceptor>> getMethodInterceptors() {
     checkState(factory.constructorInjector != null, "Binding is not ready");
     return factory.constructorInjector.getConstructionProxy().getMethodInterceptors();
   }
   /*end[AOP]*/
 
+  @Override
   public Set<Dependency<?>> getDependencies() {
-    return Dependency.forInjectionPoints(new ImmutableSet.Builder<InjectionPoint>()
-        .add(getConstructor())
-        .addAll(getInjectableMembers())
-        .build());
+    return Dependency.forInjectionPoints(
+        new ImmutableSet.Builder<InjectionPoint>()
+            .add(getConstructor())
+            .addAll(getInjectableMembers())
+            .build());
   }
 
-  @Override protected BindingImpl<T> withScoping(Scoping scoping) {
+  @Override
+  protected BindingImpl<T> withScoping(Scoping scoping) {
     return new ConstructorBindingImpl<T>(
         null, getKey(), getSource(), factory, scoping, factory, constructorInjectionPoint);
   }
 
-  @Override protected BindingImpl<T> withKey(Key<T> key) {
+  @Override
+  protected BindingImpl<T> withKey(Key<T> key) {
     return new ConstructorBindingImpl<T>(
         null, key, getSource(), factory, getScoping(), factory, constructorInjectionPoint);
   }
 
+  @Override
   @SuppressWarnings("unchecked") // the raw constructor member and declaring type always agree
   public void applyTo(Binder binder) {
     InjectionPoint constructor = getConstructor();
-    getScoping().applyTo(binder.withSource(getSource()).bind(getKey()).toConstructor(
-        (Constructor) getConstructor().getMember(), (TypeLiteral) constructor.getDeclaringType()));
+    getScoping()
+        .applyTo(
+            binder
+                .withSource(getSource())
+                .bind(getKey())
+                .toConstructor(
+                    (Constructor) getConstructor().getMember(),
+                    (TypeLiteral) constructor.getDeclaringType()));
   }
 
-  @Override public String toString() {
-    return Objects.toStringHelper(ConstructorBinding.class)
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(ConstructorBinding.class)
         .add("key", getKey())
         .add("source", getSource())
         .add("scope", getScoping())
@@ -227,11 +262,11 @@
 
   @Override
   public boolean equals(Object obj) {
-    if(obj instanceof ConstructorBindingImpl) {
-      ConstructorBindingImpl<?> o = (ConstructorBindingImpl<?>)obj;
+    if (obj instanceof ConstructorBindingImpl) {
+      ConstructorBindingImpl<?> o = (ConstructorBindingImpl<?>) obj;
       return getKey().equals(o.getKey())
-        && getScoping().equals(o.getScoping())
-        && Objects.equal(constructorInjectionPoint, o.constructorInjectionPoint);
+          && getScoping().equals(o.getScoping())
+          && Objects.equal(constructorInjectionPoint, o.constructorInjectionPoint);
     } else {
       return false;
     }
@@ -253,19 +288,22 @@
       this.key = key;
     }
 
+    @Override
     @SuppressWarnings("unchecked")
-    public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
-        throws ErrorsException {
-      checkState(constructorInjector != null, "Constructor not ready");
+    public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+        throws InternalProvisionException {
+      ConstructorInjector<T> localInjector = constructorInjector;
+      if (localInjector == null) {
+        throw new IllegalStateException("Constructor not ready");
+      }
 
-      if(failIfNotLinked && !linked) {
-        throw errors.jitDisabled(key).toException();
+      if (!linked && failIfNotLinked) {
+        throw InternalProvisionException.jitDisabled(key);
       }
 
       // This may not actually be safe because it could return a super type of T (if that's all the
       // client needs), but it should be OK in practice thanks to the wonders of erasure.
-      return (T) constructorInjector.construct(errors, context,
-          dependency.getKey().getTypeLiteral().getRawType(), provisionCallback);
+      return (T) localInjector.construct(context, dependency, provisionCallback);
     }
   }
 }
diff --git a/core/src/com/google/inject/internal/ConstructorInjector.java b/core/src/com/google/inject/internal/ConstructorInjector.java
index 1ff4be1..13e1147 100644
--- a/core/src/com/google/inject/internal/ConstructorInjector.java
+++ b/core/src/com/google/inject/internal/ConstructorInjector.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback;
+import com.google.inject.spi.Dependency;
 import com.google.inject.spi.InjectionPoint;
-
 import java.lang.reflect.InvocationTargetException;
 import java.util.Set;
 
@@ -36,7 +36,8 @@
   private final ConstructionProxy<T> constructionProxy;
   private final MembersInjectorImpl<T> membersInjector;
 
-  ConstructorInjector(Set<InjectionPoint> injectableMembers,
+  ConstructorInjector(
+      Set<InjectionPoint> injectableMembers,
       ConstructionProxy<T> constructionProxy,
       SingleParameterInjector<?>[] parameterInjectors,
       MembersInjectorImpl<T> membersInjector) {
@@ -55,40 +56,48 @@
   }
 
   /**
-   * Construct an instance. Returns {@code Object} instead of {@code T} because
-   * it may return a proxy.
+   * Construct an instance. Returns {@code Object} instead of {@code T} because it may return a
+   * proxy.
    */
-  Object construct(final Errors errors, final InternalContext context,
-      Class<?> expectedType,
-      ProvisionListenerStackCallback<T> provisionCallback)
-      throws ErrorsException {
+  Object construct(
+      final InternalContext context,
+      Dependency<?> dependency,
+      /* @Nullable */ ProvisionListenerStackCallback<T> provisionCallback)
+      throws InternalProvisionException {
     final ConstructionContext<T> constructionContext = context.getConstructionContext(this);
-
     // We have a circular reference between constructors. Return a proxy.
     if (constructionContext.isConstructing()) {
       // TODO (crazybob): if we can't proxy this object, can we proxy the other object?
       return constructionContext.createProxy(
-          errors, context.getInjectorOptions(), expectedType);
+          context.getInjectorOptions(), dependency.getKey().getTypeLiteral().getRawType());
     }
 
     // If we're re-entering this factory while injecting fields or methods,
     // return the same instance. This prevents infinite loops.
     T t = constructionContext.getCurrentReference();
     if (t != null) {
-      return t;
+      if (context.getInjectorOptions().disableCircularProxies) {
+        throw InternalProvisionException.circularDependenciesDisabled(
+            dependency.getKey().getTypeLiteral().getRawType());
+      } else {
+        return t;
+      }
     }
 
     constructionContext.startConstruction();
     try {
       // Optimization: Don't go through the callback stack if we have no listeners.
-      if (!provisionCallback.hasListeners()) {
-        return provision(errors, context, constructionContext);
+      if (provisionCallback == null) {
+        return provision(context, constructionContext);
       } else {
-        return provisionCallback.provision(errors, context, new ProvisionCallback<T>() {
-          public T call() throws ErrorsException {
-            return provision(errors, context, constructionContext);
-          }
-        });
+        return provisionCallback.provision(
+            context,
+            new ProvisionCallback<T>() {
+              @Override
+              public T call() throws InternalProvisionException {
+                return provision(context, constructionContext);
+              }
+            });
       }
     } finally {
       constructionContext.finishConstruction();
@@ -96,12 +105,12 @@
   }
 
   /** Provisions a new T. */
-  private T provision(Errors errors, InternalContext context,
-      ConstructionContext<T> constructionContext) throws ErrorsException {
+  private T provision(InternalContext context, ConstructionContext<T> constructionContext)
+      throws InternalProvisionException {
     try {
       T t;
       try {
-        Object[] parameters = SingleParameterInjector.getAll(errors, context, parameterInjectors);
+        Object[] parameters = SingleParameterInjector.getAll(context, parameterInjectors);
         t = constructionProxy.newInstance(parameters);
         constructionContext.setProxyDelegates(t);
       } finally {
@@ -111,16 +120,15 @@
       // Store reference. If an injector re-enters this factory, they'll get the same reference.
       constructionContext.setCurrentReference(t);
 
-      membersInjector.injectMembers(t, errors, context, false);
-      membersInjector.notifyListeners(t, errors);
+      MembersInjectorImpl<T> localMembersInjector = membersInjector;
+      localMembersInjector.injectMembers(t, context, false);
+      localMembersInjector.notifyListeners(t);
 
       return t;
     } catch (InvocationTargetException userException) {
-      Throwable cause = userException.getCause() != null
-          ? userException.getCause()
-          : userException;
-      throw errors.withSource(constructionProxy.getInjectionPoint())
-          .errorInjectingConstructor(cause).toException();
+      Throwable cause = userException.getCause() != null ? userException.getCause() : userException;
+      throw InternalProvisionException.errorInjectingConstructor(cause)
+          .addSource(constructionProxy.getInjectionPoint());
     } finally {
       constructionContext.removeCurrentReference();
     }
diff --git a/core/src/com/google/inject/internal/ConstructorInjectorStore.java b/core/src/com/google/inject/internal/ConstructorInjectorStore.java
index b8e4867..eb17a54 100644
--- a/core/src/com/google/inject/internal/ConstructorInjectorStore.java
+++ b/core/src/com/google/inject/internal/ConstructorInjectorStore.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,35 +29,33 @@
 final class ConstructorInjectorStore {
   private final InjectorImpl injector;
 
-  private final FailableCache<InjectionPoint, ConstructorInjector<?>>  cache
-      = new FailableCache<InjectionPoint, ConstructorInjector<?>> () {
-    @Override
-    protected ConstructorInjector<?> create(InjectionPoint constructorInjector, Errors errors)
-        throws ErrorsException {
-      return createConstructor(constructorInjector, errors);
-    }
-  };
+  private final FailableCache<InjectionPoint, ConstructorInjector<?>> cache =
+      new FailableCache<InjectionPoint, ConstructorInjector<?>>() {
+        @Override
+        protected ConstructorInjector<?> create(InjectionPoint constructorInjector, Errors errors)
+            throws ErrorsException {
+          return createConstructor(constructorInjector, errors);
+        }
+      };
 
   ConstructorInjectorStore(InjectorImpl injector) {
     this.injector = injector;
   }
 
-  /**
-   * Returns a new complete constructor injector with injection listeners registered.
-   */
+  /** Returns a new complete constructor injector with injection listeners registered. */
   public ConstructorInjector<?> get(InjectionPoint constructorInjector, Errors errors)
       throws ErrorsException {
     return cache.get(constructorInjector, errors);
   }
-  
+
   /**
    * Purges an injection point from the cache. Use this only if the cache is not actually valid and
    * needs to be purged. (See issue 319 and
    * ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and
    * #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is
    * necessary.)
-   * 
-   * Returns true if the injector for that point was stored in the cache, false otherwise.
+   *
+   * <p>Returns true if the injector for that point was stored in the cache, false otherwise.
    */
   boolean remove(InjectionPoint ip) {
     return cache.remove(ip);
@@ -67,27 +65,32 @@
       throws ErrorsException {
     int numErrorsBefore = errors.size();
 
-    SingleParameterInjector<?>[] constructorParameterInjectors
-        = injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
+    SingleParameterInjector<?>[] constructorParameterInjectors =
+        injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
 
     @SuppressWarnings("unchecked") // the injector type agrees with the injection point type
-    MembersInjectorImpl<T> membersInjector = (MembersInjectorImpl<T>) injector.membersInjectorStore
-        .get(injectionPoint.getDeclaringType(), errors);
+    MembersInjectorImpl<T> membersInjector =
+        (MembersInjectorImpl<T>)
+            injector.membersInjectorStore.get(injectionPoint.getDeclaringType(), errors);
 
     /*if[AOP]*/
     ImmutableList<MethodAspect> injectorAspects = injector.state.getMethodAspects();
-    ImmutableList<MethodAspect> methodAspects = membersInjector.getAddedAspects().isEmpty()
-        ? injectorAspects
-        : ImmutableList.copyOf(concat(injectorAspects, membersInjector.getAddedAspects()));
-    ConstructionProxyFactory<T> factory = new ProxyFactory<T>(injectionPoint, methodAspects);
+    ImmutableList<MethodAspect> methodAspects =
+        membersInjector.getAddedAspects().isEmpty()
+            ? injectorAspects
+            : ImmutableList.copyOf(concat(injectorAspects, membersInjector.getAddedAspects()));
+    ConstructionProxyFactory<T> factory = new ProxyFactory<>(injectionPoint, methodAspects);
     /*end[AOP]*/
     /*if[NO_AOP]
-    ConstructionProxyFactory<T> factory = new DefaultConstructionProxyFactory<T>(injectionPoint);
+    ConstructionProxyFactory<T> factory = new DefaultConstructionProxyFactory<>(injectionPoint);
     end[NO_AOP]*/
 
     errors.throwIfNewErrors(numErrorsBefore);
 
-    return new ConstructorInjector<T>(membersInjector.getInjectionPoints(), factory.create(),
-        constructorParameterInjectors, membersInjector);
+    return new ConstructorInjector<T>(
+        membersInjector.getInjectionPoints(),
+        factory.create(),
+        constructorParameterInjectors,
+        membersInjector);
   }
 }
diff --git a/core/src/com/google/inject/internal/ContextualCallable.java b/core/src/com/google/inject/internal/ContextualCallable.java
deleted file mode 100644
index 56c0630..0000000
--- a/core/src/com/google/inject/internal/ContextualCallable.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * 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;
-
-/**
- * @author crazybob@google.com (Bob Lee)
- */
-interface ContextualCallable<T> {
-  T call(InternalContext context) throws ErrorsException;
-}
diff --git a/core/src/com/google/inject/internal/CreationListener.java b/core/src/com/google/inject/internal/CreationListener.java
index 1779204..53a61ee 100644
--- a/core/src/com/google/inject/internal/CreationListener.java
+++ b/core/src/com/google/inject/internal/CreationListener.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,4 +21,4 @@
 
   /** Notifies that creation should happen. */
   void notify(Errors errors);
-}
\ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/CycleDetectingLock.java b/core/src/com/google/inject/internal/CycleDetectingLock.java
index 690b151..7b387b0 100644
--- a/core/src/com/google/inject/internal/CycleDetectingLock.java
+++ b/core/src/com/google/inject/internal/CycleDetectingLock.java
@@ -2,7 +2,6 @@
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Supplier;
-import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableListMultimap;
 import com.google.common.collect.LinkedHashMultimap;
 import com.google.common.collect.ListMultimap;
@@ -10,7 +9,6 @@
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multimaps;
-
 import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -21,166 +19,174 @@
 /**
  * Simplified version of {@link Lock} that is special due to how it handles deadlocks detection.
  *
- * <p>Is an inherent part of {@link SingletonScope}, moved into a upper level class due
- * to its size and complexity.
+ * <p>Is an inherent part of {@link SingletonScope}, moved into a upper level class due to its size
+ * and complexity.
  *
- * @param <ID> Lock identification provided by the client, is returned unmodified to the client
- *        when lock cycle is detected to identify it. Only toString() needs to be implemented.
- *        Lock references this object internally,
- *        for the purposes of Garbage Collection you should not use heavy IDs.
- *        Lock is referenced by a lock factory as long as it's owned by a thread.
- *
+ * @param <ID> Lock identification provided by the client, is returned unmodified to the client when
+ *     lock cycle is detected to identify it. Only toString() needs to be implemented. Lock
+ *     references this object internally, for the purposes of Garbage Collection you should not use
+ *     heavy IDs. Lock is referenced by a lock factory as long as it's owned by a thread.
  * @see SingletonScope
  * @see com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory
- *
  * @author timofeyb (Timothy Basanov)
  */
 interface CycleDetectingLock<ID> {
 
   /**
-   * Takes a lock in a blocking fashion in case no potential deadlocks are detected.
-   * If the lock was successfully owned, returns an empty map indicating no detected potential
-   * deadlocks.
+   * Takes a lock in a blocking fashion in case no potential deadlocks are detected. If the lock was
+   * successfully owned, returns an empty map indicating no detected potential deadlocks.
    *
-   * Otherwise, a map indicating threads involved in a potential deadlock are returned.
-   * Map is ordered by dependency cycle and lists locks for each thread that are part of
-   * the loop in order. Returned map is created atomically.
+   * <p>Otherwise, a map indicating threads involved in a potential deadlock are returned. Map is
+   * ordered by dependency cycle and lists locks for each thread that are part of the loop in order,
+   * the last lock in the list is the one that the thread is currently waiting for. Returned map is
+   * created atomically.
    *
-   * In case no cycle is detected performance is O(threads creating singletons),
-   * in case cycle is detected performance is O(singleton locks).
+   * <p>In case no cycle is detected performance is O(threads creating singletons), in case cycle is
+   * detected performance is O(singleton locks).
    */
-  ListMultimap<Long, ID> lockOrDetectPotentialLocksCycle();
+  ListMultimap<Thread, ID> lockOrDetectPotentialLocksCycle();
 
-  /**
-   * Unlocks previously locked lock.
-   */
+  /** Unlocks previously locked lock. */
   void unlock();
 
   /**
-   * Wraps locks so they would never cause a deadlock. On each
-   * {@link CycleDetectingLock#lockOrDetectPotentialLocksCycle} we check for dependency cycles
-   * within locks created by the same factory. Either we detect a cycle and return it
-   * or take it atomically.
+   * Wraps locks so they would never cause a deadlock. On each {@link
+   * CycleDetectingLock#lockOrDetectPotentialLocksCycle} we check for dependency cycles within locks
+   * created by the same factory. Either we detect a cycle and return it or take it atomically.
    *
-   * <p>Important to note that we do not prevent deadlocks in the client code. As an example:
-   * Thread A takes lock L and creates singleton class CA depending on the singleton class CB.
-   * Meanwhile thread B is creating class CB and is waiting on the lock L. Issue happens
-   * due to client code creating interdependent classes and using locks, where
-   * no guarantees on the creation order from Guice are provided.
+   * <p>Important to note that we do not prevent deadlocks in the client code. As an example: Thread
+   * A takes lock L and creates singleton class CA depending on the singleton class CB. Meanwhile
+   * thread B is creating class CB and is waiting on the lock L. Issue happens due to client code
+   * creating interdependent classes and using locks, where no guarantees on the creation order from
+   * Guice are provided.
    *
    * <p>Instances of these locks are not intended to be exposed outside of {@link SingletonScope}.
    */
   class CycleDetectingLockFactory<ID> {
 
     /**
-     * Specifies lock that thread is currently waiting on to own it.
-     * Used only for purposes of locks cycle detection.
+     * Specifies lock that thread is currently waiting on to own it. Used only for purposes of locks
+     * cycle detection.
      *
-     * Key: thread id
-     * Value: lock that is being waited on
+     * <ul>
+     * <li>Key: thread
+     * <li> Value: lock that is being waited on
+     * </ul>
      *
-     * Element is added inside {@link #lockOrDetectPotentialLocksCycle()} before {@link Lock#lock}
-     * is called. Element is removed inside {@link #lockOrDetectPotentialLocksCycle()} after
-     * {@link Lock#lock} and synchronously with adding it to {@link #locksOwnedByThread}.
+     * <p>Element is added inside {@link #lockOrDetectPotentialLocksCycle()} before {@link
+     * Lock#lock} is called. Element is removed inside {@link #lockOrDetectPotentialLocksCycle()}
+     * after {@link Lock#lock} and synchronously with adding it to {@link #locksOwnedByThread}.
      *
-     * Same lock can be added for several threads in case all of them are trying to
-     * take it.
+     * <p>Same lock can be added for several threads in case all of them are trying to take it.
      *
-     * Guarded by {@code this}.
+     * <p>Guarded by {@code CycleDetectingLockFactory.class}.
      */
-    private Map<Long, ReentrantCycleDetectingLock> lockThreadIsWaitingOn = Maps.newHashMap();
+    private static Map<Thread, ReentrantCycleDetectingLock<?>> lockThreadIsWaitingOn =
+        Maps.newHashMap();
 
     /**
-     * Lists locks that thread owns.
-     * Used only to populate locks in a potential cycle when it is detected.
+     * Lists locks that thread owns. Used only to populate locks in a potential cycle when it is
+     * detected.
      *
-     * Key: thread id
-     * Value: stack of locks that were owned.
+     * <ul>
+     * <li>Key: thread
+     * <li>Value: stack of locks that were owned.
+     * </ul>
      *
-     * Element is added inside {@link #lockOrDetectPotentialLocksCycle()} after {@link Lock#lock}
-     * is called. Element is removed inside {@link #unlock()} synchronously with
-     * {@link Lock#unlock()} call.
+     * <p>Element is added inside {@link #lockOrDetectPotentialLocksCycle()} after {@link Lock#lock}
+     * is called. Element is removed inside {@link #unlock()} synchronously with {@link
+     * Lock#unlock()} call.
      *
-     * Same lock can only be present several times for the same thread as locks are
-     * reentrant. Lock can not be owned by several different threads as the same time.
+     * <p>Same lock can only be present several times for the same thread as locks are reentrant.
+     * Lock can not be owned by several different threads as the same time.
      *
-     * Guarded by {@code this}.
+     * <p>Guarded by {@code CycleDetectingLockFactory.class}.
      */
-    private final Multimap<Long, ReentrantCycleDetectingLock> locksOwnedByThread =
+    private static final Multimap<Thread, ReentrantCycleDetectingLock<?>> locksOwnedByThread =
         LinkedHashMultimap.create();
 
     /**
-     * Creates new lock within this factory context. We can guarantee that locks created by
-     * the same factory would not deadlock.
+     * Creates new lock within this factory context. We can guarantee that locks created by the same
+     * factory would not deadlock.
      *
-     * @param newLockId lock id that would be used to report lock cycles if detected
+     * @param userLockId lock id that would be used to report lock cycles if detected
      */
-    CycleDetectingLock<ID> create(ID newLockId) {
-      return new ReentrantCycleDetectingLock(newLockId, new ReentrantLock());
+    CycleDetectingLock<ID> create(ID userLockId) {
+      return new ReentrantCycleDetectingLock<ID>(this, userLockId, new ReentrantLock());
     }
 
     /** The implementation for {@link CycleDetectingLock}. */
-    class ReentrantCycleDetectingLock implements CycleDetectingLock<ID> {
+    static class ReentrantCycleDetectingLock<ID> implements CycleDetectingLock<ID> {
 
       /** Underlying lock used for actual waiting when no potential deadlocks are detected. */
       private final Lock lockImplementation;
       /** User id for this lock. */
       private final ID userLockId;
+      /** Factory that was used to create this lock. */
+      private final CycleDetectingLockFactory<ID> lockFactory;
       /**
-       * Thread id for the thread that owned this lock. Nullable.
-       * Guarded by {@code CycleDetectingLockFactory.this}.
+       * Thread that owns this lock. Nullable. Guarded by {@code CycleDetectingLockFactory.this}.
        */
-      private Long lockOwnerThreadId = null;
+      private Thread lockOwnerThread = null;
+
       /**
-       * Number of times that thread owned this lock.
-       * Guarded by {@code CycleDetectingLockFactory.this}.
+       * Number of times that thread owned this lock. Guarded by {@code
+       * CycleDetectingLockFactory.this}.
        */
       private int lockReentranceCount = 0;
 
-      ReentrantCycleDetectingLock(ID userLockId, Lock lockImplementation) {
+      ReentrantCycleDetectingLock(
+          CycleDetectingLockFactory<ID> lockFactory, ID userLockId, Lock lockImplementation) {
+        this.lockFactory = lockFactory;
         this.userLockId = Preconditions.checkNotNull(userLockId, "userLockId");
-        this.lockImplementation = Preconditions.checkNotNull(
-            lockImplementation, "lockImplementation");
+        this.lockImplementation =
+            Preconditions.checkNotNull(lockImplementation, "lockImplementation");
       }
 
-      @Override public ListMultimap<Long, ID> lockOrDetectPotentialLocksCycle() {
-        final long currentThreadId = Thread.currentThread().getId();
-        synchronized (CycleDetectingLockFactory.this) {
+      @Override
+      public ListMultimap<Thread, ID> lockOrDetectPotentialLocksCycle() {
+        final Thread currentThread = Thread.currentThread();
+        synchronized (CycleDetectingLockFactory.class) {
           checkState();
-          ListMultimap<Long, ID> locksInCycle = detectPotentialLocksCycle();
+          // Add this lock to the waiting map to ensure it is included in any reported lock cycle.
+          lockThreadIsWaitingOn.put(currentThread, this);
+          ListMultimap<Thread, ID> locksInCycle = detectPotentialLocksCycle();
           if (!locksInCycle.isEmpty()) {
+            // We aren't actually going to wait for this lock, so remove it from the map.
+            lockThreadIsWaitingOn.remove(currentThread);
             // potential deadlock is found, we don't try to take this lock
             return locksInCycle;
           }
 
-          lockThreadIsWaitingOn.put(currentThreadId, this);
         }
 
         // this may be blocking, but we don't expect it to cause a deadlock
         lockImplementation.lock();
 
-        synchronized (CycleDetectingLockFactory.this) {
+        synchronized (CycleDetectingLockFactory.class) {
           // current thread is no longer waiting on this lock
-          lockThreadIsWaitingOn.remove(currentThreadId);
+          lockThreadIsWaitingOn.remove(currentThread);
           checkState();
 
           // mark it as owned by us
-          lockOwnerThreadId = currentThreadId;
+          lockOwnerThread = currentThread;
           lockReentranceCount++;
           // add this lock to the list of locks owned by a current thread
-          locksOwnedByThread.put(currentThreadId, this);
+          locksOwnedByThread.put(currentThread, this);
         }
         // no deadlock is found, locking successful
         return ImmutableListMultimap.of();
       }
 
-      @Override public void unlock() {
-        final long currentThreadId = Thread.currentThread().getId();
-        synchronized (CycleDetectingLockFactory.this) {
+      @Override
+      public void unlock() {
+        final Thread currentThread = Thread.currentThread();
+        synchronized (CycleDetectingLockFactory.class) {
           checkState();
-          Preconditions.checkState(lockOwnerThreadId != null,
-              "Thread is trying to unlock a lock that is not locked");
-          Preconditions.checkState(lockOwnerThreadId == currentThreadId,
+          Preconditions.checkState(
+              lockOwnerThread != null, "Thread is trying to unlock a lock that is not locked");
+          Preconditions.checkState(
+              lockOwnerThread == currentThread,
               "Thread is trying to unlock a lock owned by another thread");
 
           // releasing underlying lock
@@ -190,12 +196,13 @@
           lockReentranceCount--;
           if (lockReentranceCount == 0) {
             // we no longer own this lock
-            lockOwnerThreadId = null;
-            Preconditions.checkState(locksOwnedByThread.remove(currentThreadId, this),
+            lockOwnerThread = null;
+            Preconditions.checkState(
+                locksOwnedByThread.remove(currentThread, this),
                 "Internal error: Can not find this lock in locks owned by a current thread");
-            if (locksOwnedByThread.get(currentThreadId).isEmpty()) {
+            if (locksOwnedByThread.get(currentThread).isEmpty()) {
               // clearing memory
-              locksOwnedByThread.removeAll(currentThreadId);
+              locksOwnedByThread.removeAll(currentThread);
             }
           }
         }
@@ -203,21 +210,26 @@
 
       /** Check consistency of an internal state. */
       void checkState() throws IllegalStateException {
-        final long currentThreadId = Thread.currentThread().getId();
-        Preconditions.checkState(!lockThreadIsWaitingOn.containsKey(currentThreadId),
+        final Thread currentThread = Thread.currentThread();
+        Preconditions.checkState(
+            !lockThreadIsWaitingOn.containsKey(currentThread),
             "Internal error: Thread should not be in a waiting thread on a lock now");
-        if (lockOwnerThreadId != null) {
+        if (lockOwnerThread != null) {
           // check state of a locked lock
-          Preconditions.checkState(lockReentranceCount >= 0,
+          Preconditions.checkState(
+              lockReentranceCount >= 0,
               "Internal error: Lock ownership and reentrance count internal states do not match");
-          Preconditions.checkState(locksOwnedByThread.get(lockOwnerThreadId).contains(this),
+          Preconditions.checkState(
+              locksOwnedByThread.get(lockOwnerThread).contains(this),
               "Internal error: Set of locks owned by a current thread and lock "
                   + "ownership status do not match");
         } else {
           // check state of a non locked lock
-          Preconditions.checkState(lockReentranceCount == 0,
+          Preconditions.checkState(
+              lockReentranceCount == 0,
               "Internal error: Reentrance count of a non locked lock is expect to be zero");
-          Preconditions.checkState(!locksOwnedByThread.values().contains(this),
+          Preconditions.checkState(
+              !locksOwnedByThread.values().contains(this),
               "Internal error: Non locked lock should not be owned by any thread");
         }
       }
@@ -225,76 +237,93 @@
       /**
        * Algorithm to detect a potential lock cycle.
        *
-       * For lock's thread owner check which lock is it trying to take.
-       * Repeat recursively. When current thread is found a potential cycle is detected.
+       * <p>For lock's thread owner check which lock is it trying to take. Repeat recursively. When
+       * current thread is found a potential cycle is detected.
        *
        * @see CycleDetectingLock#lockOrDetectPotentialLocksCycle()
        */
-      private ListMultimap<Long, ID> detectPotentialLocksCycle() {
-        final long currentThreadId = Thread.currentThread().getId();
-        if (lockOwnerThreadId == null || lockOwnerThreadId == currentThreadId) {
+      private ListMultimap<Thread, ID> detectPotentialLocksCycle() {
+        final Thread currentThread = Thread.currentThread();
+        if (lockOwnerThread == null || lockOwnerThread == currentThread) {
           // if nobody owns this lock, lock cycle is impossible
           // if a current thread owns this lock, we let Guice to handle it
           return ImmutableListMultimap.of();
         }
 
-        ListMultimap<Long, ID> potentialLocksCycle = Multimaps.newListMultimap(
-            new LinkedHashMap<Long, Collection<ID>>(),
-            new Supplier<List<ID>>() {
-              @Override
-              public List<ID> get() {
-                return Lists.newArrayList();
-              }
-            });
+        ListMultimap<Thread, ID> potentialLocksCycle =
+            Multimaps.newListMultimap(
+                new LinkedHashMap<Thread, Collection<ID>>(),
+                new Supplier<List<ID>>() {
+                  @Override
+                  public List<ID> get() {
+                    return Lists.newArrayList();
+                  }
+                });
         // lock that is a part of a potential locks cycle, starts with current lock
-        ReentrantCycleDetectingLock lockOwnerWaitingOn = this;
+        ReentrantCycleDetectingLock<?> lockOwnerWaitingOn = this;
         // try to find a dependency path between lock's owner thread and a current thread
-        while (lockOwnerWaitingOn != null && lockOwnerWaitingOn.lockOwnerThreadId != null) {
-          Long threadOwnerThreadWaits = lockOwnerWaitingOn.lockOwnerThreadId;
+        while (lockOwnerWaitingOn != null && lockOwnerWaitingOn.lockOwnerThread != null) {
+          Thread threadOwnerThreadWaits = lockOwnerWaitingOn.lockOwnerThread;
           // in case locks cycle exists lock we're waiting for is part of it
-          potentialLocksCycle.putAll(threadOwnerThreadWaits,
-              getAllLockIdsAfter(threadOwnerThreadWaits, lockOwnerWaitingOn));
-
-          if (threadOwnerThreadWaits == currentThreadId) {
+          lockOwnerWaitingOn =
+              addAllLockIdsAfter(threadOwnerThreadWaits, lockOwnerWaitingOn, potentialLocksCycle);
+          if (threadOwnerThreadWaits == currentThread) {
             // owner thread depends on current thread, cycle detected
             return potentialLocksCycle;
           }
-          // going for the next thread we wait on indirectly
-          lockOwnerWaitingOn = lockThreadIsWaitingOn.get(threadOwnerThreadWaits);
         }
         // no dependency path from an owner thread to a current thread
         return ImmutableListMultimap.of();
       }
 
-      /** Return locks owned by a thread after a lock specified, inclusive. */
-      private List<ID> getAllLockIdsAfter(long threadId, ReentrantCycleDetectingLock lock) {
-        List<ID> ids = Lists.newArrayList();
+      /**
+       * Adds all locks held by the given thread that are after the given lock and then returns the
+       * lock the thread is currently waiting on, if any
+       */
+      private ReentrantCycleDetectingLock<?> addAllLockIdsAfter(
+          Thread thread,
+          ReentrantCycleDetectingLock<?> lock,
+          ListMultimap<Thread, ID> potentialLocksCycle) {
         boolean found = false;
-        Collection<ReentrantCycleDetectingLock> ownedLocks = locksOwnedByThread.get(threadId);
-        Preconditions.checkNotNull(ownedLocks,
-            "Internal error: No locks were found taken by a thread");
-        for (ReentrantCycleDetectingLock ownedLock : ownedLocks) {
+        Collection<ReentrantCycleDetectingLock<?>> ownedLocks = locksOwnedByThread.get(thread);
+        Preconditions.checkNotNull(
+            ownedLocks, "Internal error: No locks were found taken by a thread");
+        for (ReentrantCycleDetectingLock<?> ownedLock : ownedLocks) {
           if (ownedLock == lock) {
             found = true;
           }
-          if (found) {
-            ids.add(ownedLock.userLockId);
+          if (found && ownedLock.lockFactory == this.lockFactory) {
+            // All locks are stored in a shared map therefore there is no way to
+            // enforce type safety. We know that our cast is valid as we check for a lock's
+            // factory. If the lock was generated by the
+            // same factory it has to have same type as the current lock.
+            @SuppressWarnings("unchecked")
+            ID userLockId = (ID) ownedLock.userLockId;
+            potentialLocksCycle.put(thread, userLockId);
           }
         }
-        Preconditions.checkState(found, "Internal error: We can not find locks that "
-            + "created a cycle that we detected");
-        return ids;
+        Preconditions.checkState(
+            found,
+            "Internal error: We can not find locks that created a cycle that we detected");
+        ReentrantCycleDetectingLock<?> unownedLock = lockThreadIsWaitingOn.get(thread);
+        // If this thread is waiting for a lock add it to the cycle and return it
+        if (unownedLock != null && unownedLock.lockFactory == this.lockFactory) {
+          @SuppressWarnings("unchecked")
+          ID typed = (ID) unownedLock.userLockId;
+          potentialLocksCycle.put(thread, typed);
+        }
+        return unownedLock;
       }
 
-      @Override public String toString() {
+      @Override
+      public String toString() {
         // copy is made to prevent a data race
         // no synchronization is used, potentially stale data, should be good enough
-        Long localLockOwnerThreadId = this.lockOwnerThreadId;
-        if (localLockOwnerThreadId != null) {
-          return String.format("CycleDetectingLock[%s][locked by %s]",
-              userLockId, localLockOwnerThreadId);
+        Thread thread = this.lockOwnerThread;
+        if (thread != null) {
+          return String.format("%s[%s][locked by %s]", super.toString(), userLockId, thread);
         } else {
-          return String.format("CycleDetectingLock[%s][unlocked]", userLockId);
+          return String.format("%s[%s][unlocked]", super.toString(), userLockId);
         }
       }
     }
diff --git a/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java b/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java
index 947b49a..d8cfc18 100644
--- a/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java
+++ b/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,9 @@
 
 package com.google.inject.internal;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
-import com.google.inject.internal.BytecodeGen.Visibility;
 import com.google.inject.spi.InjectionPoint;
-
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -35,73 +34,119 @@
 
   private final InjectionPoint injectionPoint;
 
-  /**
-   * @param injectionPoint an injection point whose member is a constructor of {@code T}.
-   */
+  /** @param injectionPoint an injection point whose member is a constructor of {@code T}. */
   DefaultConstructionProxyFactory(InjectionPoint injectionPoint) {
     this.injectionPoint = injectionPoint;
   }
 
+  @Override
   public ConstructionProxy<T> create() {
     @SuppressWarnings("unchecked") // the injection point is for a constructor of T
     final Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember();
 
-    // Use FastConstructor if the constructor is public.
-    if (Modifier.isPublic(constructor.getModifiers())) {
-      Class<T> classToConstruct = constructor.getDeclaringClass();
-      /*if[AOP]*/
-      try {
-        final net.sf.cglib.reflect.FastConstructor fastConstructor
-            = BytecodeGen.newFastClass(classToConstruct, Visibility.forMember(constructor))
-                .getConstructor(constructor);
-
-      return new ConstructionProxy<T>() {
-        @SuppressWarnings("unchecked")
-        public T newInstance(Object... arguments) throws InvocationTargetException {
-          return (T) fastConstructor.newInstance(arguments);
-        }
-        public InjectionPoint getInjectionPoint() {
-          return injectionPoint;
-        }
-        public Constructor<T> getConstructor() {
-          return constructor;
-        }
-        public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
-            getMethodInterceptors() {
-          return ImmutableMap.of();
-        }
-      };
-      } catch (net.sf.cglib.core.CodeGenerationException e) {/* fall-through */}
-      /*end[AOP]*/
-      if (!Modifier.isPublic(classToConstruct.getModifiers())) {
-        constructor.setAccessible(true);
+    /*if[AOP]*/
+    try {
+      net.sf.cglib.reflect.FastClass fc = BytecodeGen.newFastClassForMember(constructor);
+      if (fc != null) {
+        int index = fc.getIndex(constructor.getParameterTypes());
+        // We could just fall back to reflection in this case but I believe this should actually
+        // be impossible.
+        Preconditions.checkArgument(
+            index >= 0, "Could not find constructor %s in fast class", constructor);
+        return new FastClassProxy<T>(injectionPoint, constructor, fc, index);
       }
-    } else {
-      constructor.setAccessible(true);
+    } catch (net.sf.cglib.core.CodeGenerationException e) {
+      /* fall-through */
+    }
+    /*end[AOP]*/
+
+    return new ReflectiveProxy<T>(injectionPoint, constructor);
+  }
+
+  /*if[AOP]*/
+  /** A {@link ConstructionProxy} that uses FastClass to invoke the constructor. */
+  private static final class FastClassProxy<T> implements ConstructionProxy<T> {
+    final InjectionPoint injectionPoint;
+    final Constructor<T> constructor;
+    final net.sf.cglib.reflect.FastClass fc;
+    final int index;
+
+    private FastClassProxy(
+        InjectionPoint injectionPoint,
+        Constructor<T> constructor,
+        net.sf.cglib.reflect.FastClass fc,
+        int index) {
+      this.injectionPoint = injectionPoint;
+      this.constructor = constructor;
+      this.fc = fc;
+      this.index = index;
     }
 
-    return new ConstructionProxy<T>() {
-      public T newInstance(Object... arguments) throws InvocationTargetException {
-        try {
-          return constructor.newInstance(arguments);
-        } catch (InstantiationException e) {
-          throw new AssertionError(e); // shouldn't happen, we know this is a concrete type
-        } catch (IllegalAccessException e) {
-          throw new AssertionError(e); // a security manager is blocking us, we're hosed
-        }
+    @Override
+    @SuppressWarnings("unchecked")
+    public T newInstance(Object... arguments) throws InvocationTargetException {
+      // Use this method instead of FastConstructor to save a stack frame
+      return (T) fc.newInstance(index, arguments);
+    }
+
+    @Override
+    public InjectionPoint getInjectionPoint() {
+      return injectionPoint;
+    }
+
+    @Override
+    public Constructor<T> getConstructor() {
+      return constructor;
+    }
+
+    @Override
+    public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
+        getMethodInterceptors() {
+      return ImmutableMap.of();
+    }
+  }
+  /*end[AOP]*/
+
+  private static final class ReflectiveProxy<T> implements ConstructionProxy<T> {
+    final Constructor<T> constructor;
+    final InjectionPoint injectionPoint;
+
+    ReflectiveProxy(InjectionPoint injectionPoint, Constructor<T> constructor) {
+      if (!Modifier.isPublic(constructor.getDeclaringClass().getModifiers())
+          || !Modifier.isPublic(constructor.getModifiers())) {
+        constructor.setAccessible(true);
       }
-      public InjectionPoint getInjectionPoint() {
-        return injectionPoint;
+      this.injectionPoint = injectionPoint;
+      this.constructor = constructor;
+    }
+
+    @Override
+    public T newInstance(Object... arguments) throws InvocationTargetException {
+      try {
+        return constructor.newInstance(arguments);
+      } catch (InstantiationException e) {
+        throw new AssertionError(e); // shouldn't happen, we know this is a concrete type
+      } catch (IllegalAccessException e) {
+        throw new AssertionError(e); // a security manager is blocking us, we're hosed
       }
-      public Constructor<T> getConstructor() {
-        return constructor;
-      }
-      /*if[AOP]*/
-      public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
-          getMethodInterceptors() {
-        return ImmutableMap.of();
-      }
-      /*end[AOP]*/
-    };
+    }
+
+    @Override
+    public InjectionPoint getInjectionPoint() {
+      return injectionPoint;
+    }
+
+    @Override
+    public Constructor<T> getConstructor() {
+      return constructor;
+    }
+
+    /*if[AOP]*/
+    @Override
+    public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
+        getMethodInterceptors() {
+      return ImmutableMap.of();
+    }
+    /*end[AOP]*/
   }
 }
diff --git a/core/src/com/google/inject/internal/DeferredLookups.java b/core/src/com/google/inject/internal/DeferredLookups.java
index 049c9a8..2c37406 100644
--- a/core/src/com/google/inject/internal/DeferredLookups.java
+++ b/core/src/com/google/inject/internal/DeferredLookups.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,7 +24,6 @@
 import com.google.inject.spi.Element;
 import com.google.inject.spi.MembersInjectorLookup;
 import com.google.inject.spi.ProviderLookup;
-
 import java.util.List;
 
 /**
@@ -41,22 +40,22 @@
     this.injector = injector;
   }
 
-  /**
-   * Initialize the specified lookups, either immediately or when the injector is created.
-   */
+  /** Initialize the specified lookups, either immediately or when the injector is created. */
   void initialize(Errors errors) {
     injector.lookups = injector;
     new LookupProcessor(errors).process(injector, lookups);
   }
 
+  @Override
   public <T> Provider<T> getProvider(Key<T> key) {
-    ProviderLookup<T> lookup = new ProviderLookup<T>(key, key);
+    ProviderLookup<T> lookup = new ProviderLookup<>(key, key);
     lookups.add(lookup);
     return lookup.getProvider();
   }
 
+  @Override
   public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
-    MembersInjectorLookup<T> lookup = new MembersInjectorLookup<T>(type, type);
+    MembersInjectorLookup<T> lookup = new MembersInjectorLookup<>(type, type);
     lookups.add(lookup);
     return lookup.getMembersInjector();
   }
diff --git a/core/src/com/google/inject/internal/DelayedInitialize.java b/core/src/com/google/inject/internal/DelayedInitialize.java
index 82a8463..5534f50 100644
--- a/core/src/com/google/inject/internal/DelayedInitialize.java
+++ b/core/src/com/google/inject/internal/DelayedInitialize.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,13 @@
 package com.google.inject.internal;
 
 /**
- * Something that needs some delayed initialization, typically
- * a binding or internal factory that needs to be created & put
- * into the bindings map & then initialized later.
- * 
+ * Something that needs some delayed initialization, typically a binding or internal factory that
+ * needs to be created & put into the bindings map & then initialized later.
+ *
  * @author sameb@google.com (Sam Berlin)
  */
 interface DelayedInitialize {
-  
+
   /** Initializes this binding, throwing any errors if necessary. */
   void initialize(InjectorImpl injector, Errors errors) throws ErrorsException;
-
 }
diff --git a/core/src/com/google/inject/internal/DelegatingInvocationHandler.java b/core/src/com/google/inject/internal/DelegatingInvocationHandler.java
index 32441ff..f78262f 100644
--- a/core/src/com/google/inject/internal/DelegatingInvocationHandler.java
+++ b/core/src/com/google/inject/internal/DelegatingInvocationHandler.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,7 @@
 
 package com.google.inject.internal;
 
-
 import com.google.common.base.Preconditions;
-
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -29,16 +27,18 @@
 
   private T delegate;
 
-  public Object invoke(Object proxy, Method method, Object[] args)
-      throws Throwable {
+  @Override
+  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     try {
       // checking volatile field for synchronization
-      Preconditions.checkState(initialized,
+      Preconditions.checkState(
+          initialized,
           "This is a proxy used to support"
               + " circular references. The object we're"
               + " proxying is not constructed yet. Please wait until after"
               + " injection has completed to use this object.");
-      Preconditions.checkNotNull(delegate,
+      Preconditions.checkNotNull(
+          delegate,
           "This is a proxy used to support"
               + " circular references. The object we're "
               + " proxying is initialized to null."
diff --git a/extensions/multibindings/src/com/google/inject/multibindings/Element.java b/core/src/com/google/inject/internal/Element.java
similarity index 79%
rename from extensions/multibindings/src/com/google/inject/multibindings/Element.java
rename to core/src/com/google/inject/internal/Element.java
index c675551..5b738ef 100644
--- a/extensions/multibindings/src/com/google/inject/multibindings/Element.java
+++ b/core/src/com/google/inject/internal/Element.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,33 +14,34 @@
  * limitations under the License.
  */
 
-
-package com.google.inject.multibindings;
+package com.google.inject.internal;
 
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 import com.google.inject.BindingAnnotation;
-
 import java.lang.annotation.Retention;
 
 /**
- * An internal binding annotation applied to each element in a multibinding.
- * All elements are assigned a globally-unique id to allow different modules
- * to contribute multibindings independently.
+ * An internal binding annotation applied to each element in a multibinding. All elements are
+ * assigned a globally-unique id to allow different modules to contribute multibindings
+ * independently.
  *
  * @author jessewilson@google.com (Jesse Wilson)
  */
-@Retention(RUNTIME) @BindingAnnotation
+@Retention(RUNTIME)
+@BindingAnnotation
 @interface Element {
 
   enum Type {
     MAPBINDER,
-    MULTIBINDER,
-    OPTIONALBINDER;
+    MULTIBINDER;
   }
 
   String setName();
+
   int uniqueId();
+
   Type type();
+
   String keyType();
 }
diff --git a/core/src/com/google/inject/internal/EncounterImpl.java b/core/src/com/google/inject/internal/EncounterImpl.java
index 8aa3e94..4fb8575 100644
--- a/core/src/com/google/inject/internal/EncounterImpl.java
+++ b/core/src/com/google/inject/internal/EncounterImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,13 +30,10 @@
 import com.google.inject.spi.InjectionListener;
 import com.google.inject.spi.Message;
 import com.google.inject.spi.TypeEncounter;
-
 import java.lang.reflect.Method;
 import java.util.List;
 
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
+/** @author jessewilson@google.com (Jesse Wilson) */
 final class EncounterImpl<T> implements TypeEncounter<T> {
 
   private final Errors errors;
@@ -59,12 +56,12 @@
 
   /*if[AOP]*/
   ImmutableList<MethodAspect> getAspects() {
-    return aspects == null
-        ? ImmutableList.<MethodAspect>of()
-        : ImmutableList.copyOf(aspects);
+    return aspects == null ? ImmutableList.<MethodAspect>of() : ImmutableList.copyOf(aspects);
   }
 
-  public void bindInterceptor(Matcher<? super Method> methodMatcher,
+  @Override
+  public void bindInterceptor(
+      Matcher<? super Method> methodMatcher,
       org.aopalliance.intercept.MethodInterceptor... interceptors) {
     checkState(valid, "Encounters may not be used after hear() returns.");
 
@@ -89,6 +86,7 @@
         : ImmutableSet.copyOf(injectionListeners);
   }
 
+  @Override
   public void register(MembersInjector<? super T> membersInjector) {
     checkState(valid, "Encounters may not be used after hear() returns.");
 
@@ -99,6 +97,7 @@
     membersInjectors.add(membersInjector);
   }
 
+  @Override
   public void register(InjectionListener<? super T> injectionListener) {
     checkState(valid, "Encounters may not be used after hear() returns.");
 
@@ -109,36 +108,43 @@
     injectionListeners.add(injectionListener);
   }
 
+  @Override
   public void addError(String message, Object... arguments) {
     checkState(valid, "Encounters may not be used after hear() returns.");
     errors.addMessage(message, arguments);
   }
 
+  @Override
   public void addError(Throwable t) {
     checkState(valid, "Encounters may not be used after hear() returns.");
     errors.errorInUserCode(t, "An exception was caught and reported. Message: %s", t.getMessage());
   }
 
+  @Override
   public void addError(Message message) {
     checkState(valid, "Encounters may not be used after hear() returns.");
     errors.addMessage(message);
   }
 
+  @Override
   public <T> Provider<T> getProvider(Key<T> key) {
     checkState(valid, "Encounters may not be used after hear() returns.");
     return lookups.getProvider(key);
   }
 
+  @Override
   public <T> Provider<T> getProvider(Class<T> type) {
     return getProvider(Key.get(type));
   }
 
+  @Override
   public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
     checkState(valid, "Encounters may not be used after hear() returns.");
     return lookups.getMembersInjector(typeLiteral);
   }
 
+  @Override
   public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
     return getMembersInjector(TypeLiteral.get(type));
   }
-}
\ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/ErrorHandler.java b/core/src/com/google/inject/internal/ErrorHandler.java
index b448eb7..c0ffd01 100644
--- a/core/src/com/google/inject/internal/ErrorHandler.java
+++ b/core/src/com/google/inject/internal/ErrorHandler.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,13 +25,9 @@
  */
 interface ErrorHandler {
 
-  /**
-   * Handles an error.
-   */
+  /** Handles an error. */
   void handle(Object source, Errors errors);
 
-  /**
-   * Handles a user-reported error.
-   */
+  /** Handles a user-reported error. */
   void handle(Message message);
 }
diff --git a/core/src/com/google/inject/internal/Errors.java b/core/src/com/google/inject/internal/Errors.java
index 7527e2a..7269f12 100644
--- a/core/src/com/google/inject/internal/Errors.java
+++ b/core/src/com/google/inject/internal/Errors.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,45 +20,34 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
-import com.google.common.collect.Sets;
+import com.google.common.primitives.Primitives;
+import com.google.inject.Binding;
 import com.google.inject.ConfigurationException;
 import com.google.inject.CreationException;
-import com.google.inject.Guice;
+import com.google.inject.Injector;
 import com.google.inject.Key;
-import com.google.inject.MembersInjector;
-import com.google.inject.Provider;
-import com.google.inject.Provides;
 import com.google.inject.ProvisionException;
 import com.google.inject.Scope;
 import com.google.inject.TypeLiteral;
-import com.google.inject.internal.util.Classes;
 import com.google.inject.internal.util.SourceProvider;
-import com.google.inject.internal.util.StackTraceElements;
-import com.google.inject.spi.Dependency;
 import com.google.inject.spi.ElementSource;
-import com.google.inject.spi.InjectionListener;
-import com.google.inject.spi.InjectionPoint;
 import com.google.inject.spi.Message;
 import com.google.inject.spi.ScopeBinding;
 import com.google.inject.spi.TypeConverterBinding;
 import com.google.inject.spi.TypeListenerBinding;
-
-import java.io.PrintWriter;
 import java.io.Serializable;
-import java.io.StringWriter;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Formatter;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 
 /**
  * A collection of error messages. If this type is passed as a method parameter, the method is
@@ -77,30 +66,58 @@
  */
 public final class Errors implements Serializable {
 
-  private static final Logger logger = Logger.getLogger(Guice.class.getName());
+  /** When a binding is not found, show at most this many bindings with the same type */
+  private static final int MAX_MATCHING_TYPES_REPORTED = 3;
 
-  private static final Set<Dependency<?>> warnedDependencies =
-      Sets.newSetFromMap(new ConcurrentHashMap<Dependency<?>, Boolean>());
-
+  /** When a binding is not found, show at most this many bindings that have some similarities */
+  private static final int MAX_RELATED_TYPES_REPORTED = 3;
 
   /**
-   * The root errors object. Used to access the list of error messages.
+   * Throws a ConfigurationException with an NullPointerExceptions as the cause if the given
+   * reference is {@code null}.
    */
+  static <T> T checkNotNull(T reference, String name) {
+    if (reference != null) {
+      return reference;
+    }
+
+    NullPointerException npe = new NullPointerException(name);
+    throw new ConfigurationException(ImmutableSet.of(new Message(npe.toString(), npe)));
+  }
+
+  /**
+   * Throws a ConfigurationException with a formatted {@link Message} if this condition is {@code
+   * false}.
+   */
+  static void checkConfiguration(boolean condition, String format, Object... args) {
+    if (condition) {
+      return;
+    }
+
+    throw new ConfigurationException(ImmutableSet.of(new Message(Errors.format(format, args))));
+  }
+
+  /**
+   * If the key is unknown and it is one of these types, it generally means there is a missing
+   * annotation.
+   */
+  private static final ImmutableSet<Class<?>> COMMON_AMBIGUOUS_TYPES =
+      ImmutableSet.<Class<?>>builder()
+          .add(Object.class)
+          .add(String.class)
+          .addAll(Primitives.allWrapperTypes())
+          .build();
+
+  /** The root errors object. Used to access the list of error messages. */
   private final Errors root;
 
-  /**
-   * The parent errors object. Used to obtain the chain of source objects.
-   */
+  /** The parent errors object. Used to obtain the chain of source objects. */
   private final Errors parent;
 
-  /**
-   * The leaf source for errors added here.
-   */
+  /** The leaf source for errors added here. */
   private final Object source;
 
-  /**
-   * null unless (root == this) and error messages exist. Never an empty list.
-   */
+  /** null unless (root == this) and error messages exist. Never an empty list. */
   private List<Message> errors; // lazy, use getErrorsForAdd()
 
   public Errors() {
@@ -121,9 +138,7 @@
     this.source = source;
   }
 
-  /**
-   * Returns an instance that uses {@code source} as a reference point for newly added errors.
-   */
+  /** Returns an instance that uses {@code source} as a reference point for newly added errors. */
   public Errors withSource(Object source) {
     return source == this.source || source == SourceProvider.UNKNOWN_SOURCE
         ? this
@@ -131,69 +146,166 @@
   }
 
   /**
-   * We use a fairly generic error message here. The motivation is to share the
-   * same message for both bind time errors:
+   * We use a fairly generic error message here. The motivation is to share the same message for
+   * both bind time errors:
+   *
    * <pre><code>Guice.createInjector(new AbstractModule() {
    *   public void configure() {
    *     bind(Runnable.class);
    *   }
    * }</code></pre>
+   *
    * ...and at provide-time errors:
+   *
    * <pre><code>Guice.createInjector().getInstance(Runnable.class);</code></pre>
-   * Otherwise we need to know who's calling when resolving a just-in-time
-   * binding, which makes things unnecessarily complex.
+   *
+   * Otherwise we need to know who's calling when resolving a just-in-time binding, which makes
+   * things unnecessarily complex.
    */
   public Errors missingImplementation(Key key) {
     return addMessage("No implementation for %s was bound.", key);
   }
 
-  public Errors jitDisabled(Key key) {
+  /** Within guice's core, allow for better missing binding messages */
+  <T> Errors missingImplementationWithHint(Key<T> key, Injector injector) {
+    StringBuilder sb = new StringBuilder();
+
+    sb.append(format("No implementation for %s was bound.", key));
+
+    // Keys which have similar strings as the desired key
+    List<String> possibleMatches = new ArrayList<>();
+
+    // Check for other keys that may have the same type,
+    // but not the same annotation
+    TypeLiteral<T> type = key.getTypeLiteral();
+    List<Binding<T>> sameTypes = injector.findBindingsByType(type);
+    if (!sameTypes.isEmpty()) {
+      sb.append(format("%n  Did you mean?"));
+      int howMany = Math.min(sameTypes.size(), MAX_MATCHING_TYPES_REPORTED);
+      for (int i = 0; i < howMany; ++i) {
+        // TODO: Look into a better way to prioritize suggestions. For example, possbily
+        // use levenshtein distance of the given annotation vs actual annotation.
+        sb.append(format("%n    * %s", sameTypes.get(i).getKey()));
+      }
+      int remaining = sameTypes.size() - MAX_MATCHING_TYPES_REPORTED;
+      if (remaining > 0) {
+        String plural = (remaining == 1) ? "" : "s";
+        sb.append(format("%n    %d more binding%s with other annotations.", remaining, plural));
+      }
+    } else {
+      // For now, do a simple substring search for possibilities. This can help spot
+      // issues when there are generics being used (such as a wrapper class) and the
+      // user has forgotten they need to bind based on the wrapper, not the underlying
+      // class. In the future, consider doing a strict in-depth type search.
+      // TODO: Look into a better way to prioritize suggestions. For example, possbily
+      // use levenshtein distance of the type literal strings.
+      String want = type.toString();
+      Map<Key<?>, Binding<?>> bindingMap = injector.getAllBindings();
+      for (Key<?> bindingKey : bindingMap.keySet()) {
+        String have = bindingKey.getTypeLiteral().toString();
+        if (have.contains(want) || want.contains(have)) {
+          Formatter fmt = new Formatter();
+          Messages.formatSource(fmt, bindingMap.get(bindingKey).getSource());
+          String match = String.format("%s bound%s", convert(bindingKey), fmt.toString());
+          possibleMatches.add(match);
+          // TODO: Consider a check that if there are more than some number of results,
+          // don't suggest any.
+          if (possibleMatches.size() > MAX_RELATED_TYPES_REPORTED) {
+            // Early exit if we have found more than we need.
+            break;
+          }
+        }
+      }
+
+      if ((possibleMatches.size() > 0) && (possibleMatches.size() <= MAX_RELATED_TYPES_REPORTED)) {
+        sb.append(format("%n  Did you mean?"));
+        for (String possibleMatch : possibleMatches) {
+          sb.append(format("%n    %s", possibleMatch));
+        }
+      }
+    }
+
+    // If where are no possibilities to suggest, then handle the case of missing
+    // annotations on simple types. This is usually a bad idea.
+    if (sameTypes.isEmpty()
+        && possibleMatches.isEmpty()
+        && key.getAnnotation() == null
+        && COMMON_AMBIGUOUS_TYPES.contains(key.getTypeLiteral().getRawType())) {
+      // We don't recommend using such simple types without annotations.
+      sb.append(format("%nThe key seems very generic, did you forget an annotation?"));
+    }
+
+    return addMessage(sb.toString());
+  }
+
+  public Errors jitDisabled(Key<?> key) {
     return addMessage("Explicit bindings are required and %s is not explicitly bound.", key);
   }
 
   public Errors jitDisabledInParent(Key<?> key) {
     return addMessage(
         "Explicit bindings are required and %s would be bound in a parent injector.%n"
-        + "Please add an explicit binding for it, either in the child or the parent.",
+            + "Please add an explicit binding for it, either in the child or the parent.",
         key);
   }
 
   public Errors atInjectRequired(Class clazz) {
     return addMessage(
         "Explicit @Inject annotations are required on constructors,"
-        + " but %s has no constructors annotated with @Inject.",
+            + " but %s has no constructors annotated with @Inject.",
         clazz);
   }
 
-  public Errors converterReturnedNull(String stringValue, Object source,
-      TypeLiteral<?> type, TypeConverterBinding typeConverterBinding) {
-    return addMessage("Received null converting '%s' (bound at %s) to %s%n"
-        + " using %s.",
+  public Errors converterReturnedNull(
+      String stringValue,
+      Object source,
+      TypeLiteral<?> type,
+      TypeConverterBinding typeConverterBinding) {
+    return addMessage(
+        "Received null converting '%s' (bound at %s) to %s%n using %s.",
         stringValue, convert(source), type, typeConverterBinding);
   }
 
-  public Errors conversionTypeError(String stringValue, Object source, TypeLiteral<?> type,
-      TypeConverterBinding typeConverterBinding, Object converted) {
-    return addMessage("Type mismatch converting '%s' (bound at %s) to %s%n"
-        + " using %s.%n"
-        + " Converter returned %s.",
+  public Errors conversionTypeError(
+      String stringValue,
+      Object source,
+      TypeLiteral<?> type,
+      TypeConverterBinding typeConverterBinding,
+      Object converted) {
+    return addMessage(
+        "Type mismatch converting '%s' (bound at %s) to %s%n"
+            + " using %s.%n"
+            + " Converter returned %s.",
         stringValue, convert(source), type, typeConverterBinding, converted);
   }
 
-  public Errors conversionError(String stringValue, Object source,
-      TypeLiteral<?> type, TypeConverterBinding typeConverterBinding, RuntimeException cause) {
-    return errorInUserCode(cause, "Error converting '%s' (bound at %s) to %s%n"
-        + " using %s.%n"
-        + " Reason: %s",
-        stringValue, convert(source), type, typeConverterBinding, cause);
+  public Errors conversionError(
+      String stringValue,
+      Object source,
+      TypeLiteral<?> type,
+      TypeConverterBinding typeConverterBinding,
+      RuntimeException cause) {
+    return errorInUserCode(
+        cause,
+        "Error converting '%s' (bound at %s) to %s%n using %s.%n Reason: %s",
+        stringValue,
+        convert(source),
+        type,
+        typeConverterBinding,
+        cause);
   }
 
-  public Errors ambiguousTypeConversion(String stringValue, Object source, TypeLiteral<?> type,
-      TypeConverterBinding a, TypeConverterBinding b) {
-    return addMessage("Multiple converters can convert '%s' (bound at %s) to %s:%n"
-        + " %s and%n"
-        + " %s.%n"
-        + " Please adjust your type converter configuration to avoid overlapping matches.",
+  public Errors ambiguousTypeConversion(
+      String stringValue,
+      Object source,
+      TypeLiteral<?> type,
+      TypeConverterBinding a,
+      TypeConverterBinding b) {
+    return addMessage(
+        "Multiple converters can convert '%s' (bound at %s) to %s:%n"
+            + " %s and%n"
+            + " %s.%n"
+            + " Please adjust your type converter configuration to avoid overlapping matches.",
         stringValue, convert(source), type, a, b);
   }
 
@@ -201,11 +313,6 @@
     return addMessage("Binding to Provider is not allowed.");
   }
 
-  public Errors subtypeNotProvided(Class<? extends Provider<?>> providerType,
-      Class<?> type) {
-    return addMessage("%s doesn't provide instances of %s.", providerType, type);
-  }
-
   public Errors notASubtype(Class<?> implementationType, Class<?> type) {
     return addMessage("%s doesn't extend %s.", implementationType, type);
   }
@@ -227,8 +334,9 @@
   }
 
   public Errors optionalConstructor(Constructor constructor) {
-    return addMessage("%s is annotated @Inject(optional=true), "
-        + "but constructors cannot be optional.", constructor);
+    return addMessage(
+        "%s is annotated @Inject(optional=true), but constructors cannot be optional.",
+        constructor);
   }
 
   public Errors cannotBindToGuiceType(String simpleName) {
@@ -241,13 +349,17 @@
 
   public Errors scopeAnnotationOnAbstractType(
       Class<? extends Annotation> scopeAnnotation, Class<?> type, Object source) {
-    return addMessage("%s is annotated with %s, but scope annotations are not supported "
-        + "for abstract types.%n Bound at %s.", type, scopeAnnotation, convert(source));
+    return addMessage(
+        "%s is annotated with %s, but scope annotations are not supported "
+            + "for abstract types.%n Bound at %s.",
+        type, scopeAnnotation, convert(source));
   }
 
   public Errors misplacedBindingAnnotation(Member member, Annotation bindingAnnotation) {
-    return addMessage("%s is annotated with %s, but binding annotations should be applied "
-        + "to its parameters instead.", member, bindingAnnotation);
+    return addMessage(
+        "%s is annotated with %s, but binding annotations should be applied "
+            + "to its parameters instead.",
+        member, bindingAnnotation);
   }
 
   private static final String CONSTRUCTOR_RULES =
@@ -255,22 +367,24 @@
           + "annotated with @Inject or a zero-argument constructor that is not private.";
 
   public Errors missingConstructor(Class<?> implementation) {
-    return addMessage("Could not find a suitable constructor in %s. " + CONSTRUCTOR_RULES,
-        implementation);
+    return addMessage(
+        "Could not find a suitable constructor in %s. " + CONSTRUCTOR_RULES, implementation);
   }
 
   public Errors tooManyConstructors(Class<?> implementation) {
-    return addMessage("%s has more than one constructor annotated with @Inject. "
-        + CONSTRUCTOR_RULES, implementation);
+    return addMessage(
+        "%s has more than one constructor annotated with @Inject. " + CONSTRUCTOR_RULES,
+        implementation);
   }
 
   public Errors constructorNotDefinedByType(Constructor<?> constructor, TypeLiteral<?> type) {
     return addMessage("%s does not define %s", type, constructor);
   }
 
-  public Errors duplicateScopes(ScopeBinding existing,
-      Class<? extends Annotation> annotationType, Scope scope) {
-    return addMessage("Scope %s is already bound to %s at %s.%n Cannot bind %s.",
+  public Errors duplicateScopes(
+      ScopeBinding existing, Class<? extends Annotation> annotationType, Scope scope) {
+    return addMessage(
+        "Scope %s is already bound to %s at %s.%n Cannot bind %s.",
         existing.getScope(), annotationType, existing.getSource(), scope);
   }
 
@@ -283,14 +397,17 @@
   }
 
   public Errors cannotInjectInnerClass(Class<?> type) {
-    return addMessage("Injecting into inner classes is not supported.  "
-        + "Please use a 'static' class (top-level or nested) instead of %s.", type);
+    return addMessage(
+        "Injecting into inner classes is not supported.  "
+            + "Please use a 'static' class (top-level or nested) instead of %s.",
+        type);
   }
 
-  public Errors duplicateBindingAnnotations(Member member,
-      Class<? extends Annotation> a, Class<? extends Annotation> b) {
-    return addMessage("%s has more than one annotation annotated with @BindingAnnotation: "
-        + "%s and %s", member, a, b);
+  public Errors duplicateBindingAnnotations(
+      Member member, Class<? extends Annotation> a, Class<? extends Annotation> b) {
+    return addMessage(
+        "%s has more than one annotation annotated with @BindingAnnotation: %s and %s",
+        member, a, b);
   }
 
   public Errors staticInjectionOnInterface(Class<?> clazz) {
@@ -327,7 +444,8 @@
   }
 
   public Errors jitBindingAlreadySet(Key<?> key) {
-    return addMessage("A just-in-time binding to %s was already configured on a parent injector.", key);
+    return addMessage(
+        "A just-in-time binding to %s was already configured on a parent injector.", key);
   }
 
   public Errors childBindingAlreadySet(Key<?> key, Set<Object> sources) {
@@ -339,53 +457,32 @@
         allSources.format("%n    bound at %s", source);
       }
     }
-    Errors errors = addMessage(
-        "Unable to create binding for %s."
-      + " It was already configured on one or more child injectors or private modules"
-      + "%s%n"
-      + "  If it was in a PrivateModule, did you forget to expose the binding?",
-        key, allSources.out());
+    Errors errors =
+        addMessage(
+            "Unable to create binding for %s."
+                + " It was already configured on one or more child injectors or private modules"
+                + "%s%n"
+                + "  If it was in a PrivateModule, did you forget to expose the binding?",
+            key, allSources.out());
     return errors;
   }
 
   public Errors errorCheckingDuplicateBinding(Key<?> key, Object source, Throwable t) {
     return addMessage(
         "A binding to %s was already configured at %s and an error was thrown "
-      + "while checking duplicate bindings.  Error: %s",
+            + "while checking duplicate bindings.  Error: %s",
         key, convert(source), t);
   }
 
-  public Errors errorInjectingMethod(Throwable cause) {
-    return errorInUserCode(cause, "Error injecting method, %s", cause);
-  }
-
-  public Errors errorNotifyingTypeListener(TypeListenerBinding listener,
-      TypeLiteral<?> type, Throwable cause) {
-    return errorInUserCode(cause,
-        "Error notifying TypeListener %s (bound at %s) of %s.%n"
-        + " Reason: %s",
-        listener.getListener(), convert(listener.getSource()), type, cause);
-  }
-
-  public Errors errorInjectingConstructor(Throwable cause) {
-    return errorInUserCode(cause, "Error injecting constructor, %s", cause);
-  }
-
-  public Errors errorInProvider(RuntimeException runtimeException) {
-    Throwable unwrapped = unwrap(runtimeException);
-    return errorInUserCode(unwrapped, "Error in custom provider, %s", unwrapped);
-  }
-
-  public Errors errorInUserInjector(
-      MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException cause) {
-    return errorInUserCode(cause, "Error injecting %s using %s.%n"
-        + " Reason: %s", type, listener, cause);
-  }
-
-  public Errors errorNotifyingInjectionListener(
-      InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException cause) {
-    return errorInUserCode(cause, "Error notifying InjectionListener %s of %s.%n"
-        + " Reason: %s", listener, type, cause);
+  public Errors errorNotifyingTypeListener(
+      TypeListenerBinding listener, TypeLiteral<?> type, Throwable cause) {
+    return errorInUserCode(
+        cause,
+        "Error notifying TypeListener %s (bound at %s) of %s.%n Reason: %s",
+        listener.getListener(),
+        convert(listener.getSource()),
+        type,
+        cause);
   }
 
   public Errors exposedButNotBound(Key<?> key) {
@@ -422,14 +519,6 @@
     }
   }
 
-  private Throwable unwrap(RuntimeException runtimeException) {
-   if(runtimeException instanceof Exceptions.UnhandledCheckedUserException) {
-     return runtimeException.getCause();
-   } else {
-     return runtimeException;
-   }
-  }
-
   public Errors cannotInjectRawProvider() {
     return addMessage("Cannot inject a Provider that has no type parameter");
   }
@@ -446,18 +535,6 @@
     return addMessage("Cannot inject a TypeLiteral that has no type parameter");
   }
 
-  public Errors cannotSatisfyCircularDependency(Class<?> expectedType) {
-    return addMessage(
-        "Tried proxying %s to support a circular dependency, but it is not an interface.",
-        expectedType);
-  }
-
-  public Errors circularProxiesDisabled(Class<?> expectedType) {
-    return addMessage(
-        "Tried proxying %s to support a circular dependency, but circular proxies are disabled.",
-        expectedType);
-  }
-
   public void throwCreationExceptionIfErrorsExist() {
     if (!hasErrors()) {
       return;
@@ -474,6 +551,7 @@
     throw new ConfigurationException(getMessages());
   }
 
+  // Guice no longer calls this, but external callers do
   public void throwProvisionExceptionIfErrorsExist() {
     if (!hasErrors()) {
       return;
@@ -482,16 +560,10 @@
     throw new ProvisionException(getMessages());
   }
 
-  private Message merge(Message message) {
-    List<Object> sources = Lists.newArrayList();
-    sources.addAll(getSources());
-    sources.addAll(message.getSources());
-    return new Message(sources, message.getMessage(), message.getCause());
-  }
-
   public Errors merge(Collection<Message> messages) {
+    List<Object> sources = getSources();
     for (Message message : messages) {
-      addMessage(merge(message));
+      addMessage(Messages.mergeSources(sources, message));
     }
     return this;
   }
@@ -505,7 +577,12 @@
     return this;
   }
 
-  public List<Object> getSources() {
+  public Errors merge(InternalProvisionException ipe) {
+    merge(ipe.getErrors());
+    return this;
+  }
+
+  private List<Object> getSources() {
     List<Object> sources = Lists.newArrayList();
     for (Errors e = this; e != null; e = e.parent) {
       if (e.source != SourceProvider.UNKNOWN_SOURCE) {
@@ -536,8 +613,7 @@
   }
 
   private Errors addMessage(Throwable cause, String messageFormat, Object... arguments) {
-    String message = format(messageFormat, arguments);
-    addMessage(new Message(getSources(), message, cause));
+    addMessage(Messages.create(cause, getSources(), messageFormat, arguments));
     return this;
   }
 
@@ -549,11 +625,9 @@
     return this;
   }
 
+  // TODO(lukes): inline into callers
   public static String format(String messageFormat, Object... arguments) {
-    for (int i = 0; i < arguments.length; i++) {
-      arguments[i] = Errors.convert(arguments[i]);
-    }
-    return String.format(messageFormat, arguments);
+    return Messages.format(messageFormat, arguments);
   }
 
   public List<Message> getMessages() {
@@ -569,274 +643,23 @@
     }.sortedCopy(root.errors);
   }
 
-  /** Returns the formatted message for an exception with the specified messages. */
-  public static String format(String heading, Collection<Message> errorMessages) {
-    Formatter fmt = new Formatter().format(heading).format(":%n%n");
-    int index = 1;
-    boolean displayCauses = getOnlyCause(errorMessages) == null;
-
-    for (Message errorMessage : errorMessages) {
-      fmt.format("%s) %s%n", index++, errorMessage.getMessage());
-
-      List<Object> dependencies = errorMessage.getSources();
-      for (int i = dependencies.size() - 1; i >= 0; i--) {
-        Object source = dependencies.get(i);
-        formatSource(fmt, source);
-      }
-
-      Throwable cause = errorMessage.getCause();
-      if (displayCauses && cause != null) {
-        StringWriter writer = new StringWriter();
-        cause.printStackTrace(new PrintWriter(writer));
-        fmt.format("Caused by: %s", writer.getBuffer());
-      }
-
-      fmt.format("%n");
-    }
-
-    if (errorMessages.size() == 1) {
-      fmt.format("1 error");
-    } else {
-      fmt.format("%s errors", errorMessages.size());
-    }
-
-    return fmt.toString();
-  }
-
-  /**
-   * Returns {@code value} if it is non-null allowed to be null. Otherwise a message is added and
-   * an {@code ErrorsException} is thrown.
-   */
-  public <T> T checkForNull(T value, Object source, Dependency<?> dependency)
-      throws ErrorsException {
-    if (value != null || dependency.isNullable() ) {
-      return value;
-    }
-
-    // Hack to allow null parameters to @Provides methods, for backwards compatibility.
-    if (dependency.getInjectionPoint().getMember() instanceof Method) {
-      Method annotated = (Method) dependency.getInjectionPoint().getMember();
-      if (annotated.isAnnotationPresent(Provides.class)) {
-        switch (InternalFlags.getNullableProvidesOption()) {
-          case ERROR:
-            break; // break out & let the below exception happen
-          case IGNORE:
-            return value; // user doesn't care about injecting nulls to non-@Nullables.
-          case WARN:
-            // Warn only once, otherwise we spam logs too much.
-            if (!warnedDependencies.add(dependency)) {
-              return value;
-            }
-            logger.log(Level.WARNING,
-                "Guice injected null into parameter {0} of {1} (a {2}), please mark it @Nullable."
-                    + " Use -Dguice_check_nullable_provides_params=ERROR to turn this into an"
-                    + " error.",
-                new Object[] {
-                    dependency.getParameterIndex(),
-                    convert(dependency.getInjectionPoint().getMember()),
-                    convert(dependency.getKey())});
-            return null; // log & exit.
-        }
-      }
-    }
-
-    int parameterIndex = dependency.getParameterIndex();
-    String parameterName = (parameterIndex != -1)
-        ? "parameter " + parameterIndex + " of "
-        : "";
-    addMessage("null returned by binding at %s%n but %s%s is not @Nullable",
-        source, parameterName, dependency.getInjectionPoint().getMember());
-
-    throw toException();
-  }
-
-  /**
-   * Returns the cause throwable if there is exactly one cause in {@code messages}. If there are
-   * zero or multiple messages with causes, null is returned.
-   */
-  public static Throwable getOnlyCause(Collection<Message> messages) {
-    Throwable onlyCause = null;
-    for (Message message : messages) {
-      Throwable messageCause = message.getCause();
-      if (messageCause == null) {
-        continue;
-      }
-
-      if (onlyCause != null) {
-        return null;
-      }
-
-      onlyCause = messageCause;
-    }
-
-    return onlyCause;
-  }
-
   public int size() {
     return root.errors == null ? 0 : root.errors.size();
   }
 
-  private static abstract class Converter<T> {
-
-    final Class<T> type;
-
-    Converter(Class<T> type) {
-      this.type = type;
-    }
-
-    boolean appliesTo(Object o) {
-      return o != null && type.isAssignableFrom(o.getClass());
-    }
-
-    String convert(Object o) {
-      return toString(type.cast(o));
-    }
-
-    abstract String toString(T t);
-  }
-
-  private static final Collection<Converter<?>> converters = ImmutableList.of(
-      new Converter<Class>(Class.class) {
-        @Override public String toString(Class c) {
-          return c.getName();
-        }
-      },
-      new Converter<Member>(Member.class) {
-        @Override public String toString(Member member) {
-          return Classes.toString(member);
-        }
-      },
-      new Converter<Key>(Key.class) {
-        @Override public String toString(Key key) {
-          if (key.getAnnotationType() != null) {
-            return key.getTypeLiteral() + " annotated with "
-                + (key.getAnnotation() != null ? key.getAnnotation() : key.getAnnotationType());
-          } else {
-            return key.getTypeLiteral().toString();
-          }
-        }
-      });
-
+  // TODO(lukes): inline in callers.  There are some callers outside of guice, so this is difficult
   public static Object convert(Object o) {
-    ElementSource source = null;
-    if (o instanceof ElementSource) {
-      source = (ElementSource)o;
-      o = source.getDeclaringSource();
-    }
-    return convert(o, source);
+    return Messages.convert(o);
   }
 
+  // TODO(lukes): inline in callers.  There are some callers outside of guice, so this is difficult
   public static Object convert(Object o, ElementSource source) {
-    for (Converter<?> converter : converters) {
-      if (converter.appliesTo(o)) {
-        return appendModules(converter.convert(o), source);
-      }
-    }
-    return appendModules(o, source);
+    return Messages.convert(o, source);
   }
 
-  private static Object appendModules(Object source, ElementSource elementSource) {
-    String modules = moduleSourceString(elementSource);
-    if (modules.length() == 0) {
-      return source;
-    } else {
-      return source + modules;
-    }
-  }
-
-  private static String moduleSourceString(ElementSource elementSource) {
-    // if we only have one module (or don't know what they are), then don't bother
-    // reporting it, because the source already is going to report exactly that module.
-    if (elementSource == null) {
-      return "";
-    }
-    List<String> modules = Lists.newArrayList(elementSource.getModuleClassNames());
-    // Insert any original element sources w/ module info into the path.
-    while(elementSource.getOriginalElementSource() != null) {
-      elementSource = elementSource.getOriginalElementSource();
-      modules.addAll(0, elementSource.getModuleClassNames());
-    }
-    if (modules.size() <= 1) {
-      return "";
-    }
-
-    // Ideally we'd do:
-    //    return Joiner.on(" -> ")
-    //        .appendTo(new StringBuilder(" (via modules: "), Lists.reverse(modules))
-    //        .append(")").toString();
-    // ... but for some reason we can't find Lists.reverse, so do it the boring way.
-    StringBuilder builder = new StringBuilder(" (via modules: ");
-    for (int i = modules.size() - 1; i >= 0; i--) {
-      builder.append(modules.get(i));
-      if (i != 0) {
-        builder.append(" -> ");
-      }
-    }
-    builder.append(")");
-    return builder.toString();
-  }
-
+  // TODO(lukes): inline in callers.  There are some callers outside of guice, so this is difficult
   public static void formatSource(Formatter formatter, Object source) {
-    ElementSource elementSource = null;
-    if (source instanceof ElementSource) {
-      elementSource = (ElementSource)source;
-      source = elementSource.getDeclaringSource();
-    }
-    formatSource(formatter, source, elementSource);
+    Messages.formatSource(formatter, source);
   }
 
-  public static void formatSource(Formatter formatter, Object source, ElementSource elementSource) {
-    String modules = moduleSourceString(elementSource);
-    if (source instanceof Dependency) {
-      Dependency<?> dependency = (Dependency<?>) source;
-      InjectionPoint injectionPoint = dependency.getInjectionPoint();
-      if (injectionPoint != null) {
-        formatInjectionPoint(formatter, dependency, injectionPoint, elementSource);
-      } else {
-        formatSource(formatter, dependency.getKey(), elementSource);
-      }
-
-    } else if (source instanceof InjectionPoint) {
-      formatInjectionPoint(formatter, null, (InjectionPoint) source, elementSource);
-
-    } else if (source instanceof Class) {
-      formatter.format("  at %s%s%n", StackTraceElements.forType((Class<?>) source), modules);
-
-    } else if (source instanceof Member) {
-      formatter.format("  at %s%s%n", StackTraceElements.forMember((Member) source), modules);
-
-    } else if (source instanceof TypeLiteral) {
-      formatter.format("  while locating %s%s%n", source, modules);
-
-    } else if (source instanceof Key) {
-      Key<?> key = (Key<?>) source;
-      formatter.format("  while locating %s%n", convert(key, elementSource));
-
-    } else if (source instanceof Thread) {
-      formatter.format("  in thread %s%n", source);
-
-    } else {
-      formatter.format("  at %s%s%n", source, modules);
-    }
-  }
-
-  public static void formatInjectionPoint(Formatter formatter, Dependency<?> dependency,
-      InjectionPoint injectionPoint, ElementSource elementSource) {
-    Member member = injectionPoint.getMember();
-    Class<? extends Member> memberType = Classes.memberType(member);
-
-    if (memberType == Field.class) {
-      dependency = injectionPoint.getDependencies().get(0);
-      formatter.format("  while locating %s%n", convert(dependency.getKey(), elementSource));
-      formatter.format("    for field at %s%n", StackTraceElements.forMember(member));
-
-    } else if (dependency != null) {
-      formatter.format("  while locating %s%n", convert(dependency.getKey(), elementSource));
-      formatter.format("    for parameter %s at %s%n",
-          dependency.getParameterIndex(), StackTraceElements.forMember(member));
-
-    } else {
-      formatSource(formatter, injectionPoint.getMember());
-    }
-  }
 }
diff --git a/core/src/com/google/inject/internal/ErrorsException.java b/core/src/com/google/inject/internal/ErrorsException.java
index 57f55c4..6e95dbc 100644
--- a/core/src/com/google/inject/internal/ErrorsException.java
+++ b/core/src/com/google/inject/internal/ErrorsException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package com.google.inject.internal;
 
 /**
@@ -25,6 +24,8 @@
  * @author jessewilson@google.com (Jesse Wilson)
  */
 public class ErrorsException extends Exception {
+  // NOTE: this is used by Gin which is abandoned.  So changing this API will prevent Gin users from
+  // upgrading Guice version.
 
   private final Errors errors;
 
diff --git a/core/src/com/google/inject/internal/Exceptions.java b/core/src/com/google/inject/internal/Exceptions.java
deleted file mode 100644
index f9d1e21..0000000
--- a/core/src/com/google/inject/internal/Exceptions.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * Copyright (C) 2010 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;
-
-
-/**
- * Rethrows user-code exceptions in wrapped exceptions so that Errors can target the correct
- * exception.
- *
- * @author sameb@google.com (Sam Berlin)
- */
-class Exceptions {
-
-  /**
-   * Rethrows the exception (or it's cause, if it has one) directly if possible.
-   * If it was a checked exception, this wraps the exception in a stack trace
-   * with no frames, so that the exception is shown immediately with no frames
-   * above it.
-   */
-  public static RuntimeException rethrowCause(Throwable throwable) {
-    Throwable cause = throwable;
-    if(cause.getCause() != null) {
-      cause = cause.getCause();
-    }
-    return rethrow(cause);
-  }
-  
-  /** Rethrows the exception. */
-  public static RuntimeException rethrow(Throwable throwable) {    
-    if(throwable instanceof RuntimeException) {
-      throw (RuntimeException)throwable;
-    } else if(throwable instanceof Error) {
-      throw (Error)throwable;
-    } else {
-      throw new UnhandledCheckedUserException(throwable);
-    }
-  }
-
-  /**
-   * A marker exception class that we look for in order to unwrap the exception
-   * into the user exception, to provide a cleaner stack trace.
-   */
-  static class UnhandledCheckedUserException extends RuntimeException {
-    public UnhandledCheckedUserException(Throwable cause) {
-      super(cause);
-    }
-  }
-}
diff --git a/core/src/com/google/inject/internal/ExposedBindingImpl.java b/core/src/com/google/inject/internal/ExposedBindingImpl.java
index f17d5a6..1dfe408 100644
--- a/core/src/com/google/inject/internal/ExposedBindingImpl.java
+++ b/core/src/com/google/inject/internal/ExposedBindingImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 
 package com.google.inject.internal;
 
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableSet;
 import com.google.inject.Binder;
 import com.google.inject.Injector;
@@ -25,43 +25,51 @@
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.ExposedBinding;
 import com.google.inject.spi.PrivateElements;
-
 import java.util.Set;
 
 public final class ExposedBindingImpl<T> extends BindingImpl<T> implements ExposedBinding<T> {
 
   private final PrivateElements privateElements;
 
-  public ExposedBindingImpl(InjectorImpl injector, Object source, Key<T> key,
-      InternalFactory<T> factory, PrivateElements privateElements) {
+  public ExposedBindingImpl(
+      InjectorImpl injector,
+      Object source,
+      Key<T> key,
+      InternalFactory<T> factory,
+      PrivateElements privateElements) {
     super(injector, key, source, factory, Scoping.UNSCOPED);
     this.privateElements = privateElements;
   }
 
+  @Override
   public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
     return visitor.visit(this);
   }
 
+  @Override
   public Set<Dependency<?>> getDependencies() {
     return ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class)));
   }
 
+  @Override
   public PrivateElements getPrivateElements() {
     return privateElements;
   }
 
-  @Override public String toString() {
-    return Objects.toStringHelper(ExposedBinding.class)
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(ExposedBinding.class)
         .add("key", getKey())
         .add("source", getSource())
         .add("privateElements", privateElements)
         .toString();
   }
 
+  @Override
   public void applyTo(Binder binder) {
     throw new UnsupportedOperationException("This element represents a synthetic binding.");
   }
-  
+
   // Purposely does not override equals/hashcode, because exposed bindings are only equal to
   // themselves right now -- that is, there cannot be "duplicate" exposed bindings.
 }
diff --git a/core/src/com/google/inject/internal/ExposedKeyFactory.java b/core/src/com/google/inject/internal/ExposedKeyFactory.java
index 52bf7cb..5de73aa 100644
--- a/core/src/com/google/inject/internal/ExposedKeyFactory.java
+++ b/core/src/com/google/inject/internal/ExposedKeyFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,6 +34,7 @@
     this.privateElements = privateElements;
   }
 
+  @Override
   public void notify(Errors errors) {
     InjectorImpl privateInjector = (InjectorImpl) privateElements.getInjector();
     BindingImpl<T> explicitBinding = privateInjector.state.getExplicitBinding(key);
@@ -49,8 +50,10 @@
     this.delegate = explicitBinding;
   }
 
-  public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
-      throws ErrorsException {
-    return delegate.getInternalFactory().get(errors, context, dependency, linked);
+  @Override
+  public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+      throws InternalProvisionException {
+    // TODO(lukes): add a source to the thrown exception?
+    return delegate.getInternalFactory().get(context, dependency, linked);
   }
 }
diff --git a/core/src/com/google/inject/internal/ExposureBuilder.java b/core/src/com/google/inject/internal/ExposureBuilder.java
index 3b1c227..35dca16 100644
--- a/core/src/com/google/inject/internal/ExposureBuilder.java
+++ b/core/src/com/google/inject/internal/ExposureBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,12 +20,9 @@
 import com.google.inject.Binder;
 import com.google.inject.Key;
 import com.google.inject.binder.AnnotatedElementBuilder;
-
 import java.lang.annotation.Annotation;
 
-/**
- * For private binder's expose() method.
- */
+/** For private binder's expose() method. */
 public class ExposureBuilder<T> implements AnnotatedElementBuilder {
   private final Binder binder;
   private final Object source;
@@ -43,12 +40,14 @@
     }
   }
 
+  @Override
   public void annotatedWith(Class<? extends Annotation> annotationType) {
     Preconditions.checkNotNull(annotationType, "annotationType");
     checkNotAnnotated();
     key = Key.get(key.getTypeLiteral(), annotationType);
   }
 
+  @Override
   public void annotatedWith(Annotation annotation) {
     Preconditions.checkNotNull(annotation, "annotation");
     checkNotAnnotated();
@@ -63,7 +62,8 @@
     return source;
   }
 
-  @Override public String toString() {
+  @Override
+  public String toString() {
     return "AnnotatedElementBuilder";
   }
-}
\ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/FactoryProxy.java b/core/src/com/google/inject/internal/FactoryProxy.java
index 6416d26..a3a2227 100644
--- a/core/src/com/google/inject/internal/FactoryProxy.java
+++ b/core/src/com/google/inject/internal/FactoryProxy.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 
 package com.google.inject.internal;
 
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.inject.Key;
 import com.google.inject.internal.InjectorImpl.JitLimitation;
 import com.google.inject.spi.Dependency;
 
 /**
- * A placeholder which enables us to swap in the real factory once the injector is created.
- * Used for a linked binding, so that getting the linked binding returns the link's factory.
+ * A placeholder which enables us to swap in the real factory once the injector is created. Used for
+ * a linked binding, so that getting the linked binding returns the link's factory.
  */
 final class FactoryProxy<T> implements InternalFactory<T>, CreationListener {
 
@@ -41,26 +41,36 @@
     this.source = source;
   }
 
+  @Override
   public void notify(final Errors errors) {
     try {
-      targetFactory = injector.getInternalFactory(targetKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT);
+      targetFactory =
+          injector.getInternalFactory(
+              targetKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT);
     } catch (ErrorsException e) {
       errors.merge(e.getErrors());
     }
   }
 
-  public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
-      throws ErrorsException {
-    context.pushState(targetKey, source);
+  @Override
+  public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+      throws InternalProvisionException {
+    Key<? extends T> localTargetKey = targetKey;
+    context.pushState(localTargetKey, source);
+
     try {
-      return targetFactory.get(errors.withSource(targetKey), context, dependency, true);
-    } finally {
-      context.popState();
+      return targetFactory.get(context, dependency, true);
+    } catch (InternalProvisionException ipe) {
+      throw ipe.addSource(localTargetKey);
+      } finally {
+        context.popState();
+
     }
   }
 
-  @Override public String toString() {
-    return Objects.toStringHelper(FactoryProxy.class)
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(FactoryProxy.class)
         .add("key", key)
         .add("provider", targetFactory)
         .toString();
diff --git a/core/src/com/google/inject/internal/FailableCache.java b/core/src/com/google/inject/internal/FailableCache.java
index acd8be5..e1a461d 100644
--- a/core/src/com/google/inject/internal/FailableCache.java
+++ b/core/src/com/google/inject/internal/FailableCache.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,23 +27,26 @@
  * @author jessewilson@google.com (Jesse Wilson)
  */
 public abstract class FailableCache<K, V> {
-  
-  private final LoadingCache<K, Object> delegate = CacheBuilder.newBuilder().build(
-      new CacheLoader<K, Object>() {
-        public Object load(K key) {
-          Errors errors = new Errors();
-          V result = null;
-          try {
-            result = FailableCache.this.create(key, errors);
-          } catch (ErrorsException e) {
-            errors.merge(e.getErrors());
-          }
-          return errors.hasErrors() ? errors : result;
-        }
-      });
+
+  private final LoadingCache<K, Object> delegate =
+      CacheBuilder.newBuilder()
+          .build(
+              new CacheLoader<K, Object>() {
+                @Override
+                public Object load(K key) {
+                  Errors errors = new Errors();
+                  V result = null;
+                  try {
+                    result = FailableCache.this.create(key, errors);
+                  } catch (ErrorsException e) {
+                    errors.merge(e.getErrors());
+                  }
+                  return errors.hasErrors() ? errors : result;
+                }
+              });
 
   protected abstract V create(K key, Errors errors) throws ErrorsException;
-  
+
   public V get(K key, Errors errors) throws ErrorsException {
     Object resultOrError = delegate.getUnchecked(key);
     if (resultOrError instanceof Errors) {
@@ -55,7 +58,7 @@
       return result;
     }
   }
-  
+
   boolean remove(K key) {
     return delegate.asMap().remove(key) != null;
   }
diff --git a/core/src/com/google/inject/internal/Indexer.java b/core/src/com/google/inject/internal/Indexer.java
new file mode 100644
index 0000000..acbc163
--- /dev/null
+++ b/core/src/com/google/inject/internal/Indexer.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2014 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.Objects;
+import com.google.inject.Binding;
+import com.google.inject.Injector;
+import com.google.inject.Scope;
+import com.google.inject.Scopes;
+import com.google.inject.TypeLiteral;
+import com.google.inject.spi.BindingScopingVisitor;
+import com.google.inject.spi.ConstructorBinding;
+import com.google.inject.spi.ConvertedConstantBinding;
+import com.google.inject.spi.DefaultBindingTargetVisitor;
+import com.google.inject.spi.ExposedBinding;
+import com.google.inject.spi.InstanceBinding;
+import com.google.inject.spi.LinkedKeyBinding;
+import com.google.inject.spi.ProviderBinding;
+import com.google.inject.spi.ProviderInstanceBinding;
+import com.google.inject.spi.ProviderKeyBinding;
+import com.google.inject.spi.UntargettedBinding;
+import java.lang.annotation.Annotation;
+
+/**
+ * Visits bindings to return a {@code IndexedBinding} that can be used to emulate the binding
+ * deduplication that Guice internally performs.
+ *
+ * <p>Note: simply using equals/hashCode on the BindingImpls doesn't work because they all have
+ * unique annotations. This works around that by reimplementing equality semantics that ignores
+ * {@link Element#uniqueId()}. A better solution might be to introduce the idea of an 'anonymous'
+ * binding to guice, that might support this usecase directly.
+ */
+class Indexer extends DefaultBindingTargetVisitor<Object, Indexer.IndexedBinding>
+    implements BindingScopingVisitor<Object> {
+  enum BindingType {
+    INSTANCE,
+    PROVIDER_INSTANCE,
+    PROVIDER_KEY,
+    LINKED_KEY,
+    UNTARGETTED,
+    CONSTRUCTOR,
+    CONSTANT,
+    EXPOSED,
+    PROVIDED_BY,
+  }
+
+  static class IndexedBinding {
+    final String annotationName;
+    final Element.Type annotationType;
+    final TypeLiteral<?> typeLiteral;
+    final Object scope;
+    final BindingType type;
+    final Object extraEquality;
+
+    IndexedBinding(Binding<?> binding, BindingType type, Object scope, Object extraEquality) {
+      this.scope = scope;
+      this.type = type;
+      this.extraEquality = extraEquality;
+      this.typeLiteral = binding.getKey().getTypeLiteral();
+      Element annotation = (Element) binding.getKey().getAnnotation();
+      this.annotationName = annotation.setName();
+      this.annotationType = annotation.type();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (!(obj instanceof IndexedBinding)) {
+        return false;
+      }
+      IndexedBinding o = (IndexedBinding) obj;
+      return type == o.type
+          && Objects.equal(scope, o.scope)
+          && typeLiteral.equals(o.typeLiteral)
+          && annotationType == o.annotationType
+          && annotationName.equals(o.annotationName)
+          && Objects.equal(extraEquality, o.extraEquality);
+    }
+
+    @Override
+    public int hashCode() {
+      return Objects.hashCode(
+          type, scope, typeLiteral, annotationType, annotationName, extraEquality);
+    }
+  }
+
+  final Injector injector;
+
+  Indexer(Injector injector) {
+    this.injector = injector;
+  }
+
+  boolean isIndexable(Binding<?> binding) {
+    return binding.getKey().getAnnotation() instanceof Element;
+  }
+
+  private Object scope(Binding<?> binding) {
+    return binding.acceptScopingVisitor(this);
+  }
+
+  @Override
+  public Indexer.IndexedBinding visit(ConstructorBinding<? extends Object> binding) {
+    return new Indexer.IndexedBinding(
+        binding, BindingType.CONSTRUCTOR, scope(binding), binding.getConstructor());
+  }
+
+  @Override
+  public Indexer.IndexedBinding visit(ConvertedConstantBinding<? extends Object> binding) {
+    return new Indexer.IndexedBinding(
+        binding, BindingType.CONSTANT, scope(binding), binding.getValue());
+  }
+
+  @Override
+  public Indexer.IndexedBinding visit(ExposedBinding<? extends Object> binding) {
+    return new Indexer.IndexedBinding(binding, BindingType.EXPOSED, scope(binding), binding);
+  }
+
+  @Override
+  public Indexer.IndexedBinding visit(InstanceBinding<? extends Object> binding) {
+    return new Indexer.IndexedBinding(
+        binding, BindingType.INSTANCE, scope(binding), binding.getInstance());
+  }
+
+  @Override
+  public Indexer.IndexedBinding visit(LinkedKeyBinding<? extends Object> binding) {
+    return new Indexer.IndexedBinding(
+        binding, BindingType.LINKED_KEY, scope(binding), binding.getLinkedKey());
+  }
+
+  @Override
+  public Indexer.IndexedBinding visit(ProviderBinding<? extends Object> binding) {
+    return new Indexer.IndexedBinding(
+        binding,
+        BindingType.PROVIDED_BY,
+        scope(binding),
+        injector.getBinding(binding.getProvidedKey()));
+  }
+
+  @Override
+  public Indexer.IndexedBinding visit(ProviderInstanceBinding<? extends Object> binding) {
+    return new Indexer.IndexedBinding(
+        binding, BindingType.PROVIDER_INSTANCE, scope(binding), binding.getUserSuppliedProvider());
+  }
+
+  @Override
+  public Indexer.IndexedBinding visit(ProviderKeyBinding<? extends Object> binding) {
+    return new Indexer.IndexedBinding(
+        binding, BindingType.PROVIDER_KEY, scope(binding), binding.getProviderKey());
+  }
+
+  @Override
+  public Indexer.IndexedBinding visit(UntargettedBinding<? extends Object> binding) {
+    return new Indexer.IndexedBinding(binding, BindingType.UNTARGETTED, scope(binding), null);
+  }
+
+  private static final Object EAGER_SINGLETON = new Object();
+
+  @Override
+  public Object visitEagerSingleton() {
+    return EAGER_SINGLETON;
+  }
+
+  @Override
+  public Object visitNoScoping() {
+    return Scopes.NO_SCOPE;
+  }
+
+  @Override
+  public Object visitScope(Scope scope) {
+    return scope;
+  }
+
+  @Override
+  public Object visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
+    return scopeAnnotation;
+  }
+}
diff --git a/core/src/com/google/inject/internal/InheritingState.java b/core/src/com/google/inject/internal/InheritingState.java
index 18363f4..7b739fc 100644
--- a/core/src/com/google/inject/internal/InheritingState.java
+++ b/core/src/com/google/inject/internal/InheritingState.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,25 +31,21 @@
 import com.google.inject.spi.ScopeBinding;
 import com.google.inject.spi.TypeConverterBinding;
 import com.google.inject.spi.TypeListenerBinding;
-
 import java.lang.annotation.Annotation;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
+/** @author jessewilson@google.com (Jesse Wilson) */
 final class InheritingState implements State {
 
   private final State parent;
 
   // Must be a linked hashmap in order to preserve order of bindings in Modules.
   private final Map<Key<?>, Binding<?>> explicitBindingsMutable = Maps.newLinkedHashMap();
-  private final Map<Key<?>, Binding<?>> explicitBindings
-      = Collections.unmodifiableMap(explicitBindingsMutable);
+  private final Map<Key<?>, Binding<?>> explicitBindings =
+      Collections.unmodifiableMap(explicitBindingsMutable);
   private final Map<Class<? extends Annotation>, ScopeBinding> scopes = Maps.newHashMap();
   private final List<TypeConverterBinding> converters = Lists.newArrayList();
   /*if[AOP]*/
@@ -67,41 +63,50 @@
     this.blacklistedKeys = new WeakKeySet(lock);
   }
 
+  @Override
   public State parent() {
     return parent;
   }
 
+  @Override
   @SuppressWarnings("unchecked") // we only put in BindingImpls that match their key types
   public <T> BindingImpl<T> getExplicitBinding(Key<T> key) {
     Binding<?> binding = explicitBindings.get(key);
     return binding != null ? (BindingImpl<T>) binding : parent.getExplicitBinding(key);
   }
 
+  @Override
   public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() {
     return explicitBindings;
   }
 
+  @Override
   public void putBinding(Key<?> key, BindingImpl<?> binding) {
     explicitBindingsMutable.put(key, binding);
   }
 
+  @Override
   public ScopeBinding getScopeBinding(Class<? extends Annotation> annotationType) {
     ScopeBinding scopeBinding = scopes.get(annotationType);
     return scopeBinding != null ? scopeBinding : parent.getScopeBinding(annotationType);
   }
 
+  @Override
   public void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope) {
     scopes.put(annotationType, scope);
   }
 
+  @Override
   public Iterable<TypeConverterBinding> getConvertersThisLevel() {
     return converters;
   }
 
+  @Override
   public void addConverter(TypeConverterBinding typeConverterBinding) {
     converters.add(typeConverterBinding);
   }
 
+  @Override
   public TypeConverterBinding getConverter(
       String stringValue, TypeLiteral<?> type, Errors errors, Object source) {
     TypeConverterBinding matchingConverter = null;
@@ -119,10 +124,12 @@
   }
 
   /*if[AOP]*/
+  @Override
   public void addMethodAspect(MethodAspect methodAspect) {
     methodAspects.add(methodAspect);
   }
 
+  @Override
   public ImmutableList<MethodAspect> getMethodAspects() {
     return new ImmutableList.Builder<MethodAspect>()
         .addAll(parent.getMethodAspects())
@@ -131,10 +138,12 @@
   }
   /*end[AOP]*/
 
+  @Override
   public void addTypeListener(TypeListenerBinding listenerBinding) {
     typeListenerBindings.add(listenerBinding);
   }
 
+  @Override
   public List<TypeListenerBinding> getTypeListenerBindings() {
     List<TypeListenerBinding> parentBindings = parent.getTypeListenerBindings();
     List<TypeListenerBinding> result =
@@ -143,11 +152,13 @@
     result.addAll(typeListenerBindings);
     return result;
   }
-  
+
+  @Override
   public void addProvisionListener(ProvisionListenerBinding listenerBinding) {
     provisionListenerBindings.add(listenerBinding);
   }
 
+  @Override
   public List<ProvisionListenerBinding> getProvisionListenerBindings() {
     List<ProvisionListenerBinding> parentBindings = parent.getProvisionListenerBindings();
     List<ProvisionListenerBinding> result =
@@ -157,10 +168,12 @@
     return result;
   }
 
+  @Override
   public void addScanner(ModuleAnnotatedMethodScannerBinding scanner) {
     scannerBindings.add(scanner);
   }
 
+  @Override
   public List<ModuleAnnotatedMethodScannerBinding> getScannerBindings() {
     List<ModuleAnnotatedMethodScannerBinding> parentBindings = parent.getScannerBindings();
     List<ModuleAnnotatedMethodScannerBinding> result =
@@ -170,23 +183,28 @@
     return result;
   }
 
+  @Override
   public void blacklist(Key<?> key, State state, Object source) {
     parent.blacklist(key, state, source);
     blacklistedKeys.add(key, state, source);
   }
 
+  @Override
   public boolean isBlacklisted(Key<?> key) {
     return blacklistedKeys.contains(key);
   }
-  
+
+  @Override
   public Set<Object> getSourcesForBlacklistedKey(Key<?> key) {
     return blacklistedKeys.getSources(key);
   }
 
+  @Override
   public Object lock() {
     return lock;
   }
 
+  @Override
   public Map<Class<? extends Annotation>, Scope> getScopes() {
     ImmutableMap.Builder<Class<? extends Annotation>, Scope> builder = ImmutableMap.builder();
     for (Map.Entry<Class<? extends Annotation>, ScopeBinding> entry : scopes.entrySet()) {
diff --git a/core/src/com/google/inject/internal/Initializable.java b/core/src/com/google/inject/internal/Initializable.java
index 855dd8c..e3c9ed9 100644
--- a/core/src/com/google/inject/internal/Initializable.java
+++ b/core/src/com/google/inject/internal/Initializable.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,8 +23,6 @@
  */
 interface Initializable<T> {
 
-  /**
-   * Ensures the reference is initialized, then returns it.
-   */
-  T get(Errors errors) throws ErrorsException;
+  /** Ensures the reference is initialized, then returns it. */
+  T get() throws InternalProvisionException;
 }
diff --git a/core/src/com/google/inject/internal/Initializables.java b/core/src/com/google/inject/internal/Initializables.java
index 82e2868..36655f7 100644
--- a/core/src/com/google/inject/internal/Initializables.java
+++ b/core/src/com/google/inject/internal/Initializables.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,19 @@
 
 package com.google.inject.internal;
 
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
+/** @author jessewilson@google.com (Jesse Wilson) */
 final class Initializables {
 
-  /**
-   * Returns an initializable for an instance that requires no initialization.
-   */
+  /** Returns an initializable for an instance that requires no initialization. */
   static <T> Initializable<T> of(final T instance) {
     return new Initializable<T>() {
-      public T get(Errors errors) throws ErrorsException {
+      @Override
+      public T get() {
         return instance;
       }
 
-      @Override public String toString() {
+      @Override
+      public String toString() {
         return String.valueOf(instance);
       }
     };
diff --git a/core/src/com/google/inject/internal/Initializer.java b/core/src/com/google/inject/internal/Initializer.java
index ff83ea9..2ab4b0f 100644
--- a/core/src/com/google/inject/internal/Initializer.java
+++ b/core/src/com/google/inject/internal/Initializer.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,15 +21,16 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
 import com.google.inject.Binding;
 import com.google.inject.Key;
 import com.google.inject.Stage;
 import com.google.inject.TypeLiteral;
+import com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory;
 import com.google.inject.spi.InjectionPoint;
-
-import java.util.Map;
+import java.util.IdentityHashMap;
+import java.util.List;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
 
 /**
  * Manages and injects instances at injector-creation time. This is made more complicated by
@@ -39,46 +40,76 @@
  * @author jessewilson@google.com (Jesse Wilson)
  */
 final class Initializer {
-  
-  /** the only thread that we'll use to inject members. */
-  private final Thread creatingThread = Thread.currentThread();
 
-  /** zero means everything is injected. */
-  private final CountDownLatch ready = new CountDownLatch(1);
-  
-  /** Maps from instances that need injection to the MembersInjector that will inject them. */
-  private final Map<Object, MembersInjectorImpl<?>> pendingMembersInjectors =
+  /** Is set to true once {@link #validateOustandingInjections} is called. */
+  private volatile boolean validationStarted = false;
+
+  /**
+   * Allows us to detect circular dependencies. It's only used during injectable reference
+   * initialization. After initialization direct access through volatile field is used.
+   */
+  private final CycleDetectingLockFactory<Class<?>> cycleDetectingLockFactory =
+      new CycleDetectingLockFactory<Class<?>>();
+
+  /**
+   * Instances that need injection during injector creation to a source that registered them. New
+   * references added before {@link #validateOustandingInjections}. Cleared up in {@link
+   * #injectAll}.
+   */
+  private final List<InjectableReference<?>> pendingInjections = Lists.newArrayList();
+
+  /**
+   * Map that guarantees that no instance would get two references. New references added before
+   * {@link #validateOustandingInjections}. Cleared up in {@link #validateOustandingInjections}.
+   */
+  private final IdentityHashMap<Object, InjectableReference<?>> initializablesCache =
       Maps.newIdentityHashMap();
 
-  /** Maps instances that need injection to a source that registered them */
-  private final Map<Object, InjectableReference<?>> pendingInjection = Maps.newIdentityHashMap();
-
   /**
    * Registers an instance for member injection when that step is performed.
    *
-   * @param instance an instance that optionally has members to be injected (each annotated with
-   *      @Inject).
+   * @param instance an instance that optionally has members to be injected (each annotated
+   *     with @Inject).
    * @param binding the binding that caused this initializable to be created, if it exists.
    * @param source the source location that this injection was requested
    */
-  <T> Initializable<T> requestInjection(InjectorImpl injector, T instance, Binding<T> binding,
-      Object source, Set<InjectionPoint> injectionPoints) {
+  <T> Initializable<T> requestInjection(
+      InjectorImpl injector,
+      T instance,
+      Binding<T> binding,
+      Object source,
+      Set<InjectionPoint> injectionPoints) {
     checkNotNull(source);
-    
+    Preconditions.checkState(
+        !validationStarted, "Member injection could not be requested after validation is started");
     ProvisionListenerStackCallback<T> provisionCallback =
         binding == null ? null : injector.provisionListenerStore.get(binding);
 
     // short circuit if the object has no injections or listeners.
-    if (instance == null || (injectionPoints.isEmpty()
-        && !injector.membersInjectorStore.hasTypeListeners()
-        && (provisionCallback == null || !provisionCallback.hasListeners()))) {
+    if (instance == null
+        || (injectionPoints.isEmpty()
+            && !injector.membersInjectorStore.hasTypeListeners()
+            && provisionCallback == null)) {
       return Initializables.of(instance);
     }
 
-    InjectableReference<T> initializable = new InjectableReference<T>(
-        injector, instance, binding == null ? null : binding.getKey(), provisionCallback, source);
-    pendingInjection.put(instance, initializable);
-    return initializable;
+    if (initializablesCache.containsKey(instance)) {
+      @SuppressWarnings("unchecked") // Map from T to InjectableReference<T>
+      Initializable<T> cached = (Initializable<T>) initializablesCache.get(instance);
+      return cached;
+    }
+
+    InjectableReference<T> injectableReference =
+        new InjectableReference<T>(
+            injector,
+            instance,
+            binding == null ? null : binding.getKey(),
+            provisionCallback,
+            source,
+            cycleDetectingLockFactory.create(instance.getClass()));
+    initializablesCache.put(instance, injectableReference);
+    pendingInjections.add(injectableReference);
+    return injectableReference;
   }
 
   /**
@@ -86,9 +117,11 @@
    * on the injected instances.
    */
   void validateOustandingInjections(Errors errors) {
-    for (InjectableReference<?> reference : pendingInjection.values()) {
+    validationStarted = true;
+    initializablesCache.clear();
+    for (InjectableReference<?> reference : pendingInjections) {
       try {
-        pendingMembersInjectors.put(reference.instance, reference.validate(errors));
+        reference.validate(errors);
       } catch (ErrorsException e) {
         errors.merge(e.getErrors());
       }
@@ -101,88 +134,130 @@
    * instances are codependent (directly or transitively), ordering of injection is arbitrary.
    */
   void injectAll(final Errors errors) {
-    // loop over a defensive copy since ensureInjected() mutates the set. Unfortunately, that copy
-    // is made complicated by a bug in IBM's JDK, wherein entrySet().toArray(Object[]) doesn't work
-    for (InjectableReference<?> reference : Lists.newArrayList(pendingInjection.values())) {
+    Preconditions.checkState(validationStarted, "Validation should be done before injection");
+    for (InjectableReference<?> reference : pendingInjections) {
       try {
-        reference.get(errors);
-      } catch (ErrorsException e) {
-        errors.merge(e.getErrors());
+        reference.get();
+      } catch (InternalProvisionException ipe) {
+        errors.merge(ipe);
       }
     }
-
-    if (!pendingInjection.isEmpty()) {
-      throw new AssertionError("Failed to satisfy " + pendingInjection);
-    }
-
-    ready.countDown();
+    pendingInjections.clear();
   }
 
-  private class InjectableReference<T> implements Initializable<T> {
+  private enum InjectableReferenceState {
+    NEW,
+    VALIDATED,
+    INJECTING,
+    READY
+  }
+
+  private static class InjectableReference<T> implements Initializable<T> {
+    private volatile InjectableReferenceState state = InjectableReferenceState.NEW;
+    private volatile MembersInjectorImpl<T> membersInjector = null;
+
     private final InjectorImpl injector;
     private final T instance;
     private final Object source;
     private final Key<T> key;
     private final ProvisionListenerStackCallback<T> provisionCallback;
+    private final CycleDetectingLock<?> lock;
 
-    public InjectableReference(InjectorImpl injector, T instance, Key<T> key,
-        ProvisionListenerStackCallback<T> provisionCallback, Object source) {
+    public InjectableReference(
+        InjectorImpl injector,
+        T instance,
+        Key<T> key,
+        ProvisionListenerStackCallback<T> provisionCallback,
+        Object source,
+        CycleDetectingLock<?> lock) {
       this.injector = injector;
       this.key = key; // possibly null!
       this.provisionCallback = provisionCallback; // possibly null!
       this.instance = checkNotNull(instance, "instance");
       this.source = checkNotNull(source, "source");
+      this.lock = checkNotNull(lock, "lock");
     }
 
-    public MembersInjectorImpl<T> validate(Errors errors) throws ErrorsException {
+    public void validate(Errors errors) throws ErrorsException {
       @SuppressWarnings("unchecked") // the type of 'T' is a TypeLiteral<T>
-          TypeLiteral<T> type = TypeLiteral.get((Class<T>) instance.getClass());
-      return injector.membersInjectorStore.get(type, errors.withSource(source));
+      TypeLiteral<T> type = TypeLiteral.get((Class<T>) instance.getClass());
+      membersInjector = injector.membersInjectorStore.get(type, errors.withSource(source));
+      Preconditions.checkNotNull(
+          membersInjector,
+          "No membersInjector available for instance: %s, from key: %s",
+          instance,
+          key);
+      state = InjectableReferenceState.VALIDATED;
     }
 
     /**
      * Reentrant. If {@code instance} was registered for injection at injector-creation time, this
      * method will ensure that all its members have been injected before returning.
      */
-    public T get(Errors errors) throws ErrorsException {
-      if (ready.getCount() == 0) {
+    @Override
+    public T get() throws InternalProvisionException {
+      // skipping acquiring lock if initialization is already finished
+      if (state == InjectableReferenceState.READY) {
         return instance;
       }
 
-      // just wait for everything to be injected by another thread
-      if (Thread.currentThread() != creatingThread) {
-        try {
-          ready.await();
-          return instance;
-        } catch (InterruptedException e) {
-          // Give up, since we don't know if our injection is ready
-          throw new RuntimeException(e);
-        }
-      }
+      // acquire lock for current binding to initialize an instance
+      Multimap<?, ?> lockCycle = lock.lockOrDetectPotentialLocksCycle();
+      if (!lockCycle.isEmpty()) {
+        // Potential deadlock detected and creation lock is not taken.
+        // According to injectAll()'s contract return non-initialized instance.
 
-      // toInject needs injection, do it right away. we only do this once, even if it fails
-      if (pendingInjection.remove(instance) != null) {
-        // safe because we only insert a members injector for the appropriate instance
-        @SuppressWarnings("unchecked")
-        MembersInjectorImpl<T> membersInjector =
-            (MembersInjectorImpl<T>)pendingMembersInjectors.remove(instance);
-        Preconditions.checkState(membersInjector != null,
-            "No membersInjector available for instance: %s, from key: %s", instance, key);
-        
+        // This condition should not be possible under the current Guice implementation.
+        // This clause exists for defensive programming purposes.
+
+        // Reasoning:
+        // get() is called either directly from injectAll(), holds no locks and can not create
+        // a cycle, or it is called through a singleton scope, which resolves deadlocks by itself.
+        // Before calling get() object has to be requested for injection.
+        // Initializer.requestInjection() is called either for constant object bindings, which wrap
+        // creation into a Singleton scope, or from Binder.requestInjection(), which
+        // has to use Singleton scope to reuse the same InjectableReference to potentially
+        // create a lock cycle.
+        return instance;
+      }
+      try {
+        // lock acquired, current thread owns this instance initialization
+        switch (state) {
+          case READY:
+            return instance;
+            // When instance depends on itself in the same thread potential dead lock
+            // is not detected. We have to prevent a stack overflow and we use
+            // an "injecting" stage to short-circuit a call.
+          case INJECTING:
+            return instance;
+          case VALIDATED:
+            state = InjectableReferenceState.INJECTING;
+            break;
+          case NEW:
+            throw new IllegalStateException("InjectableReference is not validated yet");
+          default:
+            throw new IllegalStateException("Unknown state: " + state);
+        }
+
         // if in Stage.TOOL, we only want to inject & notify toolable injection points.
         // (otherwise we'll inject all of them)
-        membersInjector.injectAndNotify(instance,
-            errors.withSource(source),
-            key,
-            provisionCallback,
-            source,
-            injector.options.stage == Stage.TOOL);
+        try {
+          membersInjector.injectAndNotify(
+              instance, key, provisionCallback, source, injector.options.stage == Stage.TOOL);
+        } catch (InternalProvisionException ipe) {
+          throw ipe.addSource(source);
+        }
+        // mark instance as ready to skip a lock on subsequent calls
+        state = InjectableReferenceState.READY;
+        return instance;
+      } finally {
+        // always release our creation lock, even on failures
+        lock.unlock();
       }
-
-      return instance;
     }
 
-    @Override public String toString() {
+    @Override
+    public String toString() {
       return instance.toString();
     }
   }
diff --git a/core/src/com/google/inject/internal/InjectionRequestProcessor.java b/core/src/com/google/inject/internal/InjectionRequestProcessor.java
index 36ad261..dce78e8 100644
--- a/core/src/com/google/inject/internal/InjectionRequestProcessor.java
+++ b/core/src/com/google/inject/internal/InjectionRequestProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@
 import com.google.inject.spi.InjectionPoint;
 import com.google.inject.spi.InjectionRequest;
 import com.google.inject.spi.StaticInjectionRequest;
-
 import java.util.List;
 import java.util.Set;
 
@@ -44,12 +43,14 @@
     this.initializer = initializer;
   }
 
-  @Override public Boolean visit(StaticInjectionRequest request) {
+  @Override
+  public Boolean visit(StaticInjectionRequest request) {
     staticInjections.add(new StaticInjection(injector, request));
     return true;
   }
 
-  @Override public Boolean visit(InjectionRequest<?> request) {
+  @Override
+  public Boolean visit(InjectionRequest<?> request) {
     Set<InjectionPoint> injectionPoints;
     try {
       injectionPoints = request.getInjectionPoints();
@@ -103,31 +104,32 @@
         injectionPoints = e.getPartialValue();
       }
       if (injectionPoints != null) {
-        memberInjectors = injector.membersInjectorStore.getInjectors(
-            injectionPoints, errorsForMember);
+        memberInjectors =
+            injector.membersInjectorStore.getInjectors(injectionPoints, errorsForMember);
       } else {
         memberInjectors = ImmutableList.of();
       }
-      
+
       errors.merge(errorsForMember);
     }
 
     void injectMembers() {
+      InternalContext context = injector.enterContext();
       try {
-        injector.callInContext(new ContextualCallable<Void>() {
-          public Void call(InternalContext context) {
-            for (SingleMemberInjector memberInjector : memberInjectors) {
-              // Run injections if we're not in tool stage (ie, PRODUCTION or DEV),
-              // or if we are in tool stage and the injection point is toolable.
-              if(injector.options.stage != Stage.TOOL || memberInjector.getInjectionPoint().isToolable()) {
-                memberInjector.inject(errors, context, null);
-              }
+        boolean isStageTool = injector.options.stage == Stage.TOOL;
+        for (SingleMemberInjector memberInjector : memberInjectors) {
+          // Run injections if we're not in tool stage (ie, PRODUCTION or DEV),
+          // or if we are in tool stage and the injection point is toolable.
+          if (!isStageTool || memberInjector.getInjectionPoint().isToolable()) {
+            try {
+              memberInjector.inject(context, null);
+            } catch (InternalProvisionException e) {
+              errors.merge(e);
             }
-            return null;
           }
-        });
-      } catch (ErrorsException e) {
-        throw new AssertionError();
+        }
+      } finally {
+        context.close();
       }
     }
   }
diff --git a/core/src/com/google/inject/internal/InjectorImpl.java b/core/src/com/google/inject/internal/InjectorImpl.java
index 54ce8a3..321dbea 100644
--- a/core/src/com/google/inject/internal/InjectorImpl.java
+++ b/core/src/com/google/inject/internal/InjectorImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,13 @@
 
 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.Lists;
+import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.inject.Binder;
@@ -33,7 +35,6 @@
 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;
@@ -43,10 +44,10 @@
 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;
@@ -57,7 +58,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
 
 /**
  * Default {@link Injector} implementation.
@@ -75,8 +75,12 @@
     final boolean atInjectRequired;
     final boolean exactBindingAnnotationsRequired;
 
-    InjectorOptions(Stage stage, boolean jitDisabled, boolean disableCircularProxies,
-        boolean atInjectRequired, boolean exactBindingAnnotationsRequired) {
+    InjectorOptions(
+        Stage stage,
+        boolean jitDisabled,
+        boolean disableCircularProxies,
+        boolean atInjectRequired,
+        boolean exactBindingAnnotationsRequired) {
       this.stage = stage;
       this.jitDisabled = jitDisabled;
       this.disableCircularProxies = disableCircularProxies;
@@ -86,7 +90,7 @@
 
     @Override
     public String toString() {
-      return Objects.toStringHelper(getClass())
+      return MoreObjects.toStringHelper(getClass())
           .add("stage", stage)
           .add("jitDisabled", jitDisabled)
           .add("disableCircularProxies", disableCircularProxies)
@@ -108,14 +112,14 @@
 
   final State state;
   final InjectorImpl parent;
-  final BindingsMultimap bindingsMultimap = new BindingsMultimap();
+  final ListMultimap<TypeLiteral<?>, Binding<?>> bindingsMultimap = ArrayListMultimap.create();
   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().
+   * 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();
 
@@ -129,26 +133,29 @@
     if (parent != null) {
       localContext = parent.localContext;
     } else {
-      localContext = new ThreadLocal<Object[]>();
+      // 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<>();
     }
   }
 
   /** Indexes bindings by type. */
   void index() {
     for (Binding<?> binding : state.getExplicitBindingsThisLevel().values()) {
-      index(binding);
+      bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
     }
   }
 
-  <T> void index(Binding<T> binding) {
-    bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
-  }
-
+  @Override
   public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
-    return bindingsMultimap.getAll(type);
+    @SuppressWarnings("unchecked") // safe because we only put matching entries into the map
+    List<Binding<T>> list = (List<Binding<T>>) (List) bindingsMultimap.get(type);
+    return Collections.unmodifiableList(list);
   }
 
   /** Returns the binding for {@code key} */
+  @Override
   public <T> BindingImpl<T> getBinding(Key<T> key) {
     Errors errors = new Errors(key);
     try {
@@ -160,6 +167,7 @@
     }
   }
 
+  @Override
   public <T> BindingImpl<T> getExistingBinding(Key<T> key) {
     // Check explicit bindings, i.e. bindings created by modules.
     BindingImpl<T> explicitBinding = state.getExplicitBinding(key);
@@ -171,7 +179,7 @@
       for (InjectorImpl injector = this; injector != null; injector = injector.parent) {
         @SuppressWarnings("unchecked")
         BindingImpl<T> jitBinding = (BindingImpl<T>) injector.jitBindings.get(key);
-        if(jitBinding != null) {
+        if (jitBinding != null) {
           return jitBinding;
         }
       }
@@ -179,15 +187,15 @@
 
     // 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)) {
+    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) {
+        Key<?> providedKey = (Key<?>) getProvidedKey((Key) key, new Errors());
+        if (getExistingBinding(providedKey) != null) {
           return getBinding(key);
         }
-      } catch(ErrorsException e) {
+      } catch (ErrorsException e) {
         throw new ConfigurationException(e.getErrors().getMessages());
       }
     }
@@ -197,8 +205,8 @@
   }
 
   /**
-   * 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
+   * 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.
    */
@@ -214,21 +222,22 @@
     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();
+    return new InternalInjectorCreator().parentInjector(this).addModules(modules).build();
   }
 
+  @Override
   public Injector createChildInjector(Module... modules) {
     return createChildInjector(ImmutableList.copyOf(modules));
   }
@@ -292,7 +301,8 @@
     return key.getTypeLiteral().getRawType().equals(TypeLiteral.class);
   }
 
-  private static <T> Key<T> getProvidedKey(Key<Provider<T>> key, Errors errors) throws ErrorsException {
+  private static <T> Key<T> getProvidedKey(Key<Provider<T>> key, Errors errors)
+      throws ErrorsException {
     Type providerType = key.getTypeLiteral().getType();
 
     // If the Provider has no type parameter (raw Provider)...
@@ -321,21 +331,26 @@
     }
 
     @SuppressWarnings("unchecked") // safe because T came from Key<MembersInjector<T>>
-    TypeLiteral<T> instanceType = (TypeLiteral<T>) TypeLiteral.get(
-        ((ParameterizedType) membersInjectorType).getActualTypeArguments()[0]);
+    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));
+    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);
+    return new InstanceBindingImpl<MembersInjector<T>>(
+        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>}.
+   * Creates a synthetic binding to {@code Provider<T>}, i.e. a binding to the provider from {@code
+   * Binding<T>}.
    */
   private <T> BindingImpl<Provider<T>> createProviderBinding(Key<Provider<T>> key, Errors errors)
       throws ErrorsException {
@@ -349,7 +364,11 @@
     final BindingImpl<T> providedBinding;
 
     ProviderBindingImpl(InjectorImpl injector, Key<Provider<T>> key, Binding<T> providedBinding) {
-      super(injector, key, providedBinding.getSource(), createInternalFactory(providedBinding),
+      super(
+          injector,
+          key,
+          providedBinding.getSource(),
+          createInternalFactory(providedBinding),
           Scoping.UNSCOPED);
       this.providedBinding = (BindingImpl<T>) providedBinding;
     }
@@ -357,42 +376,48 @@
     static <T> InternalFactory<Provider<T>> createInternalFactory(Binding<T> providedBinding) {
       final Provider<T> provider = providedBinding.getProvider();
       return new InternalFactory<Provider<T>>() {
-        public Provider<T> get(Errors errors, InternalContext context, Dependency dependency, boolean linked) {
+        @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 Objects.toStringHelper(ProviderBinding.class)
+    @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;
+      if (obj instanceof ProviderBindingImpl) {
+        ProviderBindingImpl<?> o = (ProviderBindingImpl<?>) obj;
         return getKey().equals(o.getKey())
-          && getScoping().equals(o.getScoping())
-          && Objects.equal(providedBinding, o.providedBinding);
+            && getScoping().equals(o.getScoping())
+            && Objects.equal(providedBinding, o.providedBinding);
       } else {
         return false;
       }
@@ -419,12 +444,17 @@
       return null;
     }
 
-    String stringValue = stringBinding.getProvider().get();
+    // We can't call getProvider().get() because this InstanceBinding may not have been inintialized
+    // yet (because we may have been called during InternalInjectorCreator.initializeStatically and
+    // instance binding validation hasn't happened yet.)
+    @SuppressWarnings("unchecked")
+    String stringValue = ((InstanceBinding<String>) stringBinding).getInstance();
     Object source = stringBinding.getSource();
 
     // Find a matching type converter.
     TypeLiteral<T> type = key.getTypeLiteral();
-    TypeConverterBinding typeConverterBinding = state.getConverter(stringValue, type, errors, source);
+    TypeConverterBinding typeConverterBinding =
+        state.getConverter(stringValue, type, errors, source);
 
     if (typeConverterBinding == null) {
       // No converter can handle the given type.
@@ -437,73 +467,91 @@
       T converted = (T) typeConverterBinding.getTypeConverter().convert(stringValue, type);
 
       if (converted == null) {
-        throw errors.converterReturnedNull(stringValue, source, type, typeConverterBinding)
+        throw errors
+            .converterReturnedNull(stringValue, source, type, typeConverterBinding)
             .toException();
       }
 
       if (!type.getRawType().isInstance(converted)) {
-        throw errors.conversionTypeError(stringValue, source, type, typeConverterBinding, converted)
+        throw errors
+            .conversionTypeError(stringValue, source, type, typeConverterBinding, converted)
             .toException();
       }
 
-      return new ConvertedConstantBindingImpl<T>(this, key, converted, stringBinding,
-          typeConverterBinding);
+      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)
+      throw errors
+          .conversionError(stringValue, source, type, typeConverterBinding, e)
           .toException();
     }
   }
 
-  private static class ConvertedConstantBindingImpl<T>
-      extends BindingImpl<T> implements ConvertedConstantBinding<T> {
+  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,
+        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);
+      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() {
+    @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 Objects.toStringHelper(ConvertedConstantBinding.class)
+    @Override
+    public String toString() {
+      return MoreObjects.toStringHelper(ConvertedConstantBinding.class)
           .add("key", getKey())
           .add("sourceKey", getSourceKey())
           .add("value", value)
@@ -512,11 +560,11 @@
 
     @Override
     public boolean equals(Object obj) {
-      if(obj instanceof ConvertedConstantBindingImpl) {
-        ConvertedConstantBindingImpl<?> o = (ConvertedConstantBindingImpl<?>)obj;
+      if (obj instanceof ConvertedConstantBindingImpl) {
+        ConvertedConstantBindingImpl<?> o = (ConvertedConstantBindingImpl<?>) obj;
         return getKey().equals(o.getKey())
-          && getScoping().equals(o.getScoping())
-          && Objects.equal(value, o.value);
+            && getScoping().equals(o.getScoping())
+            && Objects.equal(value, o.value);
       } else {
         return false;
       }
@@ -542,7 +590,7 @@
       Key<T> key = binding.getKey();
       jitBindings.put(key, binding);
       boolean successful = false;
-      DelayedInitialize delayed = (DelayedInitialize)binding;
+      DelayedInitialize delayed = (DelayedInitialize) binding;
       try {
         delayed.initialize(this, errors);
         successful = true;
@@ -560,32 +608,32 @@
 
   /**
    * 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.
+   * 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<Key> encountered) {
     boolean bindingFailed = false;
     Set<Dependency<?>> deps = getInternalDependencies(binding);
-    for(Dependency dep : deps) {
+    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
+      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
+        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;
+          if (depBinding instanceof ConstructorBindingImpl) {
+            ConstructorBindingImpl ctorBinding = (ConstructorBindingImpl) depBinding;
             ip = ctorBinding.getInternalConstructor();
-            if(!ctorBinding.isInitialized()) {
+            if (!ctorBinding.isInitialized()) {
               failed = true;
             }
           }
-          if(failed) {
+          if (failed) {
             removeFailedJitBinding(depBinding, ip);
             bindingFailed = true;
           }
-        } else if(state.getExplicitBinding(depKey) == null) {
+        } 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;
@@ -601,7 +649,7 @@
     jitBindings.remove(binding.getKey());
     membersInjectorStore.remove(binding.getKey().getTypeLiteral());
     provisionListenerStore.remove(binding);
-    if(ip != null) {
+    if (ip != null) {
       constructors.remove(ip);
     }
   }
@@ -609,10 +657,10 @@
   /** 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();
+    if (binding instanceof ConstructorBindingImpl) {
+      return ((ConstructorBindingImpl) binding).getInternalDependencies();
+    } else if (binding instanceof HasDependencies) {
+      return ((HasDependencies) binding).getDependencies();
     } else {
       return ImmutableSet.of();
     }
@@ -622,22 +670,23 @@
    * Creates a binding for an injectable type with the given scope. Looks for a scope on the type if
    * none is specified.
    */
-  <T> BindingImpl<T> createUninitializedBinding(Key<T> key, Scoping scoping, Object source,
-      Errors errors, boolean jitBinding) throws ErrorsException {
+  <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);
 
     // Don't try to inject arrays or enums annotated with @ImplementedBy.
     if (rawType.isArray() || (rawType.isEnum() && implementedBy != null)) {
-      throw errors.missingImplementation(key).toException();
+      throw errors.missingImplementationWithHint(key, this).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<T>) createTypeLiteralBinding(
-          (Key<TypeLiteral<Object>>) key, errors);
+      BindingImpl<T> binding =
+          (BindingImpl<T>) createTypeLiteralBinding((Key<TypeLiteral<Object>>) key, errors);
       return binding;
     }
 
@@ -654,8 +703,8 @@
       return createProvidedByBinding(key, scoping, providedBy, errors);
     }
 
-
-    return ConstructorBindingImpl.create(this,
+    return ConstructorBindingImpl.create(
+        this,
         key,
         null, /* use default constructor */
         source,
@@ -689,17 +738,22 @@
 
     @SuppressWarnings("unchecked") // by definition, innerType == T, so this is safe
     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);
+    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);
   }
 
   /** Creates a binding for a type annotated with @ProvidedBy. */
-  <T> BindingImpl<T> createProvidedByBinding(Key<T> key, Scoping scoping,
-      ProvidedBy providedBy, Errors errors) throws ErrorsException {
+  <T> BindingImpl<T> createProvidedByBinding(
+      Key<T> key, Scoping scoping, ProvidedBy providedBy, Errors errors) throws ErrorsException {
     Class<?> rawType = key.getTypeLiteral().getRawType();
-    Class<? extends Provider<?>> providerType = providedBy.value();
+    Class<? extends javax.inject.Provider<?>> providerType = providedBy.value();
 
     // Make sure it's not the same type. TODO: Can we check for deeper loops?
     if (providerType == rawType) {
@@ -712,21 +766,22 @@
     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);
+    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;
   }
 
   /** Creates a binding for a type annotated with @ImplementedBy. */
-  private <T> BindingImpl<T> createImplementedByBinding(Key<T> key, Scoping scoping,
-      ImplementedBy implementedBy, Errors errors)
+  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();
@@ -746,27 +801,14 @@
 
     // Look up the target binding.
     final Key<? extends T> targetKey = Key.get(subclass);
-    final BindingImpl<? extends T> targetBinding = getBindingOrThrow(targetKey, errors, JitLimitation.NEW_OR_EXISTING_JIT);
-
-    InternalFactory<T> internalFactory = new InternalFactory<T>() {
-      public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
-          throws ErrorsException {
-        context.pushState(targetKey, targetBinding.getSource());
-        try {
-          return targetBinding.getInternalFactory().get(
-              errors.withSource(targetKey), context, dependency, true);
-        } finally {
-          context.popState();
-        }
-      }
-    };
-
     Object source = rawType;
+    FactoryProxy<T> factory = new FactoryProxy<>(this, key, targetKey, source);
+    factory.notify(errors); // causes the factory to initialize itself internally
     return new LinkedBindingImpl<T>(
         this,
         key,
         source,
-        Scoping.<T>scope(key, this, internalFactory, source, scoping),
+        Scoping.<T>scope(key, this, factory, source, scoping),
         scoping,
         targetKey);
   }
@@ -775,18 +817,23 @@
    * Attempts to create a just-in-time binding for {@code key} in the root injector, falling back to
    * other ancestor injectors until this injector is tried.
    */
-  private <T> BindingImpl<T> createJustInTimeBindingRecursive(Key<T> key, Errors errors,
-      boolean jitDisabled, JitLimitation jitType) throws ErrorsException {
+  private <T> BindingImpl<T> createJustInTimeBindingRecursive(
+      Key<T> key, Errors errors, boolean jitDisabled, JitLimitation jitType)
+      throws ErrorsException {
     // ask the parent to create the JIT binding
     if (parent != null) {
       if (jitType == JitLimitation.NEW_OR_EXISTING_JIT
-          && jitDisabled && !parent.options.jitDisabled) {
+          && jitDisabled
+          && !parent.options.jitDisabled) {
         // If the binding would be forbidden here but allowed in a parent, report an error instead
         throw errors.jitDisabledInParent(key).toException();
       }
 
       try {
-        return parent.createJustInTimeBindingRecursive(key, new Errors(), jitDisabled,
+        return parent.createJustInTimeBindingRecursive(
+            key,
+            new Errors(),
+            jitDisabled,
             parent.options.jitDisabled ? JitLimitation.NO_JIT : jitType);
       } catch (ErrorsException ignored) {
       }
@@ -811,18 +858,20 @@
   /**
    * Returns a new just-in-time binding created by resolving {@code key}. The strategies used to
    * create just-in-time bindings are:
+   *
    * <ol>
-   *   <li>Internalizing Providers. If the requested binding is for {@code Provider<T>}, we delegate
+   * <li>Internalizing Providers. If the requested binding is for {@code Provider<T>}, we delegate
    *     to the binding for {@code T}.
-   *   <li>Converting constants.
-   *   <li>ImplementedBy and ProvidedBy annotations. Only for unannotated keys.
-   *   <li>The constructor of the raw type. Only for unannotated keys.
+   * <li>Converting constants.
+   * <li>ImplementedBy and ProvidedBy annotations. Only for unannotated keys.
+   * <li>The constructor of the raw type. Only for unannotated keys.
    * </ol>
    *
    * @throws com.google.inject.internal.ErrorsException if the binding cannot be created.
    */
-  private <T> BindingImpl<T> createJustInTimeBinding(Key<T> key, Errors errors,
-      boolean jitDisabled, JitLimitation jitType) throws ErrorsException {
+  private <T> BindingImpl<T> createJustInTimeBinding(
+      Key<T> key, Errors errors, boolean jitDisabled, JitLimitation jitType)
+      throws ErrorsException {
     int numErrorsBefore = errors.size();
 
     // Retrieve the sources before checking for blacklisting to guard against sources becoming null
@@ -858,9 +907,7 @@
       return convertedBinding;
     }
 
-    if (!isTypeLiteral(key)
-        && jitDisabled
-        && jitType != JitLimitation.NEW_OR_EXISTING_JIT) {
+    if (!isTypeLiteral(key) && jitDisabled && jitType != JitLimitation.NEW_OR_EXISTING_JIT) {
       throw errors.jitDisabled(key).toException();
     }
 
@@ -875,25 +922,28 @@
           // throw with a more appropriate message below
         }
       }
-      throw errors.missingImplementation(key).toException();
+      throw errors.missingImplementationWithHint(key, this).toException();
     }
 
     Object source = key.getTypeLiteral().getRawType();
-    BindingImpl<T> binding = createUninitializedBinding(key, Scoping.UNSCOPED, source, errors, true);
+    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 {
+  <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<?>>()
@@ -903,41 +953,19 @@
     }
   }
 
+  @Override
   public Map<Class<? extends Annotation>, Scope> getScopeBindings() {
     return ImmutableMap.copyOf(state.getScopes());
   }
 
+  @Override
   public Set<TypeConverterBinding> getTypeConverterBindings() {
     return ImmutableSet.copyOf(state.getConvertersThisLevel());
   }
 
-  private static class BindingsMultimap {
-    final Map<TypeLiteral<?>, List<Binding<?>>> multimap = Maps.newHashMap();
-
-    <T> void put(TypeLiteral<T> type, Binding<T> binding) {
-      List<Binding<?>> bindingsForType = multimap.get(type);
-      if (bindingsForType == null) {
-        bindingsForType = Lists.newArrayList();
-        multimap.put(type, bindingsForType);
-      }
-      bindingsForType.add(binding);
-    }
-
-
-    @SuppressWarnings("unchecked") // safe because we only put matching entries into the map
-    <T> List<Binding<T>> getAll(TypeLiteral<T> type) {
-      List<Binding<?>> bindings = multimap.get(type);
-      return bindings != null
-          ? Collections.<Binding<T>>unmodifiableList((List) multimap.get(type))
-          : ImmutableList.<Binding<T>>of();
-    }
-  }
-
-  /**
-   * Returns parameter injectors, or {@code null} if there are no parameters.
-   */
-  SingleParameterInjector<?>[] getParametersInjectors(
-      List<Dependency<?>> parameters, Errors errors) throws ErrorsException {
+  /** Returns parameter injectors, or {@code null} if there are no parameters. */
+  SingleParameterInjector<?>[] getParametersInjectors(List<Dependency<?>> parameters, Errors errors)
+      throws ErrorsException {
     if (parameters.isEmpty()) {
       return null;
     }
@@ -957,9 +985,10 @@
     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);
+  <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);
   }
 
@@ -978,12 +1007,14 @@
   /** Cached provision listener callbacks for each key. */
   ProvisionListenerCallbackStore provisionListenerStore;
 
+  @Override
   @SuppressWarnings("unchecked") // the members injector type is consistent with instance's type
   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 {
@@ -993,45 +1024,47 @@
     }
   }
 
+  @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 {
-    final Key<T> key = dependency.getKey();
-    final BindingImpl<? extends T> binding = getBindingOrThrow(key, errors, JitLimitation.NO_JIT);
+  <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() {
-        final Errors errors = new Errors(dependency);
+        InternalContext currentContext = enterContext();
+        Dependency previous = currentContext.pushDependency(dependency, source);
         try {
-          T t = callInContext(new ContextualCallable<T>() {
-            public T call(InternalContext context) throws ErrorsException {
-              Dependency previous = context.pushDependency(dependency, binding.getSource());
-              try {
-                return binding.getInternalFactory().get(errors, context, dependency, false);
-              } finally {
-                context.popStateAndSetDependency(previous);
-              }
-            }
-          });
-          errors.throwIfNewErrors(0);
+          T t = internalFactory.get(currentContext, dependency, false);
           return t;
-        } catch (ErrorsException e) {
-          throw new ProvisionException(errors.merge(e.getErrors()).getMessages());
+        } catch (InternalProvisionException e) {
+          throw e.addSource(dependency).toProvisionException();
+        } finally {
+          currentContext.popStateAndSetDependency(previous);
+          currentContext.close();
         }
       }
 
-      @Override public String toString() {
-        return binding.getInternalFactory().toString();
+      @Override
+      public String toString() {
+        return internalFactory.toString();
       }
     };
   }
 
+  @Override
   public <T> Provider<T> getProvider(final Key<T> key) {
     Errors errors = new Errors(key);
     try {
@@ -1043,77 +1076,68 @@
     }
   }
 
+  @Override
   public <T> T getInstance(Key<T> key) {
     return getProvider(key).get();
   }
 
+  @Override
   public <T> T getInstance(Class<T> type) {
     return getProvider(type).get();
   }
 
-  /** @see #getGlobalInternalContext */
+  /**
+   * Holds Object[] as a mutable wrapper, rather than InternalContext, since array operations are
+   * faster than ThreadLocal.set() / .get() operations.
+   *
+   * <p>Holds Object[] rather than InternalContext[], since localContext never gets cleaned up at
+   * any point. This could lead to problems when, for example, an OSGI application is reloaded, the
+   * InjectorImpl is destroyed, but the thread that the injector runs on is kept alive. In such a
+   * case, ThreadLocal itself would hold on to a reference to localContext, which would hold on to
+   * the old InternalContext.class object, which would hold on to the old classloader that loaded
+   * that class, and so on.
+   */
   private final ThreadLocal<Object[]> localContext;
-  /**
-   * Synchronization: map value is modified only for the current thread,
-   * it's ok to read map values of other threads. It can change between your
-   * calls.
-   *
-   * @see #getGlobalInternalContext
-   */
-  private static final ConcurrentMap<Thread, InternalContext> globalInternalContext =
-      Maps.newConcurrentMap();
 
-  /**
-   * Provides access to the internal context for the current injector of all threads.
-   * One does not need to use this from Guice source code as context could be passed on the stack.
-   * It is required for custom scopes which are called from Guice and sometimes do require
-   * access to current internal context, but it is not passed in. Contrary to {@link #localContext}
-   * it is not used to store injector-specific state, but to provide easy access to the current
-   * state.
-   *
-   * @return unmodifiable map
-   */
-  static Map<Thread, InternalContext> getGlobalInternalContext() {
-    return Collections.unmodifiableMap(globalInternalContext);
+  /** Only to be called by the {@link SingletonScope} provider. */
+  InternalContext getLocalContext() {
+    return (InternalContext) localContext.get()[0];
   }
 
-  /** Looks up thread local context. Creates (and removes) a new context if necessary. */
-  <T> T callInContext(ContextualCallable<T> callable) throws ErrorsException {
+  /**
+   * Looks up thread local context and {@link InternalContext#enter() enters} it or creates a new
+   * context if necessary.
+   *
+   * <p>All callers of this are responsible for calling {@link InternalContext#close()}. Typical
+   * usage should look like:
+   *
+   * <pre>{@code
+   * InternalContext ctx = injector.enterContext();
+   * try {
+   *   ... use ctx ...
+   * } finally {
+   *   ctx.close();
+   * }
+   * }</pre>
+   */
+  InternalContext enterContext() {
     Object[] reference = localContext.get();
     if (reference == null) {
       reference = new Object[1];
       localContext.set(reference);
     }
-    Thread currentThread = Thread.currentThread();
-    if (reference[0] == null) {
-      reference[0] = new InternalContext(options);
-      globalInternalContext.put(currentThread, (InternalContext) reference[0]);
-      try {
-        return callable.call((InternalContext) reference[0]);
-      } finally {
-        // Only clear contexts if this call created them.
-        reference[0] = null;
-        globalInternalContext.remove(currentThread);
-      }
+    InternalContext ctx = (InternalContext) reference[0];
+    if (ctx == null) {
+      reference[0] = ctx = new InternalContext(options, reference);
     } else {
-      Object previousGlobalInternalContext = globalInternalContext.get(currentThread);
-      globalInternalContext.put(currentThread, (InternalContext) reference[0]);
-      try {
-        // Someone else will clean up this local context.
-        return callable.call((InternalContext) reference[0]);
-      } finally {
-        if (previousGlobalInternalContext != null) {
-          globalInternalContext.put(currentThread, (InternalContext) previousGlobalInternalContext);
-        } else {
-          globalInternalContext.remove(currentThread);
-        }
-      }
+      ctx.enter();
     }
+    return ctx;
   }
 
   @Override
   public String toString() {
-    return Objects.toStringHelper(Injector.class)
+    return MoreObjects.toStringHelper(Injector.class)
         .add("bindings", state.getExplicitBindingsThisLevel().values())
         .toString();
   }
diff --git a/core/src/com/google/inject/internal/InjectorOptionsProcessor.java b/core/src/com/google/inject/internal/InjectorOptionsProcessor.java
index 61cc6ee..32bab00 100644
--- a/core/src/com/google/inject/internal/InjectorOptionsProcessor.java
+++ b/core/src/com/google/inject/internal/InjectorOptionsProcessor.java
@@ -53,11 +53,11 @@
     jitDisabled = true;
     return true;
   }
-  
+
   @Override
   public Boolean visit(RequireAtInjectOnConstructorsOption option) {
     atInjectRequired = true;
-    return true;    
+    return true;
   }
 
   @Override
@@ -68,7 +68,7 @@
 
   InjectorOptions getOptions(Stage stage, InjectorOptions parentOptions) {
     checkNotNull(stage, "stage must be set");
-    if(parentOptions == null) {
+    if (parentOptions == null) {
       return new InjectorOptions(
           stage,
           jitDisabled,
@@ -85,5 +85,4 @@
           exactBindingAnnotationsRequired || parentOptions.exactBindingAnnotationsRequired);
     }
   }
-
 }
diff --git a/core/src/com/google/inject/internal/InjectorShell.java b/core/src/com/google/inject/internal/InjectorShell.java
index 5982bb3..e2ddcd9 100644
--- a/core/src/com/google/inject/internal/InjectorShell.java
+++ b/core/src/com/google/inject/internal/InjectorShell.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -39,14 +39,13 @@
 import com.google.inject.spi.PrivateElements;
 import com.google.inject.spi.ProvisionListenerBinding;
 import com.google.inject.spi.TypeListenerBinding;
-
 import java.util.List;
 import java.util.logging.Logger;
 
 /**
- * A partially-initialized injector. See {@link InternalInjectorCreator}, which
- * uses this to build a tree of injectors in batch.
- * 
+ * A partially-initialized injector. See {@link InternalInjectorCreator}, which uses this to build a
+ * tree of injectors in batch.
+ *
  * @author jessewilson@google.com (Jesse Wilson)
  */
 final class InjectorShell {
@@ -54,7 +53,7 @@
   private final List<Element> elements;
   private final InjectorImpl injector;
 
-  private InjectorShell(Builder builder, List<Element> elements, InjectorImpl injector) {
+  private InjectorShell(List<Element> elements, InjectorImpl injector) {
     this.elements = elements;
     this.injector = injector;
   }
@@ -80,7 +79,7 @@
 
     /** null unless this exists in a {@link Binder#newPrivateBinder private environment} */
     private PrivateElementsImpl privateElements;
-    
+
     Builder stage(Stage stage) {
       this.stage = stage;
       return this;
@@ -105,7 +104,7 @@
         this.modules.add(module);
       }
     }
-    
+
     Stage getStage() {
       return options.stage;
     }
@@ -136,12 +135,12 @@
         modules.add(0, new InheritedScannersModule(parent.state));
       }
       elements.addAll(Elements.getElements(stage, modules));
-      
+
       // Look for injector-changing options
       InjectorOptionsProcessor optionsProcessor = new InjectorOptionsProcessor(errors);
       optionsProcessor.process(null, elements);
       options = optionsProcessor.getOptions(stage, options);
-      
+
       InjectorImpl injector = new InjectorImpl(parent, state, options);
       if (privateElements != null) {
         privateElements.initInjector(injector);
@@ -179,7 +178,7 @@
       bindStage(injector, stage);
       bindInjector(injector);
       bindLogger(injector);
-      
+
       // Process all normal bindings, then UntargettedBindings.
       // This is necessary because UntargettedBindings can create JIT bindings
       // and need all their other dependencies set up ahead of time.
@@ -191,7 +190,7 @@
       stopwatch.resetAndLog("Module annotated method scanners creation");
 
       List<InjectorShell> injectorShells = Lists.newArrayList();
-      injectorShells.add(new InjectorShell(this, elements, injector));
+      injectorShells.add(new InjectorShell(elements, injector));
 
       // recursively build child shells
       PrivateElementProcessor processor = new PrivateElementProcessor(errors);
@@ -213,15 +212,21 @@
   }
 
   /**
-   * The Injector is a special case because we allow both parent and child injectors to both have
-   * a binding for that key.
+   * The Injector is a special case because we allow both parent and child injectors to both have a
+   * binding for that key.
    */
   private static void bindInjector(InjectorImpl injector) {
     Key<Injector> key = Key.get(Injector.class);
     InjectorFactory injectorFactory = new InjectorFactory(injector);
-    injector.state.putBinding(key,
-        new ProviderInstanceBindingImpl<Injector>(injector, key, SourceProvider.UNKNOWN_SOURCE,
-            injectorFactory, Scoping.UNSCOPED, injectorFactory,
+    injector.state.putBinding(
+        key,
+        new ProviderInstanceBindingImpl<Injector>(
+            injector,
+            key,
+            SourceProvider.UNKNOWN_SOURCE,
+            injectorFactory,
+            Scoping.UNSCOPED,
+            injectorFactory,
             ImmutableSet.<InjectionPoint>of()));
   }
 
@@ -232,15 +237,17 @@
       this.injector = injector;
     }
 
-    public Injector get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
-        throws ErrorsException {
+    @Override
+    public Injector get(InternalContext context, Dependency<?> dependency, boolean linked) {
       return injector;
     }
 
+    @Override
     public Injector get() {
       return injector;
     }
 
+    @Override
     public String toString() {
       return "Provider<Injector>";
     }
@@ -253,42 +260,53 @@
   private static void bindLogger(InjectorImpl injector) {
     Key<Logger> key = Key.get(Logger.class);
     LoggerFactory loggerFactory = new LoggerFactory();
-    injector.state.putBinding(key,
-        new ProviderInstanceBindingImpl<Logger>(injector, key,
-            SourceProvider.UNKNOWN_SOURCE, loggerFactory, Scoping.UNSCOPED,
-            loggerFactory, ImmutableSet.<InjectionPoint>of()));
+    injector.state.putBinding(
+        key,
+        new ProviderInstanceBindingImpl<Logger>(
+            injector,
+            key,
+            SourceProvider.UNKNOWN_SOURCE,
+            loggerFactory,
+            Scoping.UNSCOPED,
+            loggerFactory,
+            ImmutableSet.<InjectionPoint>of()));
   }
 
   private static class LoggerFactory implements InternalFactory<Logger>, Provider<Logger> {
-    public Logger get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) {
+    @Override
+    public Logger get(InternalContext context, Dependency<?> dependency, boolean linked) {
       InjectionPoint injectionPoint = dependency.getInjectionPoint();
       return injectionPoint == null
           ? Logger.getAnonymousLogger()
           : Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
     }
 
+    @Override
     public Logger get() {
       return Logger.getAnonymousLogger();
     }
 
+    @Override
     public String toString() {
       return "Provider<Logger>";
     }
   }
-  
+
   private static void bindStage(InjectorImpl injector, Stage stage) {
     Key<Stage> key = Key.get(Stage.class);
-    InstanceBindingImpl<Stage> stageBinding = new InstanceBindingImpl<Stage>(
-        injector,
-        key,
-        SourceProvider.UNKNOWN_SOURCE,
-        new ConstantFactory<Stage>(Initializables.of(stage)),
-        ImmutableSet.<InjectionPoint>of(),
-        stage);
+    InstanceBindingImpl<Stage> stageBinding =
+        new InstanceBindingImpl<Stage>(
+            injector,
+            key,
+            SourceProvider.UNKNOWN_SOURCE,
+            new ConstantFactory<Stage>(Initializables.of(stage)),
+            ImmutableSet.<InjectionPoint>of(),
+            stage);
     injector.state.putBinding(key, stageBinding);
   }
 
   private static class RootModule implements Module {
+    @Override
     public void configure(Binder binder) {
       binder = binder.withSource(SourceProvider.UNKNOWN_SOURCE);
       binder.bindScope(Singleton.class, SINGLETON);
@@ -303,6 +321,7 @@
       this.state = state;
     }
 
+    @Override
     public void configure(Binder binder) {
       for (ModuleAnnotatedMethodScannerBinding binding : state.getScannerBindings()) {
         binding.applyTo(binder);
diff --git a/core/src/com/google/inject/internal/InstanceBindingImpl.java b/core/src/com/google/inject/internal/InstanceBindingImpl.java
index 9b7a483..44d53b4 100644
--- a/core/src/com/google/inject/internal/InstanceBindingImpl.java
+++ b/core/src/com/google/inject/internal/InstanceBindingImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,80 +16,83 @@
 
 package com.google.inject.internal;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableSet;
 import com.google.inject.Binder;
 import com.google.inject.Key;
-import com.google.inject.Provider;
 import com.google.inject.spi.BindingTargetVisitor;
 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.util.Providers;
-
 import java.util.Set;
 
 final class InstanceBindingImpl<T> extends BindingImpl<T> implements InstanceBinding<T> {
 
   final T instance;
-  final Provider<T> provider;
   final ImmutableSet<InjectionPoint> injectionPoints;
 
-  public InstanceBindingImpl(InjectorImpl injector, Key<T> key, Object source,
-      InternalFactory<? extends T> internalFactory, Set<InjectionPoint> injectionPoints,
+  public InstanceBindingImpl(
+      InjectorImpl injector,
+      Key<T> key,
+      Object source,
+      InternalFactory<? extends T> internalFactory,
+      Set<InjectionPoint> injectionPoints,
       T instance) {
     super(injector, key, source, internalFactory, Scoping.EAGER_SINGLETON);
     this.injectionPoints = ImmutableSet.copyOf(injectionPoints);
     this.instance = instance;
-    this.provider = Providers.of(instance);
   }
 
-  public InstanceBindingImpl(Object source, Key<T> key, Scoping scoping,
-      Set<InjectionPoint> injectionPoints, T instance) {
+  public InstanceBindingImpl(
+      Object source, Key<T> key, Scoping scoping, Set<InjectionPoint> injectionPoints, T instance) {
     super(source, key, scoping);
     this.injectionPoints = ImmutableSet.copyOf(injectionPoints);
     this.instance = instance;
-    this.provider = Providers.of(instance);
   }
 
-  @Override public Provider<T> getProvider() {
-    return this.provider;
-  }
-
+  @Override
   public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
     return visitor.visit(this);
   }
 
+  @Override
   public T getInstance() {
     return instance;
   }
 
+  @Override
   public Set<InjectionPoint> getInjectionPoints() {
     return injectionPoints;
   }
 
+  @Override
   public Set<Dependency<?>> getDependencies() {
     return instance instanceof HasDependencies
         ? ImmutableSet.copyOf(((HasDependencies) instance).getDependencies())
         : Dependency.forInjectionPoints(injectionPoints);
   }
 
+  @Override
   public BindingImpl<T> withScoping(Scoping scoping) {
     return new InstanceBindingImpl<T>(getSource(), getKey(), scoping, injectionPoints, instance);
   }
 
+  @Override
   public BindingImpl<T> withKey(Key<T> key) {
     return new InstanceBindingImpl<T>(getSource(), key, getScoping(), injectionPoints, instance);
   }
 
+  @Override
   public void applyTo(Binder binder) {
     // instance bindings aren't scoped
     binder.withSource(getSource()).bind(getKey()).toInstance(instance);
   }
 
-  @Override public String toString() {
-    return Objects.toStringHelper(InstanceBinding.class)
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(InstanceBinding.class)
         .add("key", getKey())
         .add("source", getSource())
         .add("instance", instance)
@@ -98,11 +101,11 @@
 
   @Override
   public boolean equals(Object obj) {
-    if(obj instanceof InstanceBindingImpl) {
-      InstanceBindingImpl<?> o = (InstanceBindingImpl<?>)obj;
+    if (obj instanceof InstanceBindingImpl) {
+      InstanceBindingImpl<?> o = (InstanceBindingImpl<?>) obj;
       return getKey().equals(o.getKey())
-        && getScoping().equals(o.getScoping())
-        && Objects.equal(instance, o.instance);
+          && getScoping().equals(o.getScoping())
+          && Objects.equal(instance, o.instance);
     } else {
       return false;
     }
diff --git a/core/src/com/google/inject/internal/InterceptorBindingProcessor.java b/core/src/com/google/inject/internal/InterceptorBindingProcessor.java
index e352672..de2174a 100644
--- a/core/src/com/google/inject/internal/InterceptorBindingProcessor.java
+++ b/core/src/com/google/inject/internal/InterceptorBindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,9 +30,11 @@
     super(errors);
   }
 
-  @Override public Boolean visit(InterceptorBinding command) {
-    injector.state.addMethodAspect(new MethodAspect(
-        command.getClassMatcher(), command.getMethodMatcher(), command.getInterceptors()));
+  @Override
+  public Boolean visit(InterceptorBinding command) {
+    injector.state.addMethodAspect(
+        new MethodAspect(
+            command.getClassMatcher(), command.getMethodMatcher(), command.getInterceptors()));
     return true;
   }
 }
diff --git a/core/src/com/google/inject/internal/InterceptorStackCallback.java b/core/src/com/google/inject/internal/InterceptorStackCallback.java
index f12ddaf..7ae22bb 100644
--- a/core/src/com/google/inject/internal/InterceptorStackCallback.java
+++ b/core/src/com/google/inject/internal/InterceptorStackCallback.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,15 @@
 package com.google.inject.internal;
 
 import com.google.common.collect.Lists;
-
-import net.sf.cglib.proxy.MethodProxy;
-
-import org.aopalliance.intercept.MethodInterceptor;
-import org.aopalliance.intercept.MethodInvocation;
-
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import net.sf.cglib.proxy.MethodProxy;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
 
 /**
  * Intercepts a method with a stack of interceptors.
@@ -36,22 +33,24 @@
  * @author crazybob@google.com (Bob Lee)
  */
 final class InterceptorStackCallback implements net.sf.cglib.proxy.MethodInterceptor {
-  private static final Set<String> AOP_INTERNAL_CLASSES = new HashSet<String>(Arrays.asList(
-      InterceptorStackCallback.class.getName(),
-      InterceptedMethodInvocation.class.getName(),
-      MethodProxy.class.getName()));
+  private static final Set<String> AOP_INTERNAL_CLASSES =
+      new HashSet<String>(
+          Arrays.asList(
+              InterceptorStackCallback.class.getName(),
+              InterceptedMethodInvocation.class.getName(),
+              MethodProxy.class.getName()));
 
   final MethodInterceptor[] interceptors;
   final Method method;
 
-  public InterceptorStackCallback(Method method,
-      List<MethodInterceptor> interceptors) {
+  public InterceptorStackCallback(Method method, List<MethodInterceptor> interceptors) {
     this.method = method;
     this.interceptors = interceptors.toArray(new MethodInterceptor[interceptors.size()]);
   }
 
-  public Object intercept(Object proxy, Method method, Object[] arguments,
-      MethodProxy methodProxy) throws Throwable {
+  @Override
+  public Object intercept(Object proxy, Method method, Object[] arguments, MethodProxy methodProxy)
+      throws Throwable {
     return new InterceptedMethodInvocation(proxy, methodProxy, arguments, 0).proceed();
   }
 
@@ -62,49 +61,54 @@
     final MethodProxy methodProxy;
     final int index;
 
-    public InterceptedMethodInvocation(Object proxy, MethodProxy methodProxy,
-        Object[] arguments, int index) {
+    public InterceptedMethodInvocation(
+        Object proxy, MethodProxy methodProxy, Object[] arguments, int index) {
       this.proxy = proxy;
       this.methodProxy = methodProxy;
       this.arguments = arguments;
       this.index = index;
     }
 
+    @Override
     public Object proceed() throws Throwable {
       try {
         return index == interceptors.length
             ? methodProxy.invokeSuper(proxy, arguments)
-            : interceptors[index].invoke(
-                new InterceptedMethodInvocation(proxy, methodProxy, arguments, index + 1));
+            : interceptors[index]
+                .invoke(new InterceptedMethodInvocation(proxy, methodProxy, arguments, index + 1));
       } catch (Throwable t) {
         pruneStacktrace(t);
         throw t;
       }
     }
 
+    @Override
     public Method getMethod() {
       return method;
     }
 
+    @Override
     public Object[] getArguments() {
       return arguments;
     }
 
+    @Override
     public Object getThis() {
       return proxy;
     }
 
+    @Override
     public AccessibleObject getStaticPart() {
       return getMethod();
     }
   }
 
   /**
-   * Removes stacktrace elements related to AOP internal mechanics from the
-   * throwable's stack trace and any causes it may have.
+   * Removes stacktrace elements related to AOP internal mechanics from the throwable's stack trace
+   * and any causes it may have.
    */
   private void pruneStacktrace(Throwable throwable) {
-    for(Throwable t = throwable; t != null; t = t.getCause()) {
+    for (Throwable t = throwable; t != null; t = t.getCause()) {
       StackTraceElement[] stackTrace = t.getStackTrace();
       List<StackTraceElement> pruned = Lists.newArrayList();
       for (StackTraceElement element : stackTrace) {
diff --git a/core/src/com/google/inject/internal/InternalContext.java b/core/src/com/google/inject/internal/InternalContext.java
index 0af1969..59c77c5 100644
--- a/core/src/com/google/inject/internal/InternalContext.java
+++ b/core/src/com/google/inject/internal/InternalContext.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,99 +16,26 @@
 
 package com.google.inject.internal;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.inject.Key;
 import com.google.inject.internal.InjectorImpl.InjectorOptions;
 import com.google.inject.spi.Dependency;
-import com.google.inject.spi.DependencyAndSource;
-
-import java.util.Arrays;
-import java.util.List;
+import java.util.IdentityHashMap;
 import java.util.Map;
 
 /**
- * Internal context. Used to coordinate injections and support circular
- * dependencies.
+ * Internal context. Used to coordinate injections and support circular dependencies.
  *
  * @author crazybob@google.com (Bob Lee)
  */
-final class InternalContext {
+final class InternalContext implements AutoCloseable {
 
   private final InjectorOptions options;
 
-  private Map<Object, ConstructionContext<?>> constructionContexts = Maps.newHashMap();
+  private final Map<Object, ConstructionContext<?>> constructionContexts =
+      new IdentityHashMap<Object, ConstructionContext<?>>();
 
   /** Keeps track of the type that is currently being requested for injection. */
   private Dependency<?> dependency;
 
-  /** Keeps track of the hierarchy of types needed during injection. */
-  private final DependencyStack state = new DependencyStack();
-
-  InternalContext(InjectorOptions options) {
-    this.options = options;
-  }
-
-  public InjectorOptions getInjectorOptions() {
-    return options;
-  }
-
-  @SuppressWarnings("unchecked")
-  public <T> ConstructionContext<T> getConstructionContext(Object key) {
-    ConstructionContext<T> constructionContext
-        = (ConstructionContext<T>) constructionContexts.get(key);
-    if (constructionContext == null) {
-      constructionContext = new ConstructionContext<T>();
-      constructionContexts.put(key, constructionContext);
-    }
-    return constructionContext;
-  }
-
-  public Dependency<?> getDependency() {
-    return dependency;
-  }
-
-  /** Sets the new current dependency & adds it to the state. */
-  public Dependency<?> pushDependency(Dependency<?> dependency, Object source) {
-    Dependency<?> previous = this.dependency;
-    this.dependency = dependency;
-    state.add(dependency, source);
-    return previous;
-  }
-
-  /** Pops the current state & sets the new dependency. */
-  public void popStateAndSetDependency(Dependency<?> newDependency) {
-    state.pop();
-    this.dependency = newDependency;
-  }
-
-  /** Adds to the state without setting the dependency. */
-  public void pushState(Key<?> key, Object source) {
-    state.add(key, source);
-  }
-  
-  /** Pops from the state without setting a dependency. */
-  public void popState() {
-    state.pop();
-  }
-
-  /** Returns the current dependency chain (all the state). */
-  public List<DependencyAndSource> getDependencyChain() {
-    ImmutableList.Builder<DependencyAndSource> builder = ImmutableList.builder();
-    for (int i = 0; i < state.size(); i += 2) {
-      Object evenEntry = state.get(i);
-      Dependency<?> dependency;
-      if (evenEntry instanceof Key) {
-        dependency = Dependency.get((Key<?>) evenEntry);
-      } else {
-        dependency = (Dependency<?>) evenEntry;
-      }
-      builder.add(new DependencyAndSource(dependency, state.get(i + 1)));
-    }
-    return builder.build();
-  }
-
   /**
    * Keeps track of the hierarchy of types needed during injection.
    *
@@ -116,29 +43,126 @@
    * even indices, and sources on odd indices. This structure is to avoid the memory overhead of
    * DependencyAndSource objects, which can add to several tens of megabytes in large applications.
    */
-  private static final class DependencyStack {
-    private Object[] elements = new Object[16];
-    private int size = 0;
+  private Object[] dependencyStack = new Object[16];
 
-    public void add(Object dependencyOrKey, Object source) {
-      if (elements.length < size + 2) {
-        elements = Arrays.copyOf(elements, (elements.length*3)/2 + 2);
-      }
-      elements[size++] = dependencyOrKey;
-      elements[size++] = source;
+  private int dependencyStackSize = 0;
+
+
+  /**
+   * The number of times {@link #enter()} has been called + 1 for initial construction. This value
+   * is decremented when {@link #exit()} is called.
+   */
+  private int enterCount;
+
+  /**
+   * A single element array to clear when the {@link #enterCount} hits {@code 0}.
+   *
+   * <p>This is the value stored in the {@code InjectorImpl.localContext} thread local.
+   */
+  private final Object[] toClear;
+
+  InternalContext(InjectorOptions options, Object[] toClear) {
+    this.options = options;
+    this.toClear = toClear;
+    this.enterCount = 1;
+  }
+
+  /** Should only be called by InjectorImpl.enterContext(). */
+  void enter() {
+    enterCount++;
+  }
+
+  /** Should be called any any method that received an instance via InjectorImpl.enterContext(). */
+  @Override
+  public void close() {
+    int newCount = --enterCount;
+    if (newCount < 0) {
+      throw new IllegalStateException("Called close() too many times");
     }
-
-    public void pop() {
-      elements[--size] = null;
-      elements[--size] = null;
-    }
-
-    public Object get(int i) {
-      return elements[i];
-    }
-
-    public int size() {
-      return size;
+    if (newCount == 0) {
+      toClear[0] = null;
     }
   }
+
+  InjectorOptions getInjectorOptions() {
+    return options;
+  }
+
+  @SuppressWarnings("unchecked")
+  <T> ConstructionContext<T> getConstructionContext(Object key) {
+    ConstructionContext<T> constructionContext =
+        (ConstructionContext<T>) constructionContexts.get(key);
+    if (constructionContext == null) {
+      constructionContext = new ConstructionContext<>();
+      constructionContexts.put(key, constructionContext);
+    }
+    return constructionContext;
+  }
+
+  Dependency<?> getDependency() {
+    return dependency;
+  }
+
+  /** Sets the new current dependency & adds it to the state. */
+  Dependency<?> pushDependency(Dependency<?> dependency, Object source) {
+    Dependency<?> previous = this.dependency;
+    this.dependency = dependency;
+    doPushState(dependency, source);
+    return previous;
+  }
+
+
+  /** Pops the current state & sets the new dependency. */
+  void popStateAndSetDependency(Dependency<?> newDependency) {
+    popState();
+    this.dependency = newDependency;
+  }
+
+
+  /** Adds to the state without setting the dependency. */
+  void pushState(com.google.inject.Key<?> key, Object source) {
+    doPushState(key, source);
+  }
+
+
+  private void doPushState(Object dependencyOrKey, Object source) {
+    int localSize = dependencyStackSize;
+    Object[] localStack = dependencyStack;
+    if (localStack.length < localSize + 2) {
+      localStack = dependencyStack =
+        java.util.Arrays.copyOf(localStack, (localStack.length * 3) / 2 + 2);
+    }
+    localStack[localSize++] = dependencyOrKey;
+    localStack[localSize++] = source;
+    dependencyStackSize = localSize;
+  }
+
+
+  /** Pops from the state without setting a dependency. */
+  void popState() {
+    // N.B. we don't null out the array entries.  It isn't necessary since all the objects in the
+    // array (Key, Dependency, or Binding source objects) are all tied to the lifetime of the
+    // injector, which is greater than the lifetime of this object.  So removing them from the array
+    // doesn't matter.
+    dependencyStackSize -= 2;
+  }
+
+
+  /** Returns the current dependency chain (all the state stored in the dependencyStack). */
+  java.util.List<com.google.inject.spi.DependencyAndSource> getDependencyChain() {
+    com.google.common.collect.ImmutableList.Builder<com.google.inject.spi.DependencyAndSource>
+        builder = com.google.common.collect.ImmutableList.builder();
+    for (int i = 0; i < dependencyStackSize; i += 2) {
+      Object evenEntry = dependencyStack[i];
+      Dependency<?> dependency;
+      if (evenEntry instanceof com.google.inject.Key) {
+        dependency = Dependency.get((com.google.inject.Key<?>) evenEntry);
+      } else {
+        dependency = (Dependency<?>) evenEntry;
+      }
+      builder.add(new com.google.inject.spi.DependencyAndSource(dependency, dependencyStack[i + 1]));
+    }
+    return builder.build();
+  }
+
 }
diff --git a/core/src/com/google/inject/internal/InternalFactory.java b/core/src/com/google/inject/internal/InternalFactory.java
index 2267b12..00f0d11 100644
--- a/core/src/com/google/inject/internal/InternalFactory.java
+++ b/core/src/com/google/inject/internal/InternalFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,12 +27,12 @@
 
   /**
    * Creates an object to be injected.
+   *
    * @param context of this injection
    * @param linked true if getting as a result of a linked binding
-   *
-   * @throws com.google.inject.internal.ErrorsException if a value cannot be provided
-   * @return instance to be injected
+   * @throws com.google.inject.internal.InternalProvisionException if a value cannot be provided
+   * @return instance that was created
    */
-  T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
-      throws ErrorsException;
+  T get(InternalContext context, Dependency<?> dependency, boolean linked)
+      throws InternalProvisionException;
 }
diff --git a/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java b/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java
index c02c70e..218ce7c 100644
--- a/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java
+++ b/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,11 +22,11 @@
 import com.google.inject.spi.ProviderInstanceBinding;
 
 /**
- * Adapts {@link ProviderInstanceBinding} providers, ensuring circular proxies
- * fail (or proxy) properly.
- * 
+ * Adapts {@link ProviderInstanceBinding} providers, ensuring circular proxies fail (or proxy)
+ * properly.
+ *
  * @author sameb@google.com (Sam Berlin)
-*/
+ */
 final class InternalFactoryToInitializableAdapter<T> extends ProviderInternalFactory<T> {
 
   private final ProvisionListenerStackCallback<T> provisionCallback;
@@ -34,29 +34,34 @@
 
   public InternalFactoryToInitializableAdapter(
       Initializable<? extends javax.inject.Provider<? extends T>> initializable,
-      Object source, ProvisionListenerStackCallback<T> provisionCallback) {
+      Object source,
+      ProvisionListenerStackCallback<T> provisionCallback) {
     super(source);
-    this.provisionCallback = checkNotNull(provisionCallback, "provisionCallback");
+    this.provisionCallback = provisionCallback;
     this.initializable = checkNotNull(initializable, "provider");
   }
 
-  public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
-      throws ErrorsException {
-    return circularGet(initializable.get(errors), errors, context, dependency,
-        provisionCallback);
-  }
-  
   @Override
-  protected T provision(javax.inject.Provider<? extends T> provider, Errors errors,
-      Dependency<?> dependency, ConstructionContext<T> constructionContext) throws ErrorsException {
+  public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+      throws InternalProvisionException {
+    return circularGet(initializable.get(), context, dependency, provisionCallback);
+  }
+
+  @Override
+  protected T provision(
+      javax.inject.Provider<? extends T> provider,
+      Dependency<?> dependency,
+      ConstructionContext<T> constructionContext)
+      throws InternalProvisionException {
     try {
-      return super.provision(provider, errors, dependency, constructionContext);
-    } catch(RuntimeException userException) {
-      throw errors.withSource(source).errorInProvider(userException).toException();
+      return super.provision(provider, dependency, constructionContext);
+    } catch (RuntimeException userException) {
+      throw InternalProvisionException.errorInProvider(userException).addSource(source);
     }
   }
 
-  @Override public String toString() {
+  @Override
+  public String toString() {
     return initializable.toString();
   }
 }
diff --git a/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java b/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java
index 4cd1b2e..690f683 100644
--- a/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java
+++ b/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,9 +21,7 @@
 import com.google.inject.Provider;
 import com.google.inject.spi.Dependency;
 
-/**
- * @author crazybob@google.com (Bob Lee)
-*/
+/** @author crazybob@google.com (Bob Lee) */
 final class InternalFactoryToProviderAdapter<T> implements InternalFactory<T> {
 
   private final Provider<? extends T> provider;
@@ -34,17 +32,22 @@
     this.source = checkNotNull(source, "source");
   }
 
-  public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
-      throws ErrorsException {
-    // TODO(sameb): Does this need to push state into the context?
+  @Override
+  public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+      throws InternalProvisionException {
     try {
-      return errors.checkForNull(provider.get(), source, dependency);
+      T t = provider.get();
+      if (t == null && !dependency.isNullable()) {
+        InternalProvisionException.onNullInjectedIntoNonNullableDependency(source, dependency);
+      }
+      return t;
     } catch (RuntimeException userException) {
-      throw errors.withSource(source).errorInProvider(userException).toException();
+      throw InternalProvisionException.errorInProvider(userException).addSource(source);
     }
   }
 
-  @Override public String toString() {
+  @Override
+  public String toString() {
     return provider.toString();
   }
 }
diff --git a/core/src/com/google/inject/internal/InternalFlags.java b/core/src/com/google/inject/internal/InternalFlags.java
index 85c07ac..4127ea6 100644
--- a/core/src/com/google/inject/internal/InternalFlags.java
+++ b/core/src/com/google/inject/internal/InternalFlags.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2013 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -121,11 +121,14 @@
     Class<T> enumType = defaultValue.getDeclaringClass();
     String value = null;
     try {
-      value = AccessController.doPrivileged(new PrivilegedAction<String>() {
-        public String run() {
-          return System.getProperty(name);
-        }
-      });
+      value =
+          AccessController.doPrivileged(
+              new PrivilegedAction<String>() {
+                @Override
+                public String run() {
+                  return System.getProperty(name);
+                }
+              });
       return (value != null && value.length() > 0) ? Enum.valueOf(enumType, value) : defaultValue;
     } catch (SecurityException e) {
       return secureValue;
diff --git a/core/src/com/google/inject/internal/InternalInjectorCreator.java b/core/src/com/google/inject/internal/InternalInjectorCreator.java
index d40bc83..64c4cf1 100644
--- a/core/src/com/google/inject/internal/InternalInjectorCreator.java
+++ b/core/src/com/google/inject/internal/InternalInjectorCreator.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,6 @@
 
 package com.google.inject.internal;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
 import com.google.inject.Binding;
 import com.google.inject.Injector;
 import com.google.inject.Key;
@@ -30,8 +28,8 @@
 import com.google.inject.internal.util.Stopwatch;
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.TypeConverterBinding;
-
 import java.lang.annotation.Annotation;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -43,14 +41,15 @@
  * top-level injector.
  *
  * <p>Injector construction happens in two phases.
+ *
  * <ol>
- *   <li>Static building. In this phase, we interpret commands, create bindings, and inspect 
+ * <li>Static building. In this phase, we interpret commands, create bindings, and inspect
  *     dependencies. During this phase, we hold a lock to ensure consistency with parent injectors.
- *     No user code is executed in this phase.</li>
- *   <li>Dynamic injection. In this phase, we call user code. We inject members that requested
+ *     No user code is executed in this phase.
+ * <li>Dynamic injection. In this phase, we call user code. We inject members that requested
  *     injection. This may require user's objects be created and their providers be called. And we
  *     create eager singletons. In this phase, user code may have started other threads. This phase
- *     is not executed for injectors created using {@link Stage#TOOL the tool stage}</li>
+ *     is not executed for injectors created using {@link Stage#TOOL the tool stage}
  * </ol>
  *
  * @author crazybob@google.com (Bob Lee)
@@ -67,12 +66,12 @@
 
   private final InjectorShell.Builder shellBuilder = new InjectorShell.Builder();
   private List<InjectorShell> shells;
-  
+
   public InternalInjectorCreator() {
     injectionRequestProcessor = new InjectionRequestProcessor(errors, initializer);
     bindingData = new ProcessedBindingData();
   }
-  
+
   public InternalInjectorCreator stage(Stage stage) {
     shellBuilder.stage(stage);
     return this;
@@ -146,6 +145,11 @@
     }
     stopwatch.resetAndLog("Provider verification");
 
+    // This needs to come late since some user bindings rely on requireBinding calls to create
+    // jit bindings during the LookupProcessor.
+    bindingData.initializeDelayedBindings();
+    stopwatch.resetAndLog("Delayed Binding initialization");
+
     for (InjectorShell shell : shells) {
       if (!shell.getElements().isEmpty()) {
         throw new AssertionError("Failed to execute " + shell.getElements());
@@ -155,9 +159,7 @@
     errors.throwCreationExceptionIfErrorsExist();
   }
 
-  /**
-   * Returns the injector being constructed. This is not necessarily the root injector.
-   */
+  /** Returns the injector being constructed. This is not necessarily the root injector. */
   private Injector primaryInjector() {
     return shells.get(0).getInjector();
   }
@@ -175,7 +177,7 @@
     stopwatch.resetAndLog("Instance injection");
     errors.throwCreationExceptionIfErrorsExist();
 
-    if(shellBuilder.getStage() != Stage.TOOL) {
+    if (shellBuilder.getStage() != Stage.TOOL) {
       for (InjectorShell shell : shells) {
         loadEagerSingletons(shell.getInjector(), shellBuilder.getStage(), errors);
       }
@@ -189,33 +191,33 @@
    * while we're binding these singletons are not be eager.
    */
   void loadEagerSingletons(InjectorImpl injector, Stage stage, final Errors errors) {
+    List<BindingImpl<?>> candidateBindings = new ArrayList<>();
     @SuppressWarnings("unchecked") // casting Collection<Binding> to Collection<BindingImpl> is safe
-    Iterable<BindingImpl<?>> candidateBindings = ImmutableList.copyOf(Iterables.concat(
-        (Collection) injector.state.getExplicitBindingsThisLevel().values(),
-        injector.jitBindings.values()));
-    for (final BindingImpl<?> binding : candidateBindings) {
-      if (isEagerSingleton(injector, binding, stage)) {
-        try {
-          injector.callInContext(new ContextualCallable<Void>() {
-            Dependency<?> dependency = Dependency.get(binding.getKey());
-            public Void call(InternalContext context) {
-              Dependency previous = context.pushDependency(dependency, binding.getSource());
-              Errors errorsForBinding = errors.withSource(dependency);
-              try {
-                binding.getInternalFactory().get(errorsForBinding, context, dependency, false);
-              } catch (ErrorsException e) {
-                errorsForBinding.merge(e.getErrors());
-              } finally {
-                context.popStateAndSetDependency(previous);
-              }
+    Collection<BindingImpl<?>> bindingsAtThisLevel =
+        (Collection) injector.state.getExplicitBindingsThisLevel().values();
+    candidateBindings.addAll(bindingsAtThisLevel);
+    synchronized (injector.state.lock()) {
+      // jit bindings must be accessed while holding the lock.
+      candidateBindings.addAll(injector.jitBindings.values());
+    }
+    InternalContext context = injector.enterContext();
+    try {
+      for (BindingImpl<?> binding : candidateBindings) {
+        if (isEagerSingleton(injector, binding, stage)) {
+          Dependency<?> dependency = Dependency.get(binding.getKey());
+          Dependency previous = context.pushDependency(dependency, binding.getSource());
 
-              return null;
+          try {
+            binding.getInternalFactory().get(context, dependency, false);
+          } catch (InternalProvisionException e) {
+            errors.withSource(dependency).merge(e);
+          } finally {
+              context.popStateAndSetDependency(previous);
             }
-          });
-        } catch (ErrorsException e) {
-          throw new AssertionError();
         }
       }
+    } finally {
+      context.close();
     }
   }
 
@@ -238,70 +240,106 @@
   /** {@link Injector} exposed to users in {@link Stage#TOOL}. */
   static class ToolStageInjector implements Injector {
     private final Injector delegateInjector;
-    
+
     ToolStageInjector(Injector delegateInjector) {
       this.delegateInjector = delegateInjector;
     }
+
+    @Override
     public void injectMembers(Object o) {
       throw new UnsupportedOperationException(
-        "Injector.injectMembers(Object) is not supported in Stage.TOOL");
+          "Injector.injectMembers(Object) is not supported in Stage.TOOL");
     }
+
+    @Override
     public Map<Key<?>, Binding<?>> getBindings() {
       return this.delegateInjector.getBindings();
     }
+
+    @Override
     public Map<Key<?>, Binding<?>> getAllBindings() {
       return this.delegateInjector.getAllBindings();
     }
+
+    @Override
     public <T> Binding<T> getBinding(Key<T> key) {
       return this.delegateInjector.getBinding(key);
     }
+
+    @Override
     public <T> Binding<T> getBinding(Class<T> type) {
       return this.delegateInjector.getBinding(type);
     }
+
+    @Override
     public <T> Binding<T> getExistingBinding(Key<T> key) {
       return this.delegateInjector.getExistingBinding(key);
     }
+
+    @Override
     public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
       return this.delegateInjector.findBindingsByType(type);
     }
+
+    @Override
     public Injector getParent() {
       return delegateInjector.getParent();
     }
+
+    @Override
     public Injector createChildInjector(Iterable<? extends Module> modules) {
       return delegateInjector.createChildInjector(modules);
     }
+
+    @Override
     public Injector createChildInjector(Module... modules) {
       return delegateInjector.createChildInjector(modules);
     }
+
+    @Override
     public Map<Class<? extends Annotation>, Scope> getScopeBindings() {
       return delegateInjector.getScopeBindings();
     }
+
+    @Override
     public Set<TypeConverterBinding> getTypeConverterBindings() {
       return delegateInjector.getTypeConverterBindings();
     }
+
+    @Override
     public <T> Provider<T> getProvider(Key<T> key) {
       throw new UnsupportedOperationException(
-        "Injector.getProvider(Key<T>) is not supported in Stage.TOOL");
+          "Injector.getProvider(Key<T>) is not supported in Stage.TOOL");
     }
+
+    @Override
     public <T> Provider<T> getProvider(Class<T> type) {
       throw new UnsupportedOperationException(
-        "Injector.getProvider(Class<T>) is not supported in Stage.TOOL");
+          "Injector.getProvider(Class<T>) is not supported in Stage.TOOL");
     }
+
+    @Override
     public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
       throw new UnsupportedOperationException(
-        "Injector.getMembersInjector(TypeLiteral<T>) is not supported in Stage.TOOL");
+          "Injector.getMembersInjector(TypeLiteral<T>) is not supported in Stage.TOOL");
     }
+
+    @Override
     public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
       throw new UnsupportedOperationException(
-        "Injector.getMembersInjector(Class<T>) is not supported in Stage.TOOL");
+          "Injector.getMembersInjector(Class<T>) is not supported in Stage.TOOL");
     }
+
+    @Override
     public <T> T getInstance(Key<T> key) {
       throw new UnsupportedOperationException(
-        "Injector.getInstance(Key<T>) is not supported in Stage.TOOL");
+          "Injector.getInstance(Key<T>) is not supported in Stage.TOOL");
     }
+
+    @Override
     public <T> T getInstance(Class<T> type) {
       throw new UnsupportedOperationException(
-        "Injector.getInstance(Class<T>) is not supported in Stage.TOOL");
+          "Injector.getInstance(Class<T>) is not supported in Stage.TOOL");
     }
   }
 }
diff --git a/core/src/com/google/inject/internal/InternalProviderInstanceBindingImpl.java b/core/src/com/google/inject/internal/InternalProviderInstanceBindingImpl.java
new file mode 100644
index 0000000..dd941aa
--- /dev/null
+++ b/core/src/com/google/inject/internal/InternalProviderInstanceBindingImpl.java
@@ -0,0 +1,195 @@
+package com.google.inject.internal;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.HasDependencies;
+import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.ProviderWithExtensionVisitor;
+
+/**
+ * A {@link ProviderInstanceBindingImpl} for implementing 'native' guice extensions.
+ *
+ * <p>Beyond the normal binding contract that is mostly handled by our baseclass, this also
+ * implements {@link DelayedInitialize} in order to initialize factory state.
+ */
+final class InternalProviderInstanceBindingImpl<T> extends ProviderInstanceBindingImpl<T>
+    implements DelayedInitialize {
+  enum InitializationTiming {
+    /** This factory can be initialized eagerly. This should be the case for most things. */
+    EAGER,
+
+    /**
+     * Initialization of this factory should be delayed until after all other static initialization
+     * completes. This will be useful for factories that need to call {@link
+     * InjectorImpl#getExistingBinding(Key)} to not create jit bindings, but also want to be able to
+     * conditionally consume jit bindings created by other other bindings.
+     */
+    DELAYED;
+  }
+
+  private final Factory<T> originalFactory;
+
+  InternalProviderInstanceBindingImpl(
+      InjectorImpl injector,
+      Key<T> key,
+      Object source,
+      Factory<T> originalFactory,
+      InternalFactory<? extends T> scopedFactory,
+      Scoping scoping) {
+    super(
+        injector,
+        key,
+        source,
+        scopedFactory,
+        scoping,
+        originalFactory,
+        ImmutableSet.<InjectionPoint>of());
+    this.originalFactory = originalFactory;
+  }
+
+  InitializationTiming getInitializationTiming() {
+    return originalFactory.initializationTiming;
+  }
+
+  @Override
+  public void initialize(final InjectorImpl injector, final Errors errors) throws ErrorsException {
+    originalFactory.source = getSource();
+    originalFactory.provisionCallback = injector.provisionListenerStore.get(this);
+    // For these kinds of providers, the 'user supplied provider' is really 'guice supplied'
+    // So make our user supplied provider just delegate to the guice supplied one.
+    originalFactory.delegateProvider = getProvider();
+    originalFactory.initialize(injector, errors);
+  }
+
+  /**
+   * A base factory implementation. Any Factories that delegate to other bindings should use the
+   * {@code CyclicFactory} subclass, but trivial factories can use this one.
+   */
+  abstract static class Factory<T> implements InternalFactory<T>, Provider<T>, HasDependencies {
+    private final InitializationTiming initializationTiming;
+    private Object source;
+    private Provider<T> delegateProvider;
+    ProvisionListenerStackCallback<T> provisionCallback;
+
+    Factory(InitializationTiming initializationTiming) {
+      this.initializationTiming = initializationTiming;
+    }
+    /**
+     * The binding source.
+     *
+     * <p>May be useful for augmenting runtime error messages.
+     *
+     * <p>Note: this will return {#code null} until {@link #initialize(InjectorImpl, Errors)} has
+     * already been called.
+     */
+    final Object getSource() {
+      return source;
+    }
+
+    /**
+     * A callback that allows for implementations to fetch dependencies on other bindings.
+     *
+     * <p>Will be called exactly once, prior to any call to {@link #doProvision}.
+     */
+    abstract void initialize(InjectorImpl injector, Errors errors) throws ErrorsException;
+
+    @Override
+    public final T get() {
+      Provider<T> local = delegateProvider;
+      if (local == null) {
+        throw new IllegalStateException(
+            "This Provider cannot be used until the Injector has been created.");
+      }
+      return local.get();
+    }
+
+    @Override
+    public T get(final InternalContext context, final Dependency<?> dependency, boolean linked)
+        throws InternalProvisionException {
+      if (provisionCallback == null) {
+        return doProvision(context, dependency);
+      } else {
+        return provisionCallback.provision(
+            context,
+            new ProvisionCallback<T>() {
+              @Override
+              public T call() throws InternalProvisionException {
+                return doProvision(context, dependency);
+              }
+            });
+      }
+    }
+    /**
+     * Creates an object to be injected.
+     *
+     * @throws com.google.inject.internal.InternalProvisionException if a value cannot be provided
+     * @return instance to be injected
+     */
+    protected abstract T doProvision(InternalContext context, Dependency<?> dependency)
+        throws InternalProvisionException;
+  }
+
+  /**
+   * An base factory implementation that can be extended to provide a specialized implementation of
+   * a {@link ProviderWithExtensionVisitor} and also implements {@link InternalFactory}
+   */
+  abstract static class CyclicFactory<T> extends Factory<T> {
+
+    CyclicFactory(InitializationTiming initializationTiming) {
+      super(initializationTiming);
+    }
+
+    @Override
+    public final T get(
+        final InternalContext context, final Dependency<?> dependency, boolean linked)
+        throws InternalProvisionException {
+      final ConstructionContext<T> constructionContext = context.getConstructionContext(this);
+      // We have a circular reference between bindings. Return a proxy.
+      if (constructionContext.isConstructing()) {
+        Class<?> expectedType = dependency.getKey().getTypeLiteral().getRawType();
+        @SuppressWarnings("unchecked")
+        T proxyType =
+            (T) constructionContext.createProxy(context.getInjectorOptions(), expectedType);
+        return proxyType;
+      }
+      // Optimization: Don't go through the callback stack if no one's listening.
+      constructionContext.startConstruction();
+      try {
+        if (provisionCallback == null) {
+          return provision(dependency, context, constructionContext);
+        } else {
+          return provisionCallback.provision(
+              context,
+              new ProvisionCallback<T>() {
+                @Override
+                public T call() throws InternalProvisionException {
+                  return provision(dependency, context, constructionContext);
+                }
+              });
+        }
+      } finally {
+        constructionContext.removeCurrentReference();
+        constructionContext.finishConstruction();
+      }
+    }
+
+    private T provision(
+        Dependency<?> dependency,
+        InternalContext context,
+        ConstructionContext<T> constructionContext)
+        throws InternalProvisionException {
+      try {
+        T t = doProvision(context, dependency);
+        constructionContext.setProxyDelegates(t);
+        return t;
+      } catch (InternalProvisionException ipe) {
+        throw ipe.addSource(getSource());
+      } catch (Throwable t) {
+        throw InternalProvisionException.errorInProvider(t).addSource(getSource());
+      }
+    }
+  }
+}
diff --git a/core/src/com/google/inject/internal/InternalProvisionException.java b/core/src/com/google/inject/internal/InternalProvisionException.java
new file mode 100644
index 0000000..4a49d92
--- /dev/null
+++ b/core/src/com/google/inject/internal/InternalProvisionException.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2017 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.inject.internal;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.inject.Guice;
+import com.google.inject.Key;
+import com.google.inject.MembersInjector;
+import com.google.inject.Provides;
+import com.google.inject.ProvisionException;
+import com.google.inject.TypeLiteral;
+import com.google.inject.internal.util.SourceProvider;
+import com.google.inject.internal.util.StackTraceElements;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.Message;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A checked exception for provisioning errors.
+ *
+ * <p>This is the internal dual of {@link ProvisionException}, similar to the relationship between
+ * {@link com.google.inject.ConfigurationException} and {@link ErrorsException}. This is useful for
+ * several reasons:
+ *
+ * <ul>
+ *   <li>Since it is a checked exception, we get some assistance from the java compiler in ensuring
+ *       that we correctly handle it everywhere. ProvisionException is unchecked.
+ *   <li>Since this is an internal package, we can add useful construction and mutation APIs that
+ *       would be undesirable in a public supported API.
+ * </ul>
+ *
+ * <p>This exception will be thrown when errors are encountered during provisioning, ErrorsException
+ * will continue to be used for errors that are encountered during provisioning and both make use of
+ * the {@link Message} as the core model.
+ *
+ * <p>NOTE: this object stores a list of messages but in the most common case the cardinality will
+ * be 1. The only time that multiple errors might be reported via this mechanism is when {@link
+ * #errorInUserCode} is called with an exception that holds multiple errors (like
+ * ProvisionException).
+ */
+public final class InternalProvisionException extends Exception {
+  private static final Logger logger = Logger.getLogger(Guice.class.getName());
+  private static final Set<Dependency<?>> warnedDependencies =
+      Collections.newSetFromMap(new ConcurrentHashMap<Dependency<?>, Boolean>());
+
+
+  public static InternalProvisionException circularDependenciesDisabled(Class<?> expectedType) {
+    return create(
+        "Found a circular dependency involving %s, and circular dependencies are disabled.",
+        expectedType);
+  }
+
+  public static InternalProvisionException cannotProxyClass(Class<?> expectedType) {
+    return create(
+        "Tried proxying %s to support a circular dependency, but it is not an interface.",
+        expectedType);
+  }
+
+  public static InternalProvisionException create(String format, Object... arguments) {
+    return new InternalProvisionException(Messages.create(format, arguments));
+  }
+
+  public static InternalProvisionException errorInUserCode(
+      Throwable cause, String messageFormat, Object... arguments) {
+    Collection<Message> messages = Errors.getMessagesFromThrowable(cause);
+    if (!messages.isEmpty()) {
+      // TODO(lukes): it seems like we are dropping some valuable context here..
+      // consider eliminating this special case
+      return new InternalProvisionException(messages);
+    } else {
+      return new InternalProvisionException(Messages.create(cause, messageFormat, arguments));
+    }
+  }
+
+  public static InternalProvisionException subtypeNotProvided(
+      Class<? extends javax.inject.Provider<?>> providerType, Class<?> type) {
+    return create("%s doesn't provide instances of %s.", providerType, type);
+  }
+
+  public static InternalProvisionException errorInProvider(Throwable cause) {
+    return errorInUserCode(cause, "Error in custom provider, %s", cause);
+  }
+
+  public static InternalProvisionException errorInjectingMethod(Throwable cause) {
+    return errorInUserCode(cause, "Error injecting method, %s", cause);
+  }
+
+  public static InternalProvisionException errorInjectingConstructor(Throwable cause) {
+    return errorInUserCode(cause, "Error injecting constructor, %s", cause);
+  }
+
+  public static InternalProvisionException errorInUserInjector(
+      MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException cause) {
+    return errorInUserCode(
+        cause, "Error injecting %s using %s.%n Reason: %s", type, listener, cause);
+  }
+
+  public static InternalProvisionException jitDisabled(Key<?> key) {
+    return create("Explicit bindings are required and %s is not explicitly bound.", key);
+  }
+
+  public static InternalProvisionException errorNotifyingInjectionListener(
+      InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException cause) {
+    return errorInUserCode(
+        cause, "Error notifying InjectionListener %s of %s.%n Reason: %s", listener, type, cause);
+  }
+
+  /**
+   * Returns {@code value} if it is non-null or allowed to be null. Otherwise a message is added and
+   * an {@code InternalProvisionException} is thrown.
+   */
+  static void onNullInjectedIntoNonNullableDependency(Object source, Dependency<?> dependency)
+      throws InternalProvisionException {
+    // Hack to allow null parameters to @Provides methods, for backwards compatibility.
+    if (dependency.getInjectionPoint().getMember() instanceof Method) {
+      Method annotated = (Method) dependency.getInjectionPoint().getMember();
+      if (annotated.isAnnotationPresent(Provides.class)) {
+        switch (InternalFlags.getNullableProvidesOption()) {
+          case ERROR:
+            break; // break out & let the below exception happen
+          case IGNORE:
+            return; // user doesn't care about injecting nulls to non-@Nullables.
+          case WARN:
+            // Warn only once, otherwise we spam logs too much.
+            if (warnedDependencies.add(dependency)) {
+              logger.log(
+                  Level.WARNING,
+                  "Guice injected null into {0} (a {1}), please mark it @Nullable."
+                      + " Use -Dguice_check_nullable_provides_params=ERROR to turn this into an"
+                      + " error.",
+                  new Object[] {
+                    Messages.formatParameter(dependency), Messages.convert(dependency.getKey())
+                  });
+            }
+            return;
+        }
+      }
+    }
+
+    Object formattedDependency =
+        (dependency.getParameterIndex() != -1)
+            ? Messages.formatParameter(dependency)
+            : StackTraceElements.forMember(dependency.getInjectionPoint().getMember());
+
+    throw InternalProvisionException.create(
+            "null returned by binding at %s%n but %s is not @Nullable", source, formattedDependency)
+        .addSource(source);
+  }
+
+  private final List<Object> sourcesToPrepend = new ArrayList<>();
+  private final ImmutableList<Message> errors;
+
+  private InternalProvisionException(Message error) {
+    this(ImmutableList.of(error));
+  }
+
+  private InternalProvisionException(Iterable<Message> errors) {
+    this.errors = ImmutableList.copyOf(errors);
+    checkArgument(!this.errors.isEmpty(), "Can't create a provision exception with no errors");
+  }
+
+  /**
+   * Prepends the given {@code source} to the stack of binding sources for the errors reported in
+   * this exception.
+   *
+   * <p>See {@link Errors#withSource(Object)}
+   *
+   * <p>It is expected that this method is called as the exception propagates up the stack.
+   *
+   * @param source
+   * @return {@code this}
+   */
+  InternalProvisionException addSource(Object source) {
+    if (source == SourceProvider.UNKNOWN_SOURCE) {
+      return this;
+    }
+    int sz = sourcesToPrepend.size();
+    if (sz > 0 && sourcesToPrepend.get(sz - 1) == source) {
+      // This is for when there are two identical sources added in a row.  This behavior is copied
+      // from Errors.withSource where it can happen when an constructor/provider method throws an
+      // exception
+      return this;
+    }
+    sourcesToPrepend.add(source);
+    return this;
+  }
+
+  ImmutableList<Message> getErrors() {
+    ImmutableList.Builder<Message> builder = ImmutableList.builder();
+    // reverse them since sources are added as the exception propagates (so the first source is the
+    // last one added)
+    List<Object> newSources = Lists.reverse(sourcesToPrepend);
+    for (Message error : errors) {
+      builder.add(Messages.mergeSources(newSources, error));
+    }
+    return builder.build();
+  }
+
+  /** Returns this exception convered to a ProvisionException. */
+  public ProvisionException toProvisionException() {
+    return new ProvisionException(getErrors());
+  }
+}
diff --git a/core/src/com/google/inject/internal/LinkedBindingImpl.java b/core/src/com/google/inject/internal/LinkedBindingImpl.java
index 8f83324..f2e1a03 100644
--- a/core/src/com/google/inject/internal/LinkedBindingImpl.java
+++ b/core/src/com/google/inject/internal/LinkedBindingImpl.java
@@ -16,6 +16,7 @@
 
 package com.google.inject.internal;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableSet;
 import com.google.inject.Binder;
@@ -24,15 +25,19 @@
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.HasDependencies;
 import com.google.inject.spi.LinkedKeyBinding;
-
 import java.util.Set;
 
-public final class LinkedBindingImpl<T> extends BindingImpl<T> implements LinkedKeyBinding<T>, HasDependencies {
+public final class LinkedBindingImpl<T> extends BindingImpl<T>
+    implements LinkedKeyBinding<T>, HasDependencies {
 
   final Key<? extends T> targetKey;
 
-  public LinkedBindingImpl(InjectorImpl injector, Key<T> key, Object source,
-      InternalFactory<? extends T> internalFactory, Scoping scoping,
+  public LinkedBindingImpl(
+      InjectorImpl injector,
+      Key<T> key,
+      Object source,
+      InternalFactory<? extends T> internalFactory,
+      Scoping scoping,
       Key<? extends T> targetKey) {
     super(injector, key, source, internalFactory, scoping);
     this.targetKey = targetKey;
@@ -43,32 +48,39 @@
     this.targetKey = targetKey;
   }
 
+  @Override
   public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
     return visitor.visit(this);
   }
 
+  @Override
   public Key<? extends T> getLinkedKey() {
     return targetKey;
   }
 
+  @Override
   public Set<Dependency<?>> getDependencies() {
     return ImmutableSet.<Dependency<?>>of(Dependency.get(targetKey));
   }
 
+  @Override
   public BindingImpl<T> withScoping(Scoping scoping) {
     return new LinkedBindingImpl<T>(getSource(), getKey(), scoping, targetKey);
   }
 
+  @Override
   public BindingImpl<T> withKey(Key<T> key) {
     return new LinkedBindingImpl<T>(getSource(), key, getScoping(), targetKey);
   }
 
+  @Override
   public void applyTo(Binder binder) {
     getScoping().applyTo(binder.withSource(getSource()).bind(getKey()).to(getLinkedKey()));
   }
 
-  @Override public String toString() {
-    return Objects.toStringHelper(LinkedKeyBinding.class)
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(LinkedKeyBinding.class)
         .add("key", getKey())
         .add("source", getSource())
         .add("scope", getScoping())
@@ -78,11 +90,11 @@
 
   @Override
   public boolean equals(Object obj) {
-    if(obj instanceof LinkedBindingImpl) {
-      LinkedBindingImpl<?> o = (LinkedBindingImpl<?>)obj;
+    if (obj instanceof LinkedBindingImpl) {
+      LinkedBindingImpl<?> o = (LinkedBindingImpl<?>) obj;
       return getKey().equals(o.getKey())
-        && getScoping().equals(o.getScoping())
-        && Objects.equal(targetKey, o.targetKey);
+          && getScoping().equals(o.getScoping())
+          && Objects.equal(targetKey, o.targetKey);
     } else {
       return false;
     }
diff --git a/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java b/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java
index a4a78a5..fa9d792 100644
--- a/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java
+++ b/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java
@@ -16,6 +16,7 @@
 
 package com.google.inject.internal;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableSet;
 import com.google.inject.Binder;
@@ -24,17 +25,20 @@
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.HasDependencies;
 import com.google.inject.spi.ProviderKeyBinding;
-
 import java.util.Set;
 
-final class LinkedProviderBindingImpl<T>
-    extends BindingImpl<T> implements ProviderKeyBinding<T>, HasDependencies, DelayedInitialize {
+final class LinkedProviderBindingImpl<T> extends BindingImpl<T>
+    implements ProviderKeyBinding<T>, HasDependencies, DelayedInitialize {
 
   final Key<? extends javax.inject.Provider<? extends T>> providerKey;
   final DelayedInitialize delayedInitializer;
 
-  private LinkedProviderBindingImpl(InjectorImpl injector, Key<T> key, Object source,
-      InternalFactory<? extends T> internalFactory, Scoping scoping,
+  private LinkedProviderBindingImpl(
+      InjectorImpl injector,
+      Key<T> key,
+      Object source,
+      InternalFactory<? extends T> internalFactory,
+      Scoping scoping,
       Key<? extends javax.inject.Provider<? extends T>> providerKey,
       DelayedInitialize delayedInitializer) {
     super(injector, key, source, internalFactory, scoping);
@@ -42,60 +46,79 @@
     this.delayedInitializer = delayedInitializer;
   }
 
-  public LinkedProviderBindingImpl(InjectorImpl injector, Key<T> key, Object source,
-      InternalFactory<? extends T> internalFactory, Scoping scoping,
+  public LinkedProviderBindingImpl(
+      InjectorImpl injector,
+      Key<T> key,
+      Object source,
+      InternalFactory<? extends T> internalFactory,
+      Scoping scoping,
       Key<? extends javax.inject.Provider<? extends T>> providerKey) {
     this(injector, key, source, internalFactory, scoping, providerKey, null);
   }
 
-  LinkedProviderBindingImpl(Object source, Key<T> key, Scoping scoping,
+  LinkedProviderBindingImpl(
+      Object source,
+      Key<T> key,
+      Scoping scoping,
       Key<? extends javax.inject.Provider<? extends T>> providerKey) {
     super(source, key, scoping);
     this.providerKey = providerKey;
     this.delayedInitializer = null;
   }
 
-  static <T> LinkedProviderBindingImpl<T> createWithInitializer(InjectorImpl injector, Key<T> key,
-      Object source, InternalFactory<? extends T> internalFactory, Scoping scoping,
+  static <T> LinkedProviderBindingImpl<T> createWithInitializer(
+      InjectorImpl injector,
+      Key<T> key,
+      Object source,
+      InternalFactory<? extends T> internalFactory,
+      Scoping scoping,
       Key<? extends javax.inject.Provider<? extends T>> providerKey,
       DelayedInitialize delayedInitializer) {
-    return new LinkedProviderBindingImpl<T>(injector, key, source, internalFactory, scoping,
-        providerKey, delayedInitializer);
+    return new LinkedProviderBindingImpl<T>(
+        injector, key, source, internalFactory, scoping, providerKey, delayedInitializer);
   }
 
+  @Override
   public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
     return visitor.visit(this);
   }
 
+  @Override
   public Key<? extends javax.inject.Provider<? extends T>> getProviderKey() {
     return providerKey;
   }
 
+  @Override
   public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
     if (delayedInitializer != null) {
       delayedInitializer.initialize(injector, errors);
     }
   }
 
+  @Override
   public Set<Dependency<?>> getDependencies() {
     return ImmutableSet.<Dependency<?>>of(Dependency.get(providerKey));
   }
 
+  @Override
   public BindingImpl<T> withScoping(Scoping scoping) {
     return new LinkedProviderBindingImpl<T>(getSource(), getKey(), scoping, providerKey);
   }
 
+  @Override
   public BindingImpl<T> withKey(Key<T> key) {
     return new LinkedProviderBindingImpl<T>(getSource(), key, getScoping(), providerKey);
   }
 
+  @Override
   public void applyTo(Binder binder) {
-    getScoping().applyTo(binder.withSource(getSource())
-        .bind(getKey()).toProvider(getProviderKey()));
+    getScoping()
+        .applyTo(binder.withSource(getSource()).bind(getKey()).toProvider(getProviderKey()));
   }
 
-  @Override public String toString() {
-    return Objects.toStringHelper(ProviderKeyBinding.class)
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(ProviderKeyBinding.class)
         .add("key", getKey())
         .add("source", getSource())
         .add("scope", getScoping())
@@ -105,11 +128,11 @@
 
   @Override
   public boolean equals(Object obj) {
-    if(obj instanceof LinkedProviderBindingImpl) {
-      LinkedProviderBindingImpl<?> o = (LinkedProviderBindingImpl<?>)obj;
+    if (obj instanceof LinkedProviderBindingImpl) {
+      LinkedProviderBindingImpl<?> o = (LinkedProviderBindingImpl<?>) obj;
       return getKey().equals(o.getKey())
-        && getScoping().equals(o.getScoping())
-        && Objects.equal(providerKey, o.providerKey);
+          && getScoping().equals(o.getScoping())
+          && Objects.equal(providerKey, o.providerKey);
     } else {
       return false;
     }
diff --git a/core/src/com/google/inject/internal/ListenerBindingProcessor.java b/core/src/com/google/inject/internal/ListenerBindingProcessor.java
index e8ebed2..e70acb5 100644
--- a/core/src/com/google/inject/internal/ListenerBindingProcessor.java
+++ b/core/src/com/google/inject/internal/ListenerBindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,13 +30,15 @@
     super(errors);
   }
 
-  @Override public Boolean visit(TypeListenerBinding binding) {
+  @Override
+  public Boolean visit(TypeListenerBinding binding) {
     injector.state.addTypeListener(binding);
     return true;
   }
-  
-  @Override public Boolean visit(ProvisionListenerBinding binding) {
+
+  @Override
+  public Boolean visit(ProvisionListenerBinding binding) {
     injector.state.addProvisionListener(binding);
     return true;
   }
-}
\ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/LookupProcessor.java b/core/src/com/google/inject/internal/LookupProcessor.java
index bf11b83..5e68505 100644
--- a/core/src/com/google/inject/internal/LookupProcessor.java
+++ b/core/src/com/google/inject/internal/LookupProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,10 +33,11 @@
     super(errors);
   }
 
-  @Override public <T> Boolean visit(MembersInjectorLookup<T> lookup) {
+  @Override
+  public <T> Boolean visit(MembersInjectorLookup<T> lookup) {
     try {
-      MembersInjector<T> membersInjector
-          = injector.membersInjectorStore.get(lookup.getType(), errors);
+      MembersInjector<T> membersInjector =
+          injector.membersInjectorStore.get(lookup.getType(), errors);
       lookup.initializeDelegate(membersInjector);
     } catch (ErrorsException e) {
       errors.merge(e.getErrors()); // TODO: source
@@ -45,7 +46,8 @@
     return true;
   }
 
-  @Override public <T> Boolean visit(ProviderLookup<T> lookup) {
+  @Override
+  public <T> Boolean visit(ProviderLookup<T> lookup) {
     // ensure the provider can be created
     try {
       Provider<T> provider = injector.getProviderOrThrow(lookup.getDependency(), errors);
diff --git a/core/src/com/google/inject/internal/Lookups.java b/core/src/com/google/inject/internal/Lookups.java
index 2b32c7a..d3e64d8 100644
--- a/core/src/com/google/inject/internal/Lookups.java
+++ b/core/src/com/google/inject/internal/Lookups.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/core/src/com/google/inject/internal/MembersInjectorImpl.java b/core/src/com/google/inject/internal/MembersInjectorImpl.java
index 498b441..c1503ea 100644
--- a/core/src/com/google/inject/internal/MembersInjectorImpl.java
+++ b/core/src/com/google/inject/internal/MembersInjectorImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,71 +33,77 @@
 final class MembersInjectorImpl<T> implements MembersInjector<T> {
   private final TypeLiteral<T> typeLiteral;
   private final InjectorImpl injector;
-  private final ImmutableList<SingleMemberInjector> memberInjectors;
-  private final ImmutableSet<MembersInjector<? super T>> userMembersInjectors;
-  private final ImmutableSet<InjectionListener<? super T>> injectionListeners;
-  /*if[AOP]*/
-  private final ImmutableList<MethodAspect> addedAspects;
+  // a null list means empty. Since it is common for many of these lists to be empty we can save
+  // some memory lookups by representing empty as null.
+  /* @Nullable */ private final ImmutableList<SingleMemberInjector> memberInjectors;
+  /* @Nullable */ private final ImmutableList<MembersInjector<? super T>> userMembersInjectors;
+  /* @Nullable */ private final ImmutableList<InjectionListener<? super T>> injectionListeners;
+  /*if[AOP]*//* @Nullable */ private final ImmutableList<MethodAspect> addedAspects;
   /*end[AOP]*/
 
-  MembersInjectorImpl(InjectorImpl injector, TypeLiteral<T> typeLiteral,
-      EncounterImpl<T> encounter, ImmutableList<SingleMemberInjector> memberInjectors) {
+  MembersInjectorImpl(
+      InjectorImpl injector,
+      TypeLiteral<T> typeLiteral,
+      EncounterImpl<T> encounter,
+      ImmutableList<SingleMemberInjector> memberInjectors) {
     this.injector = injector;
     this.typeLiteral = typeLiteral;
-    this.memberInjectors = memberInjectors;
-    this.userMembersInjectors = encounter.getMembersInjectors();
-    this.injectionListeners = encounter.getInjectionListeners();
+    this.memberInjectors = memberInjectors.isEmpty() ? null : memberInjectors;
+    this.userMembersInjectors =
+        encounter.getMembersInjectors().isEmpty() ? null : encounter.getMembersInjectors().asList();
+    this.injectionListeners =
+        encounter.getInjectionListeners().isEmpty()
+            ? null
+            : encounter.getInjectionListeners().asList();
     /*if[AOP]*/
-    this.addedAspects = encounter.getAspects();
+    this.addedAspects = encounter.getAspects().isEmpty() ? null : encounter.getAspects();
     /*end[AOP]*/
   }
 
   public ImmutableList<SingleMemberInjector> getMemberInjectors() {
-    return memberInjectors;
+    return memberInjectors == null ? ImmutableList.<SingleMemberInjector>of() : memberInjectors;
   }
 
+  @Override
   public void injectMembers(T instance) {
-    Errors errors = new Errors(typeLiteral);
+    TypeLiteral<T> localTypeLiteral = typeLiteral;
     try {
-      injectAndNotify(instance, errors, null, null, typeLiteral, false);
-    } catch (ErrorsException e) {
-      errors.merge(e.getErrors());
+      injectAndNotify(instance, null, null, localTypeLiteral, false);
+    } catch (InternalProvisionException ipe) {
+      throw ipe.addSource(localTypeLiteral).toProvisionException();
     }
-
-    errors.throwProvisionExceptionIfErrorsExist();
   }
 
-  void injectAndNotify(final T instance,
-      final Errors errors,
+  void injectAndNotify(
+      final T instance,
       final Key<T> key, // possibly null!
       final ProvisionListenerStackCallback<T> provisionCallback, // possibly null!
       final Object source,
-      final boolean toolableOnly) throws ErrorsException {
+      final boolean toolableOnly)
+      throws InternalProvisionException {
     if (instance == null) {
       return;
     }
-
-    injector.callInContext(new ContextualCallable<Void>() {
-      @Override
-      public Void call(final InternalContext context) throws ErrorsException {
-        context.pushState(key, source);
-        try {
-          if (provisionCallback != null && provisionCallback.hasListeners()) {
-            provisionCallback.provision(errors, context, new ProvisionCallback<T>() {
-              @Override public T call() {
-                injectMembers(instance, errors, context, toolableOnly);
+    final InternalContext context = injector.enterContext();
+    context.pushState(key, source);
+    try {
+      if (provisionCallback != null && provisionCallback.hasListeners()) {
+        provisionCallback.provision(
+            context,
+            new ProvisionCallback<T>() {
+              @Override
+              public T call() throws InternalProvisionException {
+                injectMembers(instance, context, toolableOnly);
                 return instance;
               }
             });
-          } else {
-            injectMembers(instance, errors, context, toolableOnly);
-          }
-        } finally {
-          context.popState();
-        }
-        return null;
+      } else {
+        injectMembers(instance, context, toolableOnly);
       }
-    });
+    } finally {
+      context.popState();
+      context.close();
+    }
 
     // TODO: We *could* notify listeners too here,
     // but it's not clear if we want to.  There's no way to know
@@ -107,59 +113,80 @@
     // if atleast one InjectionPoint was toolable, in which case
     // the above callInContext could return 'true' if it injected
     // anything.)
-    if(!toolableOnly) {
-      notifyListeners(instance, errors);
+    if (!toolableOnly) {
+      notifyListeners(instance);
     }
   }
 
-  void notifyListeners(T instance, Errors errors) throws ErrorsException {
-    int numErrorsBefore = errors.size();
-    for (InjectionListener<? super T> injectionListener : injectionListeners) {
+  void notifyListeners(T instance) throws InternalProvisionException {
+    ImmutableList<InjectionListener<? super T>> localInjectionListeners = injectionListeners;
+    if (localInjectionListeners == null) {
+      // no listeners
+      return;
+    }
+    // optimization: use manual for/each to save allocating an iterator here
+    for (int i = 0; i < localInjectionListeners.size(); i++) {
+      InjectionListener<? super T> injectionListener = localInjectionListeners.get(i);
       try {
         injectionListener.afterInjection(instance);
       } catch (RuntimeException e) {
-        errors.errorNotifyingInjectionListener(injectionListener, typeLiteral, e);
+        throw InternalProvisionException.errorNotifyingInjectionListener(
+            injectionListener, typeLiteral, e);
       }
     }
-    errors.throwIfNewErrors(numErrorsBefore);
   }
 
-  void injectMembers(T t, Errors errors, InternalContext context, boolean toolableOnly) {
-    // optimization: use manual for/each to save allocating an iterator here
-    for (int i = 0, size = memberInjectors.size(); i < size; i++) {
-      SingleMemberInjector injector = memberInjectors.get(i);
-      if(!toolableOnly || injector.getInjectionPoint().isToolable()) {
-        injector.inject(errors, context, t);
+  void injectMembers(T t, InternalContext context, boolean toolableOnly)
+      throws InternalProvisionException {
+    ImmutableList<SingleMemberInjector> localMembersInjectors = memberInjectors;
+    if (localMembersInjectors != null) {
+      // optimization: use manual for/each to save allocating an iterator here
+      for (int i = 0, size = localMembersInjectors.size(); i < size; i++) {
+        SingleMemberInjector injector = localMembersInjectors.get(i);
+        if (!toolableOnly || injector.getInjectionPoint().isToolable()) {
+          injector.inject(context, t);
+        }
       }
     }
 
     // TODO: There's no way to know if a user's MembersInjector wants toolable injections.
-    if(!toolableOnly) {
-      for (MembersInjector<? super T> userMembersInjector : userMembersInjectors) {
-        try {
-          userMembersInjector.injectMembers(t);
-        } catch (RuntimeException e) {
-          errors.errorInUserInjector(userMembersInjector, typeLiteral, e);
+    if (!toolableOnly) {
+      ImmutableList<MembersInjector<? super T>> localUsersMembersInjectors = userMembersInjectors;
+      if (localUsersMembersInjectors != null) {
+        // optimization: use manual for/each to save allocating an iterator here
+        for (int i = 0; i < localUsersMembersInjectors.size(); i++) {
+          MembersInjector<? super T> userMembersInjector = localUsersMembersInjectors.get(i);
+          try {
+            userMembersInjector.injectMembers(t);
+          } catch (RuntimeException e) {
+            throw InternalProvisionException.errorInUserInjector(
+                userMembersInjector, typeLiteral, e);
+          }
         }
       }
     }
   }
 
-  @Override public String toString() {
+  @Override
+  public String toString() {
     return "MembersInjector<" + typeLiteral + ">";
   }
 
   public ImmutableSet<InjectionPoint> getInjectionPoints() {
-    ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
-    for (SingleMemberInjector memberInjector : memberInjectors) {
-      builder.add(memberInjector.getInjectionPoint());
+    ImmutableList<SingleMemberInjector> localMemberInjectors = memberInjectors;
+    if (localMemberInjectors != null) {
+      ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
+      for (SingleMemberInjector memberInjector : localMemberInjectors) {
+        builder.add(memberInjector.getInjectionPoint());
+      }
+      return builder.build();
     }
-    return builder.build();
+    return ImmutableSet.of();
   }
 
   /*if[AOP]*/
   public ImmutableList<MethodAspect> getAddedAspects() {
-    return addedAspects;
+    return addedAspects == null ? ImmutableList.<MethodAspect>of() : addedAspects;
   }
   /*end[AOP]*/
 }
diff --git a/core/src/com/google/inject/internal/MembersInjectorStore.java b/core/src/com/google/inject/internal/MembersInjectorStore.java
index 8e2acdd..6328902 100644
--- a/core/src/com/google/inject/internal/MembersInjectorStore.java
+++ b/core/src/com/google/inject/internal/MembersInjectorStore.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,7 +24,6 @@
 import com.google.inject.spi.InjectionPoint;
 import com.google.inject.spi.TypeListener;
 import com.google.inject.spi.TypeListenerBinding;
-
 import java.lang.reflect.Field;
 import java.util.List;
 import java.util.Set;
@@ -38,16 +37,16 @@
   private final InjectorImpl injector;
   private final ImmutableList<TypeListenerBinding> typeListenerBindings;
 
-  private final FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>> cache
-      = new FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>>() {
-    @Override protected MembersInjectorImpl<?> create(TypeLiteral<?> type, Errors errors)
-        throws ErrorsException {
-      return createWithListeners(type, errors);
-    }
-  };
+  private final FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>> cache =
+      new FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>>() {
+        @Override
+        protected MembersInjectorImpl<?> create(TypeLiteral<?> type, Errors errors)
+            throws ErrorsException {
+          return createWithListeners(type, errors);
+        }
+      };
 
-  MembersInjectorStore(InjectorImpl injector,
-      List<TypeListenerBinding> typeListenerBindings) {
+  MembersInjectorStore(InjectorImpl injector, List<TypeListenerBinding> typeListenerBindings) {
     this.injector = injector;
     this.typeListenerBindings = ImmutableList.copyOf(typeListenerBindings);
   }
@@ -60,9 +59,7 @@
     return !typeListenerBindings.isEmpty();
   }
 
-  /**
-   * Returns a new complete members injector with injection listeners registered.
-   */
+  /** Returns a new complete members injector with injection listeners registered. */
   @SuppressWarnings("unchecked") // the MembersInjector type always agrees with the passed type
   public <T> MembersInjectorImpl<T> get(TypeLiteral<T> key, Errors errors) throws ErrorsException {
     return (MembersInjectorImpl<T>) cache.get(key, errors);
@@ -74,16 +71,14 @@
    * ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and
    * #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is
    * necessary.)
-   * 
-   * Returns true if the type was stored in the cache, false otherwise.
+   *
+   * <p>Returns true if the type was stored in the cache, false otherwise.
    */
   boolean remove(TypeLiteral<?> type) {
     return cache.remove(type);
   }
 
-  /**
-   * Creates a new members injector and attaches both injection listeners and method aspects.
-   */
+  /** Creates a new members injector and attaches both injection listeners and method aspects. */
   private <T> MembersInjectorImpl<T> createWithListeners(TypeLiteral<T> type, Errors errors)
       throws ErrorsException {
     int numErrorsBefore = errors.size();
@@ -98,7 +93,7 @@
     ImmutableList<SingleMemberInjector> injectors = getInjectors(injectionPoints, errors);
     errors.throwIfNewErrors(numErrorsBefore);
 
-    EncounterImpl<T> encounter = new EncounterImpl<T>(errors, injector.lookups);
+    EncounterImpl<T> encounter = new EncounterImpl<>(errors, injector.lookups);
     Set<TypeListener> alreadySeenListeners = Sets.newHashSet();
     for (TypeListenerBinding binding : typeListenerBindings) {
       TypeListener typeListener = binding.getListener();
@@ -117,20 +112,20 @@
     return new MembersInjectorImpl<T>(injector, type, encounter, injectors);
   }
 
-  /**
-   * Returns the injectors for the specified injection points.
-   */
+  /** Returns the injectors for the specified injection points. */
   ImmutableList<SingleMemberInjector> getInjectors(
       Set<InjectionPoint> injectionPoints, Errors errors) {
     List<SingleMemberInjector> injectors = Lists.newArrayList();
     for (InjectionPoint injectionPoint : injectionPoints) {
       try {
-        Errors errorsForMember = injectionPoint.isOptional()
-            ? new Errors(injectionPoint)
-            : errors.withSource(injectionPoint);
-        SingleMemberInjector injector = injectionPoint.getMember() instanceof Field
-            ? new SingleFieldInjector(this.injector, injectionPoint, errorsForMember)
-            : new SingleMethodInjector(this.injector, injectionPoint, errorsForMember);
+        Errors errorsForMember =
+            injectionPoint.isOptional()
+                ? new Errors(injectionPoint)
+                : errors.withSource(injectionPoint);
+        SingleMemberInjector injector =
+            injectionPoint.getMember() instanceof Field
+                ? new SingleFieldInjector(this.injector, injectionPoint, errorsForMember)
+                : new SingleMethodInjector(this.injector, injectionPoint, errorsForMember);
         injectors.add(injector);
       } catch (ErrorsException ignoredForNow) {
         // ignored for now
diff --git a/core/src/com/google/inject/internal/MessageProcessor.java b/core/src/com/google/inject/internal/MessageProcessor.java
index d7c607b..cb9be02 100644
--- a/core/src/com/google/inject/internal/MessageProcessor.java
+++ b/core/src/com/google/inject/internal/MessageProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,6 @@
 
 import com.google.inject.Guice;
 import com.google.inject.spi.Message;
-
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -36,10 +35,12 @@
     super(errors);
   }
 
-  @Override public Boolean visit(Message message) {
+  @Override
+  public Boolean visit(Message message) {
     if (message.getCause() != null) {
       String rootMessage = getRootMessage(message.getCause());
-      logger.log(Level.INFO,
+      logger.log(
+          Level.INFO,
           "An exception was caught and reported. Message: " + rootMessage,
           message.getCause());
     }
diff --git a/core/src/com/google/inject/internal/Messages.java b/core/src/com/google/inject/internal/Messages.java
new file mode 100644
index 0000000..2c80ab2
--- /dev/null
+++ b/core/src/com/google/inject/internal/Messages.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2017 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.inject.internal;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.base.Equivalence;
+import com.google.common.base.Objects;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import com.google.inject.internal.util.Classes;
+import com.google.inject.internal.util.StackTraceElements;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.ElementSource;
+import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.Message;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Map;
+
+/** Utility methods for {@link Message} objects */
+public final class Messages {
+  private Messages() {}
+
+  /** Prepends the list of sources to the given {@link Message} */
+  static Message mergeSources(List<Object> sources, Message message) {
+    List<Object> messageSources = message.getSources();
+    // It is possible that the end of getSources() and the beginning of message.getSources() are
+    // equivalent, in this case we should drop the repeated source when joining the lists.  The
+    // most likely scenario where this would happen is when a scoped binding throws an exception,
+    // due to the fact that InternalFactoryToProviderAdapter applies the binding source when
+    // merging errors.
+    if (!sources.isEmpty()
+        && !messageSources.isEmpty()
+        && Objects.equal(messageSources.get(0), sources.get(sources.size() - 1))) {
+      messageSources = messageSources.subList(1, messageSources.size());
+    }
+    return new Message(
+        ImmutableList.builder().addAll(sources).addAll(messageSources).build(),
+        message.getMessage(),
+        message.getCause());
+  }
+
+  /**
+   * Calls {@link String#format} after converting the arguments using some standard guice formatting
+   * for {@link Key}, {@link Class} and {@link Member} objects.
+   */
+  public static String format(String messageFormat, Object... arguments) {
+    for (int i = 0; i < arguments.length; i++) {
+      arguments[i] = convert(arguments[i]);
+    }
+    return String.format(messageFormat, arguments);
+  }
+
+  /** Returns the formatted message for an exception with the specified messages. */
+  public static String formatMessages(String heading, Collection<Message> errorMessages) {
+    Formatter fmt = new Formatter().format(heading).format(":%n%n");
+    int index = 1;
+    boolean displayCauses = getOnlyCause(errorMessages) == null;
+
+    Map<Equivalence.Wrapper<Throwable>, Integer> causes = Maps.newHashMap();
+    for (Message errorMessage : errorMessages) {
+      int thisIdx = index++;
+      fmt.format("%s) %s%n", thisIdx, errorMessage.getMessage());
+
+      List<Object> dependencies = errorMessage.getSources();
+      for (int i = dependencies.size() - 1; i >= 0; i--) {
+        Object source = dependencies.get(i);
+        formatSource(fmt, source);
+      }
+
+      Throwable cause = errorMessage.getCause();
+      if (displayCauses && cause != null) {
+        Equivalence.Wrapper<Throwable> causeEquivalence = ThrowableEquivalence.INSTANCE.wrap(cause);
+        if (!causes.containsKey(causeEquivalence)) {
+          causes.put(causeEquivalence, thisIdx);
+          fmt.format("Caused by: %s", Throwables.getStackTraceAsString(cause));
+        } else {
+          int causeIdx = causes.get(causeEquivalence);
+          fmt.format(
+              "Caused by: %s (same stack trace as error #%s)",
+              cause.getClass().getName(), causeIdx);
+        }
+      }
+
+      fmt.format("%n");
+    }
+
+    if (errorMessages.size() == 1) {
+      fmt.format("1 error");
+    } else {
+      fmt.format("%s errors", errorMessages.size());
+    }
+
+    return fmt.toString();
+  }
+
+  /**
+   * Creates a new Message without a cause.
+   *
+   * @param messageFormat Format string
+   * @param arguments format string arguments
+   */
+  public static Message create(String messageFormat, Object... arguments) {
+    return create(null, messageFormat, arguments);
+  }
+
+  /**
+   * Creates a new Message with the given cause.
+   *
+   * @param cause The exception that caused the error
+   * @param messageFormat Format string
+   * @param arguments format string arguments
+   */
+  public static Message create(Throwable cause, String messageFormat, Object... arguments) {
+    return create(cause, ImmutableList.of(), messageFormat, arguments);
+  }
+
+  /**
+   * Creates a new Message with the given cause and a binding source stack.
+   *
+   * @param cause The exception that caused the error
+   * @param sources The binding sources for the source stack
+   * @param messageFormat Format string
+   * @param arguments format string arguments
+   */
+  public static Message create(
+      Throwable cause, List<Object> sources, String messageFormat, Object... arguments) {
+    String message = format(messageFormat, arguments);
+    return new Message(sources, message, cause);
+  }
+
+  /** Formats an object in a user friendly way. */
+  static Object convert(Object o) {
+    ElementSource source = null;
+    if (o instanceof ElementSource) {
+      source = (ElementSource) o;
+      o = source.getDeclaringSource();
+    }
+    return convert(o, source);
+  }
+
+  static Object convert(Object o, ElementSource source) {
+    for (Converter<?> converter : converters) {
+      if (converter.appliesTo(o)) {
+        return appendModules(converter.convert(o), source);
+      }
+    }
+    return appendModules(o, source);
+  }
+
+  private static Object appendModules(Object source, ElementSource elementSource) {
+    String modules = moduleSourceString(elementSource);
+    if (modules.length() == 0) {
+      return source;
+    } else {
+      return source + modules;
+    }
+  }
+
+  private static String moduleSourceString(ElementSource elementSource) {
+    // if we only have one module (or don't know what they are), then don't bother
+    // reporting it, because the source already is going to report exactly that module.
+    if (elementSource == null) {
+      return "";
+    }
+    List<String> modules = Lists.newArrayList(elementSource.getModuleClassNames());
+    // Insert any original element sources w/ module info into the path.
+    while (elementSource.getOriginalElementSource() != null) {
+      elementSource = elementSource.getOriginalElementSource();
+      modules.addAll(0, elementSource.getModuleClassNames());
+    }
+    if (modules.size() <= 1) {
+      return "";
+    }
+
+    // Ideally we'd do:
+    //    return Joiner.on(" -> ")
+    //        .appendTo(new StringBuilder(" (via modules: "), Lists.reverse(modules))
+    //        .append(")").toString();
+    // ... but for some reason we can't find Lists.reverse, so do it the boring way.
+    StringBuilder builder = new StringBuilder(" (via modules: ");
+    for (int i = modules.size() - 1; i >= 0; i--) {
+      builder.append(modules.get(i));
+      if (i != 0) {
+        builder.append(" -> ");
+      }
+    }
+    builder.append(")");
+    return builder.toString();
+  }
+
+  static void formatSource(Formatter formatter, Object source) {
+    ElementSource elementSource = null;
+    if (source instanceof ElementSource) {
+      elementSource = (ElementSource) source;
+      source = elementSource.getDeclaringSource();
+    }
+    formatSource(formatter, source, elementSource);
+  }
+
+  static void formatSource(Formatter formatter, Object source, ElementSource elementSource) {
+    String modules = moduleSourceString(elementSource);
+    if (source instanceof Dependency) {
+      Dependency<?> dependency = (Dependency<?>) source;
+      InjectionPoint injectionPoint = dependency.getInjectionPoint();
+      if (injectionPoint != null) {
+        formatInjectionPoint(formatter, dependency, injectionPoint, elementSource);
+      } else {
+        formatSource(formatter, dependency.getKey(), elementSource);
+      }
+
+    } else if (source instanceof InjectionPoint) {
+      formatInjectionPoint(formatter, null, (InjectionPoint) source, elementSource);
+
+    } else if (source instanceof Class) {
+      formatter.format("  at %s%s%n", StackTraceElements.forType((Class<?>) source), modules);
+
+    } else if (source instanceof Member) {
+      formatter.format("  at %s%s%n", StackTraceElements.forMember((Member) source), modules);
+
+    } else if (source instanceof TypeLiteral) {
+      formatter.format("  while locating %s%s%n", source, modules);
+
+    } else if (source instanceof Key) {
+      Key<?> key = (Key<?>) source;
+      formatter.format("  while locating %s%n", convert(key, elementSource));
+
+    } else if (source instanceof Thread) {
+      formatter.format("  in thread %s%n", source);
+
+    } else {
+      formatter.format("  at %s%s%n", source, modules);
+    }
+  }
+
+  private static void formatInjectionPoint(
+      Formatter formatter,
+      Dependency<?> dependency,
+      InjectionPoint injectionPoint,
+      ElementSource elementSource) {
+    Member member = injectionPoint.getMember();
+    Class<? extends Member> memberType = Classes.memberType(member);
+
+    if (memberType == Field.class) {
+      dependency = injectionPoint.getDependencies().get(0);
+      formatter.format("  while locating %s%n", convert(dependency.getKey(), elementSource));
+      formatter.format("    for field at %s%n", StackTraceElements.forMember(member));
+
+    } else if (dependency != null) {
+      formatter.format("  while locating %s%n", convert(dependency.getKey(), elementSource));
+      formatter.format("    for %s%n", formatParameter(dependency));
+
+    } else {
+      formatSource(formatter, injectionPoint.getMember());
+    }
+  }
+
+  static String formatParameter(Dependency<?> dependency) {
+    int ordinal = dependency.getParameterIndex() + 1;
+    return String.format(
+        "the %s%s parameter of %s",
+        ordinal,
+        getOrdinalSuffix(ordinal),
+        StackTraceElements.forMember(dependency.getInjectionPoint().getMember()));
+  }
+
+  /**
+   * Maps {@code 1} to the string {@code "1st"} ditto for all non-negative numbers
+   *
+   * @see <a href="https://en.wikipedia.org/wiki/English_numerals#Ordinal_numbers">
+   *     https://en.wikipedia.org/wiki/English_numerals#Ordinal_numbers</a>
+   */
+  private static String getOrdinalSuffix(int ordinal) {
+    // negative ordinals don't make sense, we allow zero though because we are programmers
+    checkArgument(ordinal >= 0);
+    if ((ordinal / 10) % 10 == 1) {
+      // all the 'teens' are weird
+      return "th";
+    } else {
+      // could use a lookup table? any better?
+      switch (ordinal % 10) {
+        case 1:
+          return "st";
+        case 2:
+          return "nd";
+        case 3:
+          return "rd";
+        default:
+          return "th";
+      }
+    }
+  }
+
+  private abstract static class Converter<T> {
+
+    final Class<T> type;
+
+    Converter(Class<T> type) {
+      this.type = type;
+    }
+
+    boolean appliesTo(Object o) {
+      return o != null && type.isAssignableFrom(o.getClass());
+    }
+
+    String convert(Object o) {
+      return toString(type.cast(o));
+    }
+
+    abstract String toString(T t);
+  }
+
+  @SuppressWarnings({"unchecked", "rawtypes"}) // rawtypes aren't avoidable
+  private static final Collection<Converter<?>> converters =
+      ImmutableList.of(
+          new Converter<Class>(Class.class) {
+            @Override
+            public String toString(Class c) {
+              return c.getName();
+            }
+          },
+          new Converter<Member>(Member.class) {
+            @Override
+            public String toString(Member member) {
+              return Classes.toString(member);
+            }
+          },
+          new Converter<Key>(Key.class) {
+            @Override
+            public String toString(Key key) {
+              if (key.getAnnotationType() != null) {
+                return key.getTypeLiteral()
+                    + " annotated with "
+                    + (key.getAnnotation() != null ? key.getAnnotation() : key.getAnnotationType());
+              } else {
+                return key.getTypeLiteral().toString();
+              }
+            }
+          });
+
+  /**
+   * Returns the cause throwable if there is exactly one cause in {@code messages}. If there are
+   * zero or multiple messages with causes, null is returned.
+   */
+  public static Throwable getOnlyCause(Collection<Message> messages) {
+    Throwable onlyCause = null;
+    for (Message message : messages) {
+      Throwable messageCause = message.getCause();
+      if (messageCause == null) {
+        continue;
+      }
+
+      if (onlyCause != null && !ThrowableEquivalence.INSTANCE.equivalent(onlyCause, messageCause)) {
+        return null;
+      }
+
+      onlyCause = messageCause;
+    }
+
+    return onlyCause;
+  }
+
+  private static final class ThrowableEquivalence extends Equivalence<Throwable> {
+    static final ThrowableEquivalence INSTANCE = new ThrowableEquivalence();
+
+    @Override
+    protected boolean doEquivalent(Throwable a, Throwable b) {
+      return a.getClass().equals(b.getClass())
+          && Objects.equal(a.getMessage(), b.getMessage())
+          && Arrays.equals(a.getStackTrace(), b.getStackTrace())
+          && equivalent(a.getCause(), b.getCause());
+    }
+
+    @Override
+    protected int doHash(Throwable t) {
+      return Objects.hashCode(t.getClass().hashCode(), t.getMessage(), hash(t.getCause()));
+    }
+  }
+}
diff --git a/core/src/com/google/inject/internal/MethodAspect.java b/core/src/com/google/inject/internal/MethodAspect.java
index 7bdf193..d04175f 100644
--- a/core/src/com/google/inject/internal/MethodAspect.java
+++ b/core/src/com/google/inject/internal/MethodAspect.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2006 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,10 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import com.google.inject.matcher.Matcher;
-
-import org.aopalliance.intercept.MethodInterceptor;
-
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.List;
+import org.aopalliance.intercept.MethodInterceptor;
 
 /**
  * Ties a matcher to a method interceptor.
@@ -44,15 +42,19 @@
    *     annotatedWith(Transactional.class)}.
    * @param interceptors to apply
    */
-  MethodAspect(Matcher<? super Class<?>> classMatcher,
-      Matcher<? super Method> methodMatcher, List<MethodInterceptor> interceptors) {
+  MethodAspect(
+      Matcher<? super Class<?>> classMatcher,
+      Matcher<? super Method> methodMatcher,
+      List<MethodInterceptor> interceptors) {
     this.classMatcher = checkNotNull(classMatcher, "class matcher");
     this.methodMatcher = checkNotNull(methodMatcher, "method matcher");
     this.interceptors = checkNotNull(interceptors, "interceptors");
   }
 
-  MethodAspect(Matcher<? super Class<?>> classMatcher,
-      Matcher<? super Method> methodMatcher, MethodInterceptor... interceptors) {
+  MethodAspect(
+      Matcher<? super Class<?>> classMatcher,
+      Matcher<? super Method> methodMatcher,
+      MethodInterceptor... interceptors) {
     this(classMatcher, methodMatcher, Arrays.asList(interceptors));
   }
 
diff --git a/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java b/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java
index 85c721d..74c64b0 100644
--- a/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java
+++ b/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2015 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,7 +29,8 @@
     super(errors);
   }
 
-  @Override public Boolean visit(ModuleAnnotatedMethodScannerBinding command) {
+  @Override
+  public Boolean visit(ModuleAnnotatedMethodScannerBinding command) {
     injector.state.addScanner(command);
     return true;
   }
diff --git a/core/src/com/google/inject/internal/MoreTypes.java b/core/src/com/google/inject/internal/MoreTypes.java
index bdf6029..11e6ab3 100644
--- a/core/src/com/google/inject/internal/MoreTypes.java
+++ b/core/src/com/google/inject/internal/MoreTypes.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package com.google.inject.internal;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -26,7 +25,6 @@
 import com.google.inject.Key;
 import com.google.inject.TypeLiteral;
 import com.google.inject.util.Types;
-
 import java.io.Serializable;
 import java.lang.reflect.Array;
 import java.lang.reflect.GenericArrayType;
@@ -36,12 +34,10 @@
 import java.lang.reflect.TypeVariable;
 import java.lang.reflect.WildcardType;
 import java.util.Arrays;
-import java.util.Map;
 import java.util.NoSuchElementException;
 
 /**
- * Static methods for working with types that we aren't publishing in the
- * public {@code Types} API.
+ * Static methods for working with types that we aren't publishing in the public {@code Types} API.
  *
  * @author jessewilson@google.com (Jesse Wilson)
  */
@@ -51,8 +47,8 @@
 
   private MoreTypes() {}
 
-  private static final Map<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER
-      = new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>()
+  private static final ImmutableMap<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER =
+      new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>()
           .put(TypeLiteral.get(boolean.class), TypeLiteral.get(Boolean.class))
           .put(TypeLiteral.get(byte.class), TypeLiteral.get(Byte.class))
           .put(TypeLiteral.get(short.class), TypeLiteral.get(Short.class))
@@ -65,13 +61,12 @@
           .build();
 
   /**
-   * Returns a key that doesn't hold any references to parent classes.
-   * This is necessary for anonymous keys, so ensure we don't hold a ref
-   * to the containing module (or class) forever.
+   * Returns a key that doesn't hold any references to parent classes. This is necessary for
+   * anonymous keys, so ensure we don't hold a ref to the containing module (or class) forever.
    */
   public static <T> Key<T> canonicalizeKey(Key<T> key) {
     // If we know this isn't a subclass, return as-is.
-    // Otherwise, recreate the key to avoid the subclass 
+    // Otherwise, recreate the key to avoid the subclass
     if (key.getClass() == Key.class) {
       return key;
     } else if (key.getAnnotation() != null) {
@@ -106,8 +101,9 @@
       // the following casts are generally unsafe, but com.google.inject.Provider extends
       // javax.inject.Provider and is covariant
       @SuppressWarnings("unchecked")
-      TypeLiteral<T> guiceProviderType = (TypeLiteral<T>) TypeLiteral.get(
-          Types.providerOf(parameterizedType.getActualTypeArguments()[0]));
+      TypeLiteral<T> guiceProviderType =
+          (TypeLiteral<T>)
+              TypeLiteral.get(Types.providerOf(parameterizedType.getActualTypeArguments()[0]));
       return guiceProviderType;
     }
 
@@ -129,9 +125,7 @@
     return recreated;
   }
 
-  /**
-   * Returns true if {@code type} is free from type variables.
-   */
+  /** Returns true if {@code type} is free from type variables. */
   private static boolean isFullySpecified(Type type) {
     if (type instanceof Class) {
       return true;
@@ -139,7 +133,7 @@
     } else if (type instanceof CompositeType) {
       return ((CompositeType) type).isFullySpecified();
 
-    } else if (type instanceof TypeVariable){
+    } else if (type instanceof TypeVariable) {
       return false;
 
     } else {
@@ -148,9 +142,8 @@
   }
 
   /**
-   * Returns a type that is functionally equal but not necessarily equal
-   * according to {@link Object#equals(Object) Object.equals()}. The returned
-   * type is {@link Serializable}.
+   * Returns a type that is functionally equal but not necessarily equal according to {@link
+   * Object#equals(Object) Object.equals()}. The returned type is {@link Serializable}.
    */
   public static Type canonicalize(Type type) {
     if (type instanceof Class) {
@@ -162,8 +155,8 @@
 
     } else if (type instanceof ParameterizedType) {
       ParameterizedType p = (ParameterizedType) type;
-      return new ParameterizedTypeImpl(p.getOwnerType(),
-          p.getRawType(), p.getActualTypeArguments());
+      return new ParameterizedTypeImpl(
+          p.getOwnerType(), p.getRawType(), p.getActualTypeArguments());
 
     } else if (type instanceof GenericArrayType) {
       GenericArrayType g = (GenericArrayType) type;
@@ -191,28 +184,33 @@
       // Neal isn't either but suspects some pathological case related
       // to nested classes exists.
       Type rawType = parameterizedType.getRawType();
-      checkArgument(rawType instanceof Class,
-          "Expected a Class, but <%s> is of type %s", type, type.getClass().getName());
+      checkArgument(
+          rawType instanceof Class,
+          "Expected a Class, but <%s> is of type %s",
+          type,
+          type.getClass().getName());
       return (Class<?>) rawType;
 
     } else if (type instanceof GenericArrayType) {
-      Type componentType = ((GenericArrayType)type).getGenericComponentType();
+      Type componentType = ((GenericArrayType) type).getGenericComponentType();
       return Array.newInstance(getRawType(componentType), 0).getClass();
 
-    } else if (type instanceof TypeVariable) {
+    } else if (type instanceof TypeVariable || type instanceof WildcardType) {
       // we could use the variable's bounds, but that'll won't work if there are multiple.
-      // having a raw type that's more general than necessary is okay  
+      // having a raw type that's more general than necessary is okay
       return Object.class;
 
     } else {
-      throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
-          + "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName());
+      throw new IllegalArgumentException(
+          "Expected a Class, ParameterizedType, or "
+              + "GenericArrayType, but <"
+              + type
+              + "> is of type "
+              + type.getClass().getName());
     }
   }
 
-  /**
-   * Returns true if {@code a} and {@code b} are equal.
-   */
+  /** Returns true if {@code a} and {@code b} are equal. */
   public static boolean equals(Type a, Type b) {
     if (a == b) {
       // also handles (a == null && b == null)
@@ -278,8 +276,8 @@
 
   /**
    * Returns the generic supertype for {@code type}. For example, given a class {@code IntegerSet},
-   * the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the result
-   * when the supertype is {@code Collection.class} is {@code Collection<Integer>}.
+   * the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the result when
+   * the supertype is {@code Collection.class} is {@code Collection<Integer>}.
    */
   public static Type getGenericSupertype(Type type, Class<?> rawType, Class<?> toResolve) {
     if (toResolve == rawType) {
@@ -347,9 +345,7 @@
    */
   private static Class<?> declaringClassOf(TypeVariable typeVariable) {
     GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
-    return genericDeclaration instanceof Class
-        ? (Class<?>) genericDeclaration
-        : null;
+    return genericDeclaration instanceof Class ? (Class<?>) genericDeclaration : null;
   }
 
   public static class ParameterizedTypeImpl
@@ -372,18 +368,22 @@
       }
     }
 
+    @Override
     public Type[] getActualTypeArguments() {
       return typeArguments.clone();
     }
 
+    @Override
     public Type getRawType() {
       return rawType;
     }
 
+    @Override
     public Type getOwnerType() {
       return ownerType;
     }
 
+    @Override
     public boolean isFullySpecified() {
       if (ownerType != null && !MoreTypes.isFullySpecified(ownerType)) {
         return false;
@@ -402,18 +402,19 @@
       return true;
     }
 
-    @Override public boolean equals(Object other) {
+    @Override
+    public boolean equals(Object other) {
       return other instanceof ParameterizedType
           && MoreTypes.equals(this, (ParameterizedType) other);
     }
 
-    @Override public int hashCode() {
-      return Arrays.hashCode(typeArguments)
-          ^ rawType.hashCode()
-          ^ hashCodeOrZero(ownerType);
+    @Override
+    public int hashCode() {
+      return Arrays.hashCode(typeArguments) ^ rawType.hashCode() ^ hashCodeOrZero(ownerType);
     }
 
-    @Override public String toString() {
+    @Override
+    public String toString() {
       StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1));
       stringBuilder.append(typeToString(rawType));
 
@@ -431,10 +432,14 @@
     private static void ensureOwnerType(Type ownerType, Type rawType) {
       if (rawType instanceof Class<?>) {
         Class rawTypeAsClass = (Class) rawType;
-        checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null,
-            "No owner type for enclosed %s", rawType);
-        checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null,
-            "Owner type for unenclosed %s", rawType);
+        checkArgument(
+            ownerType != null || rawTypeAsClass.getEnclosingClass() == null,
+            "No owner type for enclosed %s",
+            rawType);
+        checkArgument(
+            ownerType == null || rawTypeAsClass.getEnclosingClass() != null,
+            "Owner type for unenclosed %s",
+            rawType);
       }
     }
 
@@ -449,24 +454,28 @@
       this.componentType = canonicalize(componentType);
     }
 
+    @Override
     public Type getGenericComponentType() {
       return componentType;
     }
 
+    @Override
     public boolean isFullySpecified() {
       return MoreTypes.isFullySpecified(componentType);
     }
 
-    @Override public boolean equals(Object o) {
-      return o instanceof GenericArrayType
-          && MoreTypes.equals(this, (GenericArrayType) o);
+    @Override
+    public boolean equals(Object o) {
+      return o instanceof GenericArrayType && MoreTypes.equals(this, (GenericArrayType) o);
     }
 
-    @Override public int hashCode() {
+    @Override
+    public int hashCode() {
       return componentType.hashCode();
     }
 
-    @Override public String toString() {
+    @Override
+    public String toString() {
       return typeToString(componentType) + "[]";
     }
 
@@ -474,9 +483,9 @@
   }
 
   /**
-   * The WildcardType interface supports multiple upper bounds and multiple
-   * lower bounds. We only support what the Java 6 language needs - at most one
-   * bound. If a lower bound is set, the upper bound must be Object.class.
+   * The WildcardType interface supports multiple upper bounds and multiple lower bounds. We only
+   * support what the Java 6 language needs - at most one bound. If a lower bound is set, the upper
+   * bound must be Object.class.
    */
   public static class WildcardTypeImpl implements WildcardType, Serializable, CompositeType {
     private final Type upperBound;
@@ -501,31 +510,35 @@
       }
     }
 
+    @Override
     public Type[] getUpperBounds() {
-      return new Type[] { upperBound };
+      return new Type[] {upperBound};
     }
 
+    @Override
     public Type[] getLowerBounds() {
-      return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;
+      return lowerBound != null ? new Type[] {lowerBound} : EMPTY_TYPE_ARRAY;
     }
 
+    @Override
     public boolean isFullySpecified() {
       return MoreTypes.isFullySpecified(upperBound)
           && (lowerBound == null || MoreTypes.isFullySpecified(lowerBound));
     }
 
-    @Override public boolean equals(Object other) {
-      return other instanceof WildcardType
-          && MoreTypes.equals(this, (WildcardType) other);
+    @Override
+    public boolean equals(Object other) {
+      return other instanceof WildcardType && MoreTypes.equals(this, (WildcardType) other);
     }
 
-    @Override public int hashCode() {
-      // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());  
-      return (lowerBound != null ? 31 + lowerBound.hashCode() : 1)
-          ^ (31 + upperBound.hashCode());
+    @Override
+    public int hashCode() {
+      // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
+      return (lowerBound != null ? 31 + lowerBound.hashCode() : 1) ^ (31 + upperBound.hashCode());
     }
 
-    @Override public String toString() {
+    @Override
+    public String toString() {
       if (lowerBound != null) {
         return "? super " + typeToString(lowerBound);
       } else if (upperBound == Object.class) {
@@ -539,8 +552,11 @@
   }
 
   private static void checkNotPrimitive(Type type, String use) {
-    checkArgument(!(type instanceof Class<?>) || !((Class) type).isPrimitive(),
-        "Primitive types are not allowed in %s: %s", use, type);
+    checkArgument(
+        !(type instanceof Class<?>) || !((Class) type).isPrimitive(),
+        "Primitive types are not allowed in %s: %s",
+        use,
+        type);
   }
 
   /** A type formed from other types, such as arrays, parameterized types or wildcard types */
diff --git a/core/src/com/google/inject/internal/Nullability.java b/core/src/com/google/inject/internal/Nullability.java
index 76f7e76..c8da51d 100644
--- a/core/src/com/google/inject/internal/Nullability.java
+++ b/core/src/com/google/inject/internal/Nullability.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,14 +21,13 @@
 /**
  * Whether a member supports null values injected.
  *
- * <p>Support for {@code Nullable} annotations in Guice is loose.
- * Any annotation type whose simplename is "Nullable" is sufficient to indicate
- * support for null values injected.
+ * <p>Support for {@code Nullable} annotations in Guice is loose. Any annotation type whose
+ * simplename is "Nullable" is sufficient to indicate support for null values injected.
  *
- * <p>This allows support for JSR-305's
- * <a href="http://groups.google.com/group/jsr-305/web/proposed-annotations">
- * javax.annotation.meta.Nullable</a> annotation and IntelliJ IDEA's
- * <a href="http://www.jetbrains.com/idea/documentation/howto.html">
+ * <p>This allows support for JSR-305's <a
+ * href="http://groups.google.com/group/jsr-305/web/proposed-annotations">
+ * javax.annotation.meta.Nullable</a> annotation and IntelliJ IDEA's <a
+ * href="http://www.jetbrains.com/idea/documentation/howto.html">
  * org.jetbrains.annotations.Nullable</a>.
  *
  * @author jessewilson@google.com (Jesse Wilson)
@@ -37,7 +36,7 @@
   private Nullability() {}
 
   public static boolean allowsNull(Annotation[] annotations) {
-    for(Annotation a : annotations) {
+    for (Annotation a : annotations) {
       Class<? extends Annotation> type = a.annotationType();
       if ("Nullable".equals(type.getSimpleName())) {
         return true;
diff --git a/core/src/com/google/inject/internal/PrivateElementProcessor.java b/core/src/com/google/inject/internal/PrivateElementProcessor.java
index 4a641a9..7d45a7d 100644
--- a/core/src/com/google/inject/internal/PrivateElementProcessor.java
+++ b/core/src/com/google/inject/internal/PrivateElementProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2008 Google Inc.
  *