Enabled validation of static dependencies.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@46 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/guice.iws b/guice.iws
index 9d14620..6d916cc 100644
--- a/guice.iws
+++ b/guice.iws
@@ -24,6 +24,7 @@
       <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/google/inject/Stopwatch.java" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/com/google/inject/ErrorHandlingTest.java" afterPath="$PROJECT_DIR$/test/com/google/inject/ErrorHandlingTest.java" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/com/google/inject/GenericInjectionTest.java" afterPath="$PROJECT_DIR$/test/com/google/inject/GenericInjectionTest.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java" afterPath="$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/ContainerCreationException.java" afterPath="$PROJECT_DIR$/src/com/google/inject/ContainerCreationException.java" />
       <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/google/inject/FactoryToInternalFactoryAdapter.java" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/com/google/inject/ConstantConversionTest.java" afterPath="$PROJECT_DIR$/test/com/google/inject/ConstantConversionTest.java" />
@@ -206,10 +207,64 @@
   </component>
   <component name="FileEditorManager">
     <leaf>
-      <file leaf-file-name="ContainerBuilder.java" pinned="false" current="true" current-in-tab="true">
+      <file leaf-file-name="ContainerBuilder.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/ContainerBuilder.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="95" column="77" selection-start="3261" selection-end="3261" vertical-scroll-proportion="0.24697986">
+            <state line="884" column="34" selection-start="24992" selection-end="24992" vertical-scroll-proportion="2.7259843">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="ErrorHandlingTest.java" pinned="false" current="true" current-in-tab="true">
+        <entry file="file://$PROJECT_DIR$/test/com/google/inject/ErrorHandlingTest.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="11" column="18" selection-start="205" selection-end="205" vertical-scroll-proportion="0.2944882">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="ContainerImpl.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="248" column="0" selection-start="7834" selection-end="7834" vertical-scroll-proportion="0.38110235">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="ErrorHandler.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/com/google/inject/ErrorHandler.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="8" column="3" selection-start="167" selection-end="167" vertical-scroll-proportion="0.21417323">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="AllTests.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/test/com/google/inject/AllTests.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="45" column="22" selection-start="1548" selection-end="1548" vertical-scroll-proportion="0.6692913">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="Key.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/com/google/inject/Key.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="153" column="22" selection-start="3934" selection-end="3934" vertical-scroll-proportion="0.41732284">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="TypeLiteral.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/com/google/inject/TypeLiteral.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="150" column="18" selection-start="4385" selection-end="4385" vertical-scroll-proportion="1.0598425">
               <folding />
             </state>
           </provider>
@@ -218,7 +273,7 @@
       <file leaf-file-name="InternalToContextualFactoryAdapter.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/InternalToContextualFactoryAdapter.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="21" column="18" selection-start="512" selection-end="512" vertical-scroll-proportion="0.47919464">
+            <state line="21" column="18" selection-start="512" selection-end="512" vertical-scroll-proportion="0.5622047">
               <folding />
             </state>
           </provider>
@@ -227,7 +282,7 @@
       <file leaf-file-name="InternalFactoryToFactoryAdapter.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/InternalFactoryToFactoryAdapter.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="15" column="34" selection-start="391" selection-end="391" vertical-scroll-proportion="0.34228188">
+            <state line="15" column="34" selection-start="391" selection-end="391" vertical-scroll-proportion="0.4015748">
               <folding />
             </state>
           </provider>
@@ -236,7 +291,7 @@
       <file leaf-file-name="FactoryToInternalFactoryAdapter.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/FactoryToInternalFactoryAdapter.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="14" column="32" selection-start="397" selection-end="397" vertical-scroll-proportion="0.31946307">
+            <state line="14" column="32" selection-start="397" selection-end="397" vertical-scroll-proportion="0.37480316">
               <folding />
             </state>
           </provider>
@@ -545,6 +600,28 @@
         <option name="Make" value="true" />
       </method>
     </configuration>
