Fixing the binding order problem. My strategy was to break binding creation into two steps:
 - creating the binding itself
 - "initializing" the binding, ie. validating the bindings dependencies

This CL is a start of something that we could go further on. In particular, we could change the @ProvidedBy etc. bindings to use a BindingImpl.initialize() method uniformly to separate creating the binding from building its dependencies.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@473 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/BindCommandProcessor.java b/src/com/google/inject/BindCommandProcessor.java
index 1ab63c6..59db4b9 100644
--- a/src/com/google/inject/BindCommandProcessor.java
+++ b/src/com/google/inject/BindCommandProcessor.java
@@ -158,18 +158,25 @@
           return null;
         }
 
+        // This cast is safe after the preceeding check.
+        @SuppressWarnings("unchecked")
+        Class<T> clazz = (Class<T>) type;
+        final BindingImpl<T> binding;
+        try {
+          binding = injector.createUnitializedBinding(clazz, scope, source);
+          createBinding(source, shouldPreload, binding);
+        } catch (ResolveFailedException e) {
+          injector.errorHandler.handle(source, e.getMessage());
+          createBinding(source, shouldPreload, invalidBinding(injector, key, source));
+          return null;
+        }
+
         untargettedBindings.add(new Runnable() {
           public void run() {
-            // This cast is safe after the preceeding check.
-            @SuppressWarnings("unchecked")
-            Class<T> clazz = (Class<T>) type;
-
             try {
-              BindingImpl<T> binding = injector.createBindingFromType(clazz, scope, source);
-              createBinding(source, shouldPreload, binding);
+              injector.initializeBinding(binding);
             } catch (ResolveFailedException e) {
               injector.errorHandler.handle(source, e.getMessage());
-              createBinding(source, shouldPreload, invalidBinding(injector, key, source));
             }
           }
         });
diff --git a/src/com/google/inject/BindingImpl.java b/src/com/google/inject/BindingImpl.java
index acf4ae3..771d13d 100644
--- a/src/com/google/inject/BindingImpl.java
+++ b/src/com/google/inject/BindingImpl.java
@@ -16,6 +16,7 @@
 
 package com.google.inject;
 
+import com.google.inject.internal.ResolveFailedException;
 import com.google.inject.internal.ToStringBuilder;
 import com.google.inject.spi.ProviderBinding;
 
@@ -79,6 +80,12 @@
     return internalFactory instanceof ConstantFactory<?>;
   }
 
+  /**
+   * Perform any post-creation initialization, that could require construction
+   * of other bindings.
+   */
+  void initialize(InjectorImpl injector) throws ResolveFailedException {}
+
   public String toString() {
     return new ToStringBuilder(Binding.class)
         .add("key", key)
diff --git a/src/com/google/inject/ClassBindingImpl.java b/src/com/google/inject/ClassBindingImpl.java
index 9eb2756..65cdf30 100644
--- a/src/com/google/inject/ClassBindingImpl.java
+++ b/src/com/google/inject/ClassBindingImpl.java
@@ -17,6 +17,7 @@
 package com.google.inject;
 
 import com.google.inject.InjectorImpl.SingleParameterInjector;
+import com.google.inject.internal.ResolveFailedException;
 import com.google.inject.internal.ToStringBuilder;
 import com.google.inject.spi.BindingVisitor;
 import com.google.inject.spi.ClassBinding;
@@ -40,6 +41,10 @@
     this.lateBoundConstructor = lateBoundConstructor;
   }
 
+  @Override void initialize(InjectorImpl injector) throws ResolveFailedException {
+    lateBoundConstructor.bind(injector, getBoundClass());
+  }
+
   public void accept(BindingVisitor<? super T> visitor) {
     visitor.visit(this);
   }
diff --git a/src/com/google/inject/InjectorImpl.java b/src/com/google/inject/InjectorImpl.java
index c2b2822..1014a07 100644
--- a/src/com/google/inject/InjectorImpl.java
+++ b/src/com/google/inject/InjectorImpl.java
@@ -492,6 +492,38 @@
 
   <T> BindingImpl<T> createBindingFromType(Class<T> type, Scope scope,
       Object source) throws ResolveFailedException {
+    BindingImpl<T> binding = createUnitializedBinding(type, scope, source);
+    initializeBinding(binding);
+    return binding;
+  }
+
+  <T> void initializeBinding(BindingImpl<T> binding) throws ResolveFailedException {
+    // Put the partially constructed binding in the map a little early. This
+    // enables us to handle circular dependencies.
+    // Example: FooImpl -> BarImpl -> FooImpl.
+    // Note: We don't need to synchronize on jitBindings during injector
+    // creation.
+    if (binding instanceof ClassBindingImpl<?>) {
+      Key<T> key = binding.getKey();
+      jitBindings.put(key, binding);
+      boolean successful = false;
+      try {
+        binding.initialize(this);
+        successful = true;
+      } finally {
+        if (!successful) {
+          jitBindings.remove(key);
+        }
+      }
+    }
+  }
+
+  /**
+   * 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> createUnitializedBinding(Class<T> type,
+      Scope scope, Object source) throws ResolveFailedException {
     // Don't try to inject primitives, arrays, or enums.
     if (type.isArray() || type.isEnum() || type.isPrimitive()) {
       throw new ResolveFailedException(ErrorMessages.MISSING_BINDING, type);
@@ -511,16 +543,6 @@
       return createProvidedByBinding(type, providedBy);
     }
 
-    return createBindingForInjectableType(type, scope, source);
-  }
-
-  /**
-   * 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> createBindingForInjectableType(Class<T> type,
-      Scope scope, Object source) throws ResolveFailedException {
-
     // We can't inject abstract classes.
     // TODO: Method interceptors could actually enable us to implement
     // abstract types. Should we remove this restriction?
@@ -544,26 +566,7 @@
     InternalFactory<? extends T> scopedFactory
         = Scopes.scope(key, this, lateBoundConstructor, scope);
 
-    BindingImpl<T> binding
-        = new ClassBindingImpl<T>(this, key, source, scopedFactory, scope, lateBoundConstructor);
-
-    // Put the partially constructed binding in the map a little early. This
-    // enables us to handle circular dependencies.
-    // Example: FooImpl -> BarImpl -> FooImpl.
-    // Note: We don't need to synchronize on jitBindings during injector
-    // creation.
-    jitBindings.put(key, binding);
-    boolean successful = false;
-    try {
-      lateBoundConstructor.bind(this, type);
-      successful = true;
-    } finally {
-      if (!successful) {
-        jitBindings.remove(key);
-      }
-    }
-
-    return binding;
+    return new ClassBindingImpl<T>(this, key, source, scopedFactory, scope, lateBoundConstructor);
   }
 
   static class LateBoundConstructor<T> implements InternalFactory<T> {