Added requireBinding() convenience method to AbstractModule.

Also, improved the missing binding warning to include the full type information
  "missing binding to Callable<String>"
rather than just the partial information
  "missing binding to Callable"

git-svn-id: https://google-guice.googlecode.com/svn/trunk@566 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/AbstractModule.java b/src/com/google/inject/AbstractModule.java
index 62d1fb7..cebc188 100644
--- a/src/com/google/inject/AbstractModule.java
+++ b/src/com/google/inject/AbstractModule.java
@@ -167,6 +167,26 @@
   }
 
   /**
+   * 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.
+   */
+  protected void requireBinding(Key<?> key) {
+    binder.getProvider(key);
+  }
+
+  /**
+   * Adds a dependency from this module to {@code type}. 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.
+   */
+  protected void requireBinding(Class<?> type) {
+    binder.getProvider(type);
+  }
+
+  /**
    * @see Binder#getProvider(Key)
    */
   protected <T> Provider<T> getProvider(Key<T> key) {
diff --git a/src/com/google/inject/BindCommandProcessor.java b/src/com/google/inject/BindCommandProcessor.java
index f821b8f..515e91e 100644
--- a/src/com/google/inject/BindCommandProcessor.java
+++ b/src/com/google/inject/BindCommandProcessor.java
@@ -171,7 +171,8 @@
         Class<T> clazz = (Class<T>) type;
         final BindingImpl<T> binding;
         try {
-          binding = injector.createUnitializedBinding(clazz, scope, source, loadStrategy, errors);
+          binding = injector.createUnitializedBinding(
+              key, clazz, scope, source, loadStrategy, errors);
           putBinding(binding);
         } catch (ErrorsException e) {
           errors.merge(e.getErrors());
diff --git a/src/com/google/inject/InjectorImpl.java b/src/com/google/inject/InjectorImpl.java
index 3e9d1cb..b9f99d9 100644
--- a/src/com/google/inject/InjectorImpl.java
+++ b/src/com/google/inject/InjectorImpl.java
@@ -377,9 +377,9 @@
   }
 
   <T> BindingImpl<T> createBindingFromType(
-      Class<T> type, LoadStrategy loadStrategy, Errors errors) throws ErrorsException {
+      Key<T> key, LoadStrategy loadStrategy, Errors errors) throws ErrorsException {
     BindingImpl<T> binding = createUnitializedBinding(
-        type, null, StackTraceElements.forType(type), loadStrategy, errors);
+        key, null, loadStrategy, errors);
     initializeBinding(binding, errors);
     return binding;
   }
@@ -405,11 +405,24 @@
     }
   }
 
+  <T> BindingImpl<T> createUnitializedBinding(Key<T> key, Scope scope,
+      LoadStrategy loadStrategy, Errors errors) throws ErrorsException {
+    @SuppressWarnings("unchecked")
+    Class<T> type = (Class<T>) key.getTypeLiteral().getRawType();
+    Object source = StackTraceElements.forType(type);
+    return createUnitializedBinding(key, type, scope, source, loadStrategy, errors);
+  }
+
   /**
    * Creates a binding for an injectable type with the given scope. Looks for a scope on the type if
    * none is specified.
+   *
+   * TODO(jessewilson): Fix raw types! this method makes a binding for {@code Foo} from a request
+   *     for {@code Foo<String>}
+   *
+   * @param type the raw type for {@code key}
    */
-  <T> BindingImpl<T> createUnitializedBinding(Class<T> type, Scope scope, Object source,
+  <T> BindingImpl<T> createUnitializedBinding(Key<T> key, Class<T> type, Scope scope, Object source,
       LoadStrategy loadStrategy, Errors errors) throws ErrorsException {
     // Don't try to inject arrays, or enums.
     if (type.isArray() || type.isEnum()) {
@@ -434,7 +447,7 @@
     // TODO: Method interceptors could actually enable us to implement
     // abstract types. Should we remove this restriction?
     if (Modifier.isAbstract(type.getModifiers())) {
-      throw errors.missingImplementation(type).toException();
+      throw errors.missingImplementation(key).toException();
     }
 
     // Error: Inner class.
@@ -452,13 +465,13 @@
       }
     }
 
-    Key<T> key = Key.get(type);
+    Key<T> keyForRawType = Key.get(type);
 
     LateBoundConstructor<T> lateBoundConstructor = new LateBoundConstructor<T>();
     InternalFactory<? extends T> scopedFactory
-        = Scopes.scope(key, this, lateBoundConstructor, scope);
+        = Scopes.scope(keyForRawType, this, lateBoundConstructor, scope);
     return new ClassBindingImpl<T>(
-        this, key, source, scopedFactory, scope, lateBoundConstructor, loadStrategy);
+        this, keyForRawType, source, scopedFactory, scope, lateBoundConstructor, loadStrategy);
   }
 
   static class LateBoundConstructor<T> implements InternalFactory<T> {
@@ -604,9 +617,7 @@
     }
 
     // Create a binding based on the raw type.
-    @SuppressWarnings("unchecked")
-    Class<T> clazz = (Class<T>) key.getTypeLiteral().getRawType();
-    return createBindingFromType(clazz, LoadStrategy.LAZY, errors);
+    return createBindingFromType(key, LoadStrategy.LAZY, errors);
   }
 
   <T> InternalFactory<? extends T> getInternalFactory(Key<T> key, Errors errors)
diff --git a/test/com/google/inject/BinderTest.java b/test/com/google/inject/BinderTest.java
index 30c9878..6f96ae0 100644
--- a/test/com/google/inject/BinderTest.java
+++ b/test/com/google/inject/BinderTest.java
@@ -28,6 +28,7 @@
 import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
+import java.util.concurrent.Callable;
 import junit.framework.TestCase;
 
 /**
@@ -76,17 +77,20 @@
         public void configure() {
           getProvider(Runnable.class);
           bind(Comparator.class);
+          requireBinding(Key.get(new TypeLiteral<Callable<String>>() {}));
           bind(Date.class).annotatedWith(Names.named("date"));
         }
       });
     } catch (CreationException e) {
-      assertEquals(3, e.getErrorMessages().size());
+      assertEquals(4, e.getErrorMessages().size());
       assertContains(e.getMessage(),
           "1) Error at " + getClass().getName(),
           "No implementation for java.lang.Runnable was bound.",
           "2) Error at " + getClass().getName(),
           "No implementation for " + Comparator.class.getName() + " was bound.",
           "3) Error at " + getClass().getName(),
+          "No implementation for java.util.concurrent.Callable<java.lang.String> was bound.",
+          "4) Error at " + getClass().getName(),
           "No implementation for java.util.Date annotated with "
               + "@com.google.inject.name.Named(value=date) was bound.");
     }