+    <configuration default="false" name="AllTests" type="JUnit" factoryName="JUnit" enabled="false" merge="false">
+      <pattern value="com.google.inject.*" />
+      <module name="guice" />
+      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+      <option name="ALTERNATIVE_JRE_PATH" />
+      <option name="PACKAGE_NAME" value="com.google.inject" />
+      <option name="MAIN_CLASS_NAME" value="com.google.inject.AllTests" />
+      <option name="METHOD_NAME" />
+      <option name="TEST_OBJECT" value="class" />
+      <option name="VM_PARAMETERS" />
+      <option name="PARAMETERS" />
+      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
+      <option name="ADDITIONAL_CLASS_PATH" />
+      <option name="TEST_SEARCH_SCOPE">
+        <value defaultName="wholeProject" />
+      </option>
+      <RunnerSettings RunnerId="Run" />
+      <ConfigurationWrapper RunnerId="Run" />
+      <method>
+        <option name="Make" value="true" />
+      </method>
+    </configuration>
   </component>
   <component name="ScopeViewComponent">
     <subPane subId="Project">
@@ -636,7 +713,7 @@
       <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.15854311" order="0" />
       <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.29517502" order="1" />
       <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.16236559" order="1" />
-      <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.27909178" order="10" />
+      <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.27909178" order="10" />
       <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" order="6" />
       <window_info id="Profile" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32890996" order="13" />
       <window_info id="Module Dependencies" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="3" />
@@ -644,7 +721,7 @@
       <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="3" />
       <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.14623655" order="1" />
       <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3282876" order="8" />
-      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.38315988" order="2" />
+      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.38315988" order="2" />
       <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="2" />
       <window_info id="File View" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="6" />
       <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.39978448" order="0" />
@@ -743,48 +820,6 @@
     <option name="myLastEditedConfigurable" value="Default" />
   </component>
   <component name="editorHistoryManager">
-    <entry file="file://$PROJECT_DIR$/test/com/google/inject/NotRequiredTest.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="32" column="3" selection-start="1058" selection-end="1058" vertical-scroll-proportion="0.48188975">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/test/com/google/inject/ContainerTest.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="189" column="4" selection-start="4176" selection-end="4176" vertical-scroll-proportion="1.0598425">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/test/com/google/inject/ConstantConversionTest.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="110" column="17" selection-start="3274" selection-end="3274" vertical-scroll-proportion="2.4897637">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/AbstractModule.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="121" column="0" selection-start="2941" selection-end="2941" vertical-scroll-proportion="1.5291339">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/TypeLiteral.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="40" column="4" selection-start="1254" selection-end="1254" vertical-scroll-proportion="0.026771653">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/ConfigurationException.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="33" column="2" selection-start="958" selection-end="958" vertical-scroll-proportion="0.5086614">
-          <folding />
-        </state>
-      </provider>
-    </entry>
     <entry file="jar:///usr/local/src.zip!/java/lang/reflect/Type.java">
       <provider selected="true" editor-type-id="text-editor">
         <state line="17" column="17" selection-start="426" selection-end="426" vertical-scroll-proportion="0.32125986">
@@ -822,28 +857,70 @@
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/google/inject/FactoryToInternalFactoryAdapter.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="14" column="32" selection-start="397" selection-end="397" vertical-scroll-proportion="0.31946307">
+        <state line="14" column="32" selection-start="397" selection-end="397" vertical-scroll-proportion="0.37480316">
           <folding />
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/google/inject/InternalFactoryToFactoryAdapter.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="15" column="34" selection-start="391" selection-end="391" vertical-scroll-proportion="0.34228188">
+        <state line="15" column="34" selection-start="391" selection-end="391" vertical-scroll-proportion="0.4015748">
           <folding />
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/google/inject/InternalToContextualFactoryAdapter.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="21" column="18" selection-start="512" selection-end="512" vertical-scroll-proportion="0.47919464">
+        <state line="21" column="18" selection-start="512" selection-end="512" vertical-scroll-proportion="0.5622047">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/TypeLiteral.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="150" column="18" selection-start="4385" selection-end="4385" vertical-scroll-proportion="1.0598425">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/Key.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="153" column="22" selection-start="3934" selection-end="3934" vertical-scroll-proportion="0.41732284">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/ErrorHandler.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="8" column="3" selection-start="167" selection-end="167" vertical-scroll-proportion="0.21417323">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/test/com/google/inject/AllTests.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="45" column="22" selection-start="1548" selection-end="1548" vertical-scroll-proportion="0.6692913">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="248" column="0" selection-start="7834" selection-end="7834" vertical-scroll-proportion="0.38110235">
           <folding />
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/google/inject/ContainerBuilder.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="95" column="77" selection-start="3261" selection-end="3261" vertical-scroll-proportion="0.24697986">
+        <state line="884" column="34" selection-start="24992" selection-end="24992" vertical-scroll-proportion="2.7259843">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/test/com/google/inject/ErrorHandlingTest.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="11" column="18" selection-start="205" selection-end="205" vertical-scroll-proportion="0.2944882">
           <folding />
         </state>
       </provider>
