Added some new error messages:
- when a method or constructor has a binding annotation, rather than its parameters
- when a type has a scope annotation, but that scope is not bound
- when a scope annotation is applied to an abstract type or interface
I suspect these will find lots of bugs!
git-svn-id: https://google-guice.googlecode.com/svn/trunk@523 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/AbstractModule.java b/src/com/google/inject/AbstractModule.java
index 25ff52e..87c6491 100644
--- a/src/com/google/inject/AbstractModule.java
+++ b/src/com/google/inject/AbstractModule.java
@@ -22,6 +22,7 @@
import com.google.inject.binder.AnnotatedConstantBindingBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.matcher.Matcher;
+import com.google.inject.spi.Message;
import com.google.inject.spi.SourceProviders;
import com.google.inject.spi.TypeConverter;
import java.lang.annotation.Annotation;
@@ -139,6 +140,13 @@
}
/**
+ * @see Binder#addError(Message)
+ */
+ protected void addError(Message message) {
+ binder.addError(message);
+ }
+
+ /**
* @see Binder#requestStaticInjection(Class[])
*/
protected void requestStaticInjection(Class<?>... types) {
diff --git a/src/com/google/inject/BindCommandProcessor.java b/src/com/google/inject/BindCommandProcessor.java
index f155e13..e44d18a 100644
--- a/src/com/google/inject/BindCommandProcessor.java
+++ b/src/com/google/inject/BindCommandProcessor.java
@@ -23,6 +23,7 @@
import com.google.inject.commands.BindScoping.Visitor;
import com.google.inject.commands.BindTarget;
import com.google.inject.internal.Annotations;
+import com.google.inject.internal.Classes;
import com.google.inject.internal.Errors;
import com.google.inject.internal.ErrorsException;
import com.google.inject.internal.StackTraceElements;
@@ -91,7 +92,7 @@
return scope;
} else {
errors.scopeNotFound(scopeAnnotation);
- return Scopes.NO_SCOPE;
+ return null;
}
}
@@ -207,6 +208,15 @@
errors.at(StackTraceElements.forType(annotationType)).missingBindingAnnotation(source);
}
}
+
+ Class<? super T> rawType = key.getRawType();
+ if (!Classes.isConcrete(rawType)) {
+ Class<? extends Annotation> scopeAnnotation = Scopes.getScopeAnnotation(errors, rawType);
+ if (scopeAnnotation != null) {
+ errors.at(StackTraceElements.forType(rawType))
+ .scopeAnnotationOnAbstractType(scopeAnnotation, rawType, source);
+ }
+ }
}
<T> InvalidBindingImpl<T> invalidBinding(InjectorImpl injector, Key<T> key, Object source) {
diff --git a/src/com/google/inject/Binder.java b/src/com/google/inject/Binder.java
index 2e32780..9382b75 100644
--- a/src/com/google/inject/Binder.java
+++ b/src/com/google/inject/Binder.java
@@ -260,6 +260,11 @@
void addError(Throwable t);
/**
+ * Records an error message to be presented to the user at a later time.
+ */
+ void addError(Message message);
+
+ /**
* Returns the provider used to obtain instances for the given injection key.
* The returned will not be valid until the {@link Injector} has been
* created. The provider will throw an {@code IllegalStateException} if you
diff --git a/src/com/google/inject/ConstructionProxy.java b/src/com/google/inject/ConstructionProxy.java
index fb5267d..39e3e3c 100644
--- a/src/com/google/inject/ConstructionProxy.java
+++ b/src/com/google/inject/ConstructionProxy.java
@@ -16,8 +16,8 @@
package com.google.inject;
+import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Member;
import java.util.List;
/**
@@ -36,9 +36,8 @@
List<Parameter<?>> getParameters();
/**
- * Returns the injected method or constructor. If the injected member is
- * synthetic (such as generated code for method interception), the natural
- * constructor is returned.
+ * Returns the injected constructor. If the injected constructor is synthetic (such as generated
+ * code for method interception), the natural constructor is returned.
*/
- Member getMember();
+ Constructor getConstructor();
}
diff --git a/src/com/google/inject/ConstructorInjector.java b/src/com/google/inject/ConstructorInjector.java
index 89caef9..66cdada 100644
--- a/src/com/google/inject/ConstructorInjector.java
+++ b/src/com/google/inject/ConstructorInjector.java
@@ -20,6 +20,8 @@
import com.google.inject.InjectorImpl.SingleParameterInjector;
import com.google.inject.internal.Errors;
import com.google.inject.internal.ErrorsException;
+import com.google.inject.internal.StackTraceElements;
+import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
@@ -48,10 +50,17 @@
SingleParameterInjector<?>[] createParameterInjector(Errors errors,
InjectorImpl injector, ConstructionProxy<T> constructionProxy)
throws ErrorsException {
- return constructionProxy.getParameters().isEmpty()
- ? null // default constructor.
- : injector.getParametersInjectors(constructionProxy.getMember(),
- constructionProxy.getParameters(), errors);
+ Constructor constructor = constructionProxy.getConstructor();
+ Object source = StackTraceElements.forMember(constructor);
+ errors.pushSource(source);
+ try {
+ return constructionProxy.getParameters().isEmpty()
+ ? null // default constructor.
+ : injector.getParametersInjectors(constructor,
+ constructionProxy.getParameters(), errors);
+ } finally {
+ errors.popSource(source);
+ }
}
/**
diff --git a/src/com/google/inject/DefaultConstructionProxyFactory.java b/src/com/google/inject/DefaultConstructionProxyFactory.java
index c99f508..33bfdc8 100644
--- a/src/com/google/inject/DefaultConstructionProxyFactory.java
+++ b/src/com/google/inject/DefaultConstructionProxyFactory.java
@@ -21,7 +21,6 @@
import com.google.inject.internal.GuiceFastClass;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.util.List;
import net.sf.cglib.reflect.FastClass;
@@ -60,7 +59,7 @@
public List<Parameter<?>> getParameters() {
return parameters;
}
- public Member getMember() {
+ public Constructor getConstructor() {
return constructor;
}
};
@@ -78,7 +77,7 @@
public List<Parameter<?>> getParameters() {
return parameters;
}
- public Member getMember() {
+ public Constructor getConstructor() {
return constructor;
}
};
diff --git a/src/com/google/inject/InjectorImpl.java b/src/com/google/inject/InjectorImpl.java
index 2bf0a63..d6966ba 100644
--- a/src/com/google/inject/InjectorImpl.java
+++ b/src/com/google/inject/InjectorImpl.java
@@ -488,7 +488,13 @@
}
if (scope == null) {
- scope = Scopes.getScopeForType(errors, type, scopes);
+ Class<? extends Annotation> scopeAnnotation = Scopes.getScopeAnnotation(errors, type);
+ if (scopeAnnotation != null) {
+ scope = scopes.get(scopeAnnotation);
+ if (scope == null) {
+ errors.at(StackTraceElements.forType(type)).scopeNotFound(scopeAnnotation);
+ }
+ }
}
Key<T> key = Key.get(type);
@@ -830,8 +836,14 @@
* @param member to which the parameters belong
* @return injections
*/
- SingleParameterInjector<?>[] getParametersInjectors(
- Member member, List<Parameter<?>> parameters, Errors errors) throws ErrorsException {
+ <M extends Member & AnnotatedElement> SingleParameterInjector<?>[] getParametersInjectors(
+ M member, List<Parameter<?>> parameters, Errors errors) throws ErrorsException {
+ Annotation misplacedBindingAnnotation
+ = Keys.findBindingAnnotation(errors, member, member.getAnnotations());
+ if (misplacedBindingAnnotation != null) {
+ errors.misplacedBindingAnnotation(member, misplacedBindingAnnotation);
+ }
+
SingleParameterInjector<?>[] parameterInjectors
= new SingleParameterInjector<?>[parameters.size()];
int index = 0;
diff --git a/src/com/google/inject/ProviderMethods.java b/src/com/google/inject/ProviderMethods.java
index 86408a8..258f81d 100644
--- a/src/com/google/inject/ProviderMethods.java
+++ b/src/com/google/inject/ProviderMethods.java
@@ -18,12 +18,11 @@
import com.google.common.collect.Lists;
import com.google.inject.internal.Errors;
+import com.google.inject.internal.Keys;
import com.google.inject.internal.StackTraceElements;
-import com.google.inject.spi.SourceProvider;
-import com.google.inject.spi.SourceProviders;
+import com.google.inject.spi.Message;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
@@ -47,24 +46,12 @@
final Object providers;
- Object source;
-
- final SourceProvider sourceProvider = new SourceProvider() {
- public Object source() {
- return source;
- }
- };
-
ProviderMethodsModule(Object providers) {
this.providers = providers;
}
protected void configure() {
- SourceProviders.withDefault(sourceProvider, new Runnable() {
- public void run() {
- bindProviderMethods(providers.getClass());
- }
- });
+ bindProviderMethods(providers.getClass());
}
void bindProviderMethods(Class<?> clazz) {
@@ -82,21 +69,25 @@
}
<T> void bindProviderMethod(final Method method) {
- this.source = StackTraceElements.forMember(method);
+ Errors errors = new Errors()
+ .pushSource(StackTraceElements.forMember(method));
method.setAccessible(true);
Class<? extends Annotation> scopeAnnotation
- = findScopeAnnotation(method.getAnnotations());
- Annotation bindingAnnotation = findBindingAnnotation(method, method.getAnnotations());
+ = findScopeAnnotation(errors, method.getAnnotations());
+ Annotation bindingAnnotation
+ = Keys.findBindingAnnotation(errors, method, method.getAnnotations());
- final List<Provider<?>> parameterProviders
- = findParameterProviders(method);
+ final List<Provider<?>> parameterProviders = findParameterProviders(errors, method);
+
+ for (Message message : errors.getMessages()) {
+ addError(message);
+ }
// Define T as the method's return type.
@SuppressWarnings("unchecked")
- TypeLiteral<T> returnType
- = (TypeLiteral<T>) TypeLiteral.get(method.getGenericReturnType());
+ TypeLiteral<T> returnType = (TypeLiteral<T>) TypeLiteral.get(method.getGenericReturnType());
Provider<T> provider = new Provider<T>() {
public T get() {
@@ -107,8 +98,8 @@
try {
// We know this cast is safe becase T is the method's return type.
- @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
- T result = (T) method.invoke(providers, parameters);
+ @SuppressWarnings({ "unchecked", "UnnecessaryLocalVariable" }) T result = (T) method
+ .invoke(providers, parameters);
return result;
}
catch (IllegalAccessException e) {
@@ -134,13 +125,14 @@
}
}
- List<Provider<?>> findParameterProviders(Method method) {
+ List<Provider<?>> findParameterProviders(Errors errors, Method method) {
List<Provider<?>> parameterProviders = Lists.newArrayList();
Type[] parameterTypes = method.getGenericParameterTypes();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0; i < parameterTypes.length; i++) {
- Annotation bindingAnnotation = findBindingAnnotation(method, parameterAnnotations[i]);
+ Annotation bindingAnnotation
+ = Keys.findBindingAnnotation(errors, method, parameterAnnotations[i]);
Key<?> key = bindingAnnotation == null ? Key.get(parameterTypes[i])
: Key.get(parameterTypes[i], bindingAnnotation);
Provider<?> provider = getProvider(key);
@@ -150,15 +142,17 @@
return parameterProviders;
}
- Class<? extends Annotation> findScopeAnnotation(Annotation[] annotations) {
+ /**
+ * Returns the scoping annotation, or null if there isn't one.
+ */
+ Class<? extends Annotation> findScopeAnnotation(Errors errors, Annotation[] annotations) {
Class<? extends Annotation> found = null;
for (Annotation annotation : annotations) {
if (annotation.annotationType()
.isAnnotationPresent(ScopeAnnotation.class)) {
if (found != null) {
- addError(new Errors().duplicateScopeAnnotations(
- found, annotation.annotationType()).toString());
+ errors.duplicateScopeAnnotations(found, annotation.annotationType());
} else {
found = annotation.annotationType();
}
@@ -167,23 +161,5 @@
return found;
}
-
- Annotation findBindingAnnotation(Member member, Annotation[] annotations) {
- Annotation found = null;
-
- for (Annotation annotation : annotations) {
- if (annotation.annotationType()
- .isAnnotationPresent(BindingAnnotation.class)) {
- if (found != null) {
- addError(new Errors().duplicateBindingAnnotations(member,
- found.annotationType(), annotation.annotationType()).toString());
- } else {
- found = annotation;
- }
- }
- }
-
- return found;
- }
}
}
diff --git a/src/com/google/inject/ProxyFactory.java b/src/com/google/inject/ProxyFactory.java
index 6923798..07aca7c 100644
--- a/src/com/google/inject/ProxyFactory.java
+++ b/src/com/google/inject/ProxyFactory.java
@@ -25,7 +25,6 @@
import com.google.inject.internal.ReferenceCache;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@@ -188,7 +187,7 @@
return parameters;
}
- public Member getMember() {
+ public Constructor getConstructor() {
return standardConstructor;
}
};
diff --git a/src/com/google/inject/Scopes.java b/src/com/google/inject/Scopes.java
index c124b81..f0bc525 100644
--- a/src/com/google/inject/Scopes.java
+++ b/src/com/google/inject/Scopes.java
@@ -18,7 +18,6 @@
import com.google.inject.internal.Errors;
import java.lang.annotation.Annotation;
-import java.util.Map;
/**
* Built in scope implementations.
@@ -88,27 +87,22 @@
};
/**
- * Gets the scope for a type based on its annotations. Returns {@code null}
- * if none specified.
- *
- * @param implementation type
- * @param scopes map of scope names to scopes
+ * Returns the scope annotation on {@code type}, or null if none is specified.
*/
- static Scope getScopeForType(Errors errors, Class<?> implementation,
- Map<Class<? extends Annotation>, Scope> scopes) {
+ static Class<? extends Annotation> getScopeAnnotation(
+ Errors errors, Class<?> implementation) {
Class<? extends Annotation> found = null;
for (Annotation annotation : implementation.getAnnotations()) {
if (isScopeAnnotation(annotation)) {
if (found != null) {
errors.duplicateScopeAnnotations(found, annotation.annotationType());
- }
- else {
+ } else {
found = annotation.annotationType();
}
}
}
- return scopes.get(found);
+ return found;
}
static boolean isScopeAnnotation(Annotation annotation) {
diff --git a/src/com/google/inject/commands/CommandRecorder.java b/src/com/google/inject/commands/CommandRecorder.java
index a4b3307..c9c17f0 100644
--- a/src/com/google/inject/commands/CommandRecorder.java
+++ b/src/com/google/inject/commands/CommandRecorder.java
@@ -16,18 +16,29 @@
package com.google.inject.commands;
-import com.google.inject.*;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.inject.Binder;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.Provider;
+import com.google.inject.Scope;
+import com.google.inject.Stage;
+import com.google.inject.TypeLiteral;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.AnnotatedConstantBindingBuilder;
import com.google.inject.matcher.Matcher;
+import com.google.inject.spi.Message;
import com.google.inject.spi.SourceProviders;
import static com.google.inject.spi.SourceProviders.defaultSource;
import com.google.inject.spi.TypeConverter;
-import org.aopalliance.intercept.MethodInterceptor;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.aopalliance.intercept.MethodInterceptor;
/**
* Records commands executed by a module so they can be inspected or
@@ -78,8 +89,8 @@
}
private class RecordingBinder implements Binder {
- private final Set<Module> modules = new HashSet<Module>();
- private final List<Command> commands = new ArrayList<Command>();
+ private final Set<Module> modules = Sets.newHashSet();
+ private final List<Command> commands = Lists.newArrayList();
public void bindInterceptor(
Matcher<? super Class<?>> classMatcher,
@@ -115,6 +126,10 @@
commands.add(new AddThrowableErrorCommand(defaultSource(), t));
}
+ public void addError(Message message) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
public <T> BindCommand<T>.BindingBuilder bind(Key<T> key) {
BindCommand<T> bindCommand = new BindCommand<T>(defaultSource(), key);
commands.add(bindCommand);
diff --git a/src/com/google/inject/internal/Errors.java b/src/com/google/inject/internal/Errors.java
index ec97b23..5e82f4a 100644
--- a/src/com/google/inject/internal/Errors.java
+++ b/src/com/google/inject/internal/Errors.java
@@ -175,11 +175,13 @@
}
public Errors missingBindingAnnotation(Object source) {
- return addMessage("Please annotate with @BindingAnnotation. Bound at %s.", source);
+ return addMessage("Please annotate with @BindingAnnotation.%n"
+ + " Bound at %s.", source);
}
public Errors missingRuntimeRetention(Object source) {
- return addMessage("Please annotate with @Retention(RUNTIME). Bound at %s.", source);
+ return addMessage("Please annotate with @Retention(RUNTIME).%n"
+ + " Bound at %s.", source);
}
public Errors missingScopeAnnotation() {
@@ -204,6 +206,17 @@
return addMessage("No scope is bound to %s.", scopeAnnotation);
}
+ 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, 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);
+ }
+
private static final String CONSTRUCTOR_RULES =
"Classes must have either one (and only one) constructor "
+ "annotated with @Inject or a zero-argument constructor.";
@@ -465,6 +478,11 @@
return c.getName();
}
},
+ new Converter<Member>(Member.class) {
+ public String toString(Member member) {
+ return MoreTypes.canonicalize(member).toString();
+ }
+ },
new Converter<Key>(Key.class) {
public String toString(Key k) {
StringBuilder result = new StringBuilder();
diff --git a/src/com/google/inject/internal/Keys.java b/src/com/google/inject/internal/Keys.java
index 7f58ede..0b2beac 100644
--- a/src/com/google/inject/internal/Keys.java
+++ b/src/com/google/inject/internal/Keys.java
@@ -30,17 +30,29 @@
*/
public static Key<?> get(Type type, Member member, Annotation[] annotations, Errors errors)
throws ErrorsException {
+ Annotation found = findBindingAnnotation(errors, member, annotations);
+ errors.throwIfNecessary();
+ return found == null ? Key.get(type) : Key.get(type, found);
+ }
+
+ /**
+ * 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;
+
for (Annotation annotation : annotations) {
- if (annotation.annotationType().getAnnotation(BindingAnnotation.class) != null) {
- if (found == null) {
- found = annotation;
+ if (annotation.annotationType().isAnnotationPresent(BindingAnnotation.class)) {
+ if (found != null) {
+ errors.duplicateBindingAnnotations(member,
+ found.annotationType(), annotation.annotationType());
} else {
- throw errors.duplicateBindingAnnotations(
- member, found.annotationType(), annotation.annotationType()).toException();
+ found = annotation;
}
}
}
- return found == null ? Key.get(type) : Key.get(type, found);
+
+ return found;
}
}
diff --git a/src/com/google/inject/spi/SourceProviders.java b/src/com/google/inject/spi/SourceProviders.java
index e0e5784..1f566c4 100644
--- a/src/com/google/inject/spi/SourceProviders.java
+++ b/src/com/google/inject/spi/SourceProviders.java
@@ -86,8 +86,7 @@
* Sets the default source provider, runs the given command, and then
* restores the previous default source provider.
*/
- public static void withDefault(
- SourceProvider sourceProvider, Runnable r) {
+ private static void withDefault(SourceProvider sourceProvider, Runnable r) {
// We use a holder so we perform only 1 thread local access instead of 3.
SourceProvider[] holder = localSourceProvider.get();
SourceProvider previous = holder[0];
diff --git a/test/com/google/inject/BinderTest.java b/test/com/google/inject/BinderTest.java
index 7dcd208..2680c73 100644
--- a/test/com/google/inject/BinderTest.java
+++ b/test/com/google/inject/BinderTest.java
@@ -19,8 +19,12 @@
import static com.google.inject.Asserts.assertContains;
import static com.google.inject.Asserts.assertNotSerializable;
import com.google.inject.name.Names;
+import com.google.inject.util.Providers;
import java.io.IOException;
-import java.util.ArrayList;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
@@ -31,6 +35,23 @@
*/
public class BinderTest extends TestCase {
+ private ParameterizedType parameterizedWithVariable;
+ private ParameterizedType parameterizedWithWildcard;
+ private TypeVariable typeVariable;
+ private WildcardType wildcardType;
+
+ <T> void parameterizedWithVariable(List<T> typeWithVariables) {}
+ <T> void parameterizedWithWildcard(List<? extends Comparable> typeWithWildcard) {}
+
+ @Override protected void setUp() throws Exception {
+ parameterizedWithVariable = (ParameterizedType) getClass()
+ .getDeclaredMethod("parameterizedWithVariable", List.class).getGenericParameterTypes()[0];
+ parameterizedWithWildcard = (ParameterizedType) getClass()
+ .getDeclaredMethod("parameterizedWithWildcard", List.class).getGenericParameterTypes()[0];
+ typeVariable = (TypeVariable) parameterizedWithVariable.getActualTypeArguments()[0];
+ wildcardType = (WildcardType) parameterizedWithWildcard.getActualTypeArguments()[0];
+ }
+
Provider<Foo> fooProvider;
public void testProviderFromBinder() {
@@ -188,19 +209,29 @@
}
/** Test for issue 186 */
- public void testGuiceRefusesToCreateParameterizedClasses() {
- try {
- Guice.createInjector(new AbstractModule() {
- protected void configure() {
- bind(List.class).to(ArrayList.class);
- }
- });
- fail();
- } catch (CreationException expected) {
- Asserts.assertContains(expected.getMessage(),
- "Cannot instantiate Parameterized class java.util.List");
- }
+ public void testBindDisallowedTypes() throws NoSuchMethodException {
+ Type[] types = new Type[] {
+ parameterizedWithVariable,
+ parameterizedWithWildcard,
+ typeVariable,
+ wildcardType,
+ };
+ for (Type type : types) {
+ @SuppressWarnings("unchecked") final
+ Key<Object> key = (Key<Object>) Key.get(type);
+
+ try {
+ Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(key).toProvider(Providers.of(null));
+ }
+ });
+ fail("Guice should not allow bindings to " + type);
+ } catch (CreationException e) {
+ assertContains(e.getMessage(), "Cannot bind types that have type variables");
+ }
+ }
}
// public void testBindInterfaceWithoutImplementation() {
diff --git a/test/com/google/inject/ErrorMessagesTest.java b/test/com/google/inject/ErrorMessagesTest.java
index 6c415db..880846a 100644
--- a/test/com/google/inject/ErrorMessagesTest.java
+++ b/test/com/google/inject/ErrorMessagesTest.java
@@ -3,7 +3,6 @@
package com.google.inject;
import static com.google.inject.Asserts.assertContains;
-import com.google.inject.util.Providers;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
@@ -11,11 +10,6 @@
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
-import java.util.List;
import junit.framework.TestCase;
/**
@@ -25,23 +19,6 @@
*/
public class ErrorMessagesTest extends TestCase {
- private ParameterizedType parameterizedWithVariable;
- private ParameterizedType parameterizedWithWildcard;
- private TypeVariable typeVariable;
- private WildcardType wildcardType;
-
- <T> void parameterizedWithVariable(List<T> typeWithVariables) {}
- <T> void parameterizedWithWildcard(List<? extends Comparable> typeWithWildcard) {}
-
- @Override protected void setUp() throws Exception {
- parameterizedWithVariable = (ParameterizedType) getClass()
- .getDeclaredMethod("parameterizedWithVariable", List.class).getGenericParameterTypes()[0];
- parameterizedWithWildcard = (ParameterizedType) getClass()
- .getDeclaredMethod("parameterizedWithWildcard", List.class).getGenericParameterTypes()[0];
- typeVariable = (TypeVariable) parameterizedWithVariable.getActualTypeArguments()[0];
- wildcardType = (WildcardType) parameterizedWithWildcard.getActualTypeArguments()[0];
- }
-
private class InnerClass {}
public void testInjectInnerClass() throws Exception {
@@ -67,45 +44,6 @@
}
}
- public void testBindDisallowedTypes() throws NoSuchMethodException {
- Type[] types = new Type[] {
- parameterizedWithVariable,
- parameterizedWithWildcard,
- typeVariable,
- wildcardType,
- };
-
- for (Type type : types) {
- @SuppressWarnings("unchecked") final
- Key<Object> key = (Key<Object>) Key.get(type);
-
- try {
- Guice.createInjector(new AbstractModule() {
- protected void configure() {
- bind(key).toProvider(Providers.of(null));
- }
- });
- fail("Guice should not allow bindings to " + type);
- } catch (CreationException e) {
- assertContains(e.getMessage(), "Cannot bind types that have type variables");
- }
- }
- }
-
- public void testScopingAnnotationsOnAbstractTypes() {
- try {
- Guice.createInjector(new AbstractModule() {
- protected void configure() {
- bind(A.class).to(AImpl.class);
- }
- });
- fail();
- } catch (CreationException expected) {
- assertContains(expected.getMessage(),
- "Scope annotations on abstract types are not supported.");
- }
- }
-
/** Demonstrates issue 64, when setAccessible() fails. */
public void testGetUninjectableClass() {
try {
@@ -122,18 +60,15 @@
}
}
- @Singleton
- interface A {}
- class AImpl implements A {}
-
public void testBindingAnnotationsOnMethodsAndConstructors() {
try {
Guice.createInjector().getInstance(B.class);
fail();
} catch (ProvisionException expected) {
assertContains(expected.getMessage(),
- "Binding annotations on injected methods are not supported. "
- + "Annotate the parameter instead?");
+ "method " + B.class.getName() + ".injectMe() ",
+ "is annotated with @", Green.class.getName() + "(), ",
+ "but binding annotations should be applied to its parameters instead.");
}
try {
@@ -141,8 +76,9 @@
fail();
} catch (ProvisionException expected) {
assertContains(expected.getMessage(),
- "Binding annotations on injected constructors are not supported. "
- + "Annotate the parameter instead?");
+ "constructor " + C.class.getName() + "() ",
+ "is annotated with @", Green.class.getName() + "(), ",
+ "but binding annotations should be applied to its parameters instead.");
}
}
diff --git a/test/com/google/inject/ScopesTest.java b/test/com/google/inject/ScopesTest.java
index eaa5921..d364104 100644
--- a/test/com/google/inject/ScopesTest.java
+++ b/test/com/google/inject/ScopesTest.java
@@ -16,13 +16,14 @@
package com.google.inject;
+import com.google.common.collect.Maps;
+import static com.google.inject.Asserts.assertContains;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
@@ -106,6 +107,49 @@
injector.getInstance(AnnotatedSingleton.class));
}
+ public void testScopingAnnotationsOnAbstractTypes() {
+ try {
+ Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(A.class).to(AImpl.class);
+ }
+ });
+ fail();
+ } catch (CreationException expected) {
+ assertContains(expected.getMessage(),
+ "Error at " + A.class.getName() + ".class(ScopesTest.java:",
+ A.class.getName() + " is annotated with " + Singleton.class.getName(),
+ "but scope annotations are not supported for abstract types.");
+ }
+ }
+
+ @Singleton
+ interface A {}
+ static class AImpl implements A {}
+
+ public void testScopeUsedButNotBound() {
+ try {
+ Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(B.class).in(CustomScoped.class);
+ bind(C.class);
+ }
+ });
+ fail();
+ } catch (CreationException expected) {
+ assertContains(expected.getMessage(),
+ "1) Error at " + getClass().getName(), ".configure(ScopesTest.java:",
+ "No scope is bound to " + CustomScoped.class.getName(),
+ "2) Error at " + C.class.getName() + ".class",
+ "No scope is bound to " + CustomScoped.class.getName());
+ }
+ }
+
+ static class B {}
+
+ @CustomScoped
+ static class C {}
+
public void testSingletonsInProductionStage() {
Guice.createInjector(Stage.PRODUCTION, singletonsModule);
@@ -155,7 +199,7 @@
}
class RememberProviderScope implements Scope {
- final Map<Key<?>, Provider<?>> providers = new HashMap<Key<?>, Provider<?>>();
+ final Map<Key<?>, Provider<?>> providers = Maps.newHashMap();
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
providers.put(key, unscoped);
return unscoped;