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.");
}