diff --git a/src/com/google/inject/ContainerBuilder.java b/src/com/google/inject/ContainerBuilder.java
index b5bb567..c8cf940 100644
--- a/src/com/google/inject/ContainerBuilder.java
+++ b/src/com/google/inject/ContainerBuilder.java
@@ -17,6 +17,7 @@
 package com.google.inject;
 
 import com.google.inject.util.Objects;
+import com.google.inject.util.Stopwatch;
 import static com.google.inject.util.Objects.nonNull;
 
 import java.lang.reflect.Member;
@@ -64,7 +65,8 @@
       new ArrayList<LinkedBindingBuilder<?>>();
   final Map<String, Scope> scopes = new HashMap<String, Scope>();
 
-  final List<Class<?>> staticInjections = new ArrayList<Class<?>>();
+  final List<StaticInjection> staticInjections =
+      new ArrayList<StaticInjection>();
 
   boolean created;
 
@@ -117,14 +119,13 @@
    */
   void validate(final Object source, final Class<?> type) {
     validations.add(new Validation() {
-      public void run(ContainerImpl container) {
-        ErrorHandler previous = container.getErrorHandler();
-        try {
-          container.setErrorHandler(new ConfigurationErrorHandler(source));
-          container.getConstructor(type);
-        } finally {
-          container.setErrorHandler(previous);
-        }
+      public void run(final ContainerImpl container) {
+        container.withErrorHandler(new ConfigurationErrorHandler(source),
+            new Runnable() {
+              public void run() {
+                container.getConstructor(type);
+              }
+            });
       }
     });
   }
@@ -237,7 +238,7 @@
    * @param types for which static members will be injected
    */
   public void requestStaticInjection(Class<?>... types) {
-    staticInjections.addAll(Arrays.asList(types));
+    staticInjections.add(new StaticInjection(source(), types));
   }
 
   /**
@@ -308,6 +309,12 @@
 
     stopwatch.resetAndLog(logger, "Validation");
 
+    for (StaticInjection staticInjection : staticInjections) {
+      staticInjection.createInjectors(container);
+    }
+
+    stopwatch.resetAndLog(logger, "Static validation");
+
     // Blow up.
     if (!errorMessages.isEmpty()) {
       throw new ContainerCreationException(createErrorMessage());
@@ -317,7 +324,9 @@
     container.setErrorHandler(new RuntimeErrorHandler());
 
     // Inject static members.
-    container.injectStatics(staticInjections);
+    for (StaticInjection staticInjection : staticInjections) {
+      staticInjection.runInjectors(container);
+    }
 
     stopwatch.resetAndLog(logger, "Static member injection");
 
@@ -872,4 +881,45 @@
     }
     throw new AssertionError();
   }
+
+  /**
+   * A requested static injection.
+   */
+  class StaticInjection {
+
+    final Object source;
+    final Class<?>[] types;
+    final List<ContainerImpl.Injector> injectors =
+        new ArrayList<ContainerImpl.Injector>();
+
+    public StaticInjection(Object source, Class<?>[] types) {
+      this.source = source;
+      this.types = types;
+    }
+
+    void createInjectors(final ContainerImpl container) {
+      container.withErrorHandler(new ConfigurationErrorHandler(source),
+          new Runnable() {
+            public void run() {
+              for (Class<?> clazz : types) {
+                container.addInjectorsForFields(
+                    clazz.getDeclaredFields(), true, injectors);
+                container.addInjectorsForMethods(
+                    clazz.getDeclaredMethods(), true, injectors);
+              }
+            }
+          });
+    }
+
+    void runInjectors(ContainerImpl container) {
+      container.callInContext(new ContainerImpl.ContextualCallable<Void>() {
+        public Void call(InternalContext context) {
+          for (ContainerImpl.Injector injector : injectors) {
+            injector.inject(context, null);
+          }
+          return null;
+        }
+      });
+    }
+  }
 }
diff --git a/src/com/google/inject/ContainerImpl.java b/src/com/google/inject/ContainerImpl.java
index 8c08418..2ca249d 100644
--- a/src/com/google/inject/ContainerImpl.java
+++ b/src/com/google/inject/ContainerImpl.java
@@ -89,12 +89,18 @@
     this.factories = factories;
   }
 
-  void setErrorHandler(ErrorHandler errorHandler) {
+  void withErrorHandler(ErrorHandler errorHandler, Runnable runnable) {
+    ErrorHandler previous = this.errorHandler;
     this.errorHandler = errorHandler;
+    try {
+      runnable.run();
+    } finally {
+      this.errorHandler = previous;
+    }
   }
 
-  ErrorHandler getErrorHandler() {
-    return errorHandler;
+  void setErrorHandler(ErrorHandler errorHandler) {
+    this.errorHandler = errorHandler;
   }
 
   @SuppressWarnings("unchecked")
@@ -240,24 +246,6 @@
     addInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors);
   }
 
-  void injectStatics(List<Class<?>> staticInjections) {
-    final List<Injector> injectors = new ArrayList<Injector>();
-
-    for (Class<?> clazz : staticInjections) {
-      addInjectorsForFields(clazz.getDeclaredFields(), true, injectors);
-      addInjectorsForMethods(clazz.getDeclaredMethods(), true, injectors);
-    }
-
-    callInContext(new ContextualCallable<Void>() {
-      public Void call(InternalContext context) {
-        for (Injector injector : injectors) {
-          injector.inject(context, null);
-        }
-        return null;
-      }
-    });
-  }
-
   void addInjectorsForMethods(Method[] methods, boolean statics,
       List<Injector> injectors) {
     addInjectorsForMembers(Arrays.asList(methods), statics, injectors,
diff --git a/src/com/google/inject/Stopwatch.java b/src/com/google/inject/util/Stopwatch.java
similarity index 71%
rename from src/com/google/inject/Stopwatch.java
rename to src/com/google/inject/util/Stopwatch.java
index 582b96e..62850e8 100644
--- a/src/com/google/inject/Stopwatch.java
+++ b/src/com/google/inject/util/Stopwatch.java
@@ -1,20 +1,22 @@
 // Copyright 2006 Google Inc. All Rights Reserved.
 
-package com.google.inject;
+package com.google.inject.util;
 
 import java.util.logging.Logger;
 
 /**
+ * Enables simple performance monitoring.
+ *
  * @author crazybob@google.com (Bob Lee)
  */
-class Stopwatch {
+public class Stopwatch {
 
   long start = System.currentTimeMillis();
 
   /**
    * Resets and returns ellapsed time.
    */
-  long reset() {
+  public long reset() {
     long now = System.currentTimeMillis();
     try {
       return now - start;
@@ -26,7 +28,7 @@
   /**
    * Resets and logs ellapsed time.
    */
-  void resetAndLog(Logger logger, String label) {
+  public void resetAndLog(Logger logger, String label) {
     logger.info(label + ": " + reset() + "ms");
   }
 }
diff --git a/test/com/google/inject/ErrorHandlingTest.java b/test/com/google/inject/ErrorHandlingTest.java
index 8a768d4..e8af9e1 100644
--- a/test/com/google/inject/ErrorHandlingTest.java
+++ b/test/com/google/inject/ErrorHandlingTest.java
@@ -9,6 +9,9 @@
  */
 public class ErrorHandlingTest {
 
+  @Inject("missing")
+  static List<String> missing;
+
   static class Foo {
     @Inject
     public Foo(Runnable r) {}
@@ -39,6 +42,7 @@
       bind(Tee.class);
       bind(String.class).named("foo").in("foo");
       link(Key.get(Runnable.class)).to(Key.get(Runnable.class));
+      requestStaticInjection(ErrorHandlingTest.class);
     }
   }