Add a new method to ThrowingProviderBinder: providing(Class) or providing(TypeLiteral).
This instructs ThrowingProviderBinder to create a proxy implementation of the CheckedProvider interface and delegate it to the constructor of the class in question. As a bonus, the class it constructs fully participates in Guice AOP.
This is a binary-safe change, but a compile-unsafe change if classes directly kept a reference to SecondaryBinder. SecondaryBinder now has two generic types (as opposed to one).
Revision created by MOE tool push_codebase.
MOE_MIGRATION=4307
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvideUtils.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvideUtils.java
new file mode 100644
index 0000000..17885c1
--- /dev/null
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvideUtils.java
@@ -0,0 +1,48 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+package com.google.inject.throwingproviders;
+
+import com.google.inject.Binder;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Utilities for the throwing provider module.
+ *
+ * @author sameb@google.com (Sam Berlin)
+ */
+class CheckedProvideUtils {
+
+ private CheckedProvideUtils() {}
+
+ /** Adds errors to the binder if the exceptions aren't valid. */
+ static void validateExceptions(Binder binder,
+ Iterable<TypeLiteral<?>> actualExceptionTypes,
+ Iterable<Class<? extends Throwable>> expectedExceptionTypes,
+ Class<? extends CheckedProvider> checkedProvider) {
+ // Validate the exceptions in the method match the exceptions
+ // in the CheckedProvider.
+ for (TypeLiteral<?> exType : actualExceptionTypes) {
+ Class<?> exActual = exType.getRawType();
+ // Ignore runtime exceptions & errors.
+ if (RuntimeException.class.isAssignableFrom(exActual)
+ || Error.class.isAssignableFrom(exActual)) {
+ continue;
+ }
+
+ boolean notAssignable = true;
+ for (Class<? extends Throwable> exExpected : expectedExceptionTypes) {
+ if (exExpected.isAssignableFrom(exActual)) {
+ notAssignable = false;
+ break;
+ }
+ }
+ if (notAssignable) {
+ binder.addError(
+ "%s is not compatible with the exceptions (%s) declared in "
+ + "the CheckedProvider interface (%s)",
+ exActual, expectedExceptionTypes, checkedProvider);
+ }
+ }
+ }
+
+}
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java
index 0de744a..8d975ee 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java
@@ -76,9 +76,9 @@
void configure(Binder binder) {
binder = binder.withSource(method);
- SecondaryBinder<?> sbinder =
+ SecondaryBinder<?, ?> sbinder =
ThrowingProviderBinder.create(binder)
- .bind(checkedProvider, key.getTypeLiteral().getType());
+ .bind(checkedProvider, key.getTypeLiteral());
if(key.getAnnotation() != null) {
sbinder = sbinder.annotatedWith(key.getAnnotation());
} else if(key.getAnnotationType() != null) {
@@ -94,29 +94,9 @@
// misplaced @Exposed, calling this will add an error to the binder's error queue
((PrivateBinder) binder).expose(sbinder.getKey());
}
-
- // Validate the exceptions in the method match the exceptions
- // in the CheckedProvider.
- for(TypeLiteral<?> exType : exceptionTypes) {
- Class<?> exActual = exType.getRawType();
- // Ignore runtime exceptions & errors.
- if(RuntimeException.class.isAssignableFrom(exActual) || Error.class.isAssignableFrom(exActual)) {
- continue;
- }
-
- boolean notAssignable = true;
- for(Class<? extends Throwable> exExpected : sbinder.getExceptionTypes()) {
- if (exExpected.isAssignableFrom(exActual)) {
- notAssignable = false;
- break;
- }
- }
- if(notAssignable) {
- binder.addError(
- "%s is not compatible with the exceptions (%s) declared in the CheckedProvider interface (%s)",
- exActual, sbinder.getExceptionTypes(), checkedProvider);
- }
- }
+
+ CheckedProvideUtils.validateExceptions(
+ binder, exceptionTypes, sbinder.getExceptionTypes(), checkedProvider);
}
public T get() throws Exception {
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java
index 523d020..6c81dab 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java
@@ -75,8 +75,7 @@
List<CheckedProviderMethod<?>> result = Lists.newArrayList();
for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) {
for (Method method : c.getDeclaredMethods()) {
- CheckedProvides checkedProvides =
- (CheckedProvides)method.getAnnotation(CheckedProvides.class);
+ CheckedProvides checkedProvides = method.getAnnotation(CheckedProvides.class);
if(checkedProvides != null) {
result.add(createProviderMethod(binder, method, checkedProvides.value()));
}
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderWithDependencies.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderWithDependencies.java
new file mode 100644
index 0000000..4b87f40
--- /dev/null
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderWithDependencies.java
@@ -0,0 +1,16 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+package com.google.inject.throwingproviders;
+
+import com.google.inject.spi.HasDependencies;
+import com.google.inject.throwingproviders.ThrowingProviderBinder.SecondaryBinder;
+
+/**
+ * A checked provider with dependencies, so {@link HasDependencies} can be implemented
+ * when using the {@link SecondaryBinder#using} methods.
+ *
+ * @author sameb@google.com (Sam Berlin)
+ */
+interface CheckedProviderWithDependencies<T> extends CheckedProvider<T>, HasDependencies {
+
+}
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
index 41e68b0..8131b2d 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
@@ -22,18 +22,24 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.inject.Binder;
+import com.google.inject.ConfigurationException;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
+import com.google.inject.ProvisionException;
+import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.ScopedBindingBuilder;
import com.google.inject.internal.UniqueAnnotations;
import com.google.inject.spi.Dependency;
+import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.Message;
import com.google.inject.spi.ProviderWithDependencies;
import com.google.inject.util.Types;
import java.io.Serializable;
import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
@@ -66,9 +72,17 @@
* }
* }
* </code></pre>
+ * You also can declare that a CheckedProvider construct
+ * a particular class whose constructor throws an exception:
+ * <pre><code>ThrowingProviderBinder.create(binder())
+ * .bind(RemoteProvider.class, Customer.class)
+ * .providing(CustomerImpl.class)
+ * .in(RequestScope.class);
+ * </code></pre>
*
* @author jmourits@google.com (Jerome Mourits)
* @author jessewilson@google.com (Jesse Wilson)
+ * @author sameb@google.com (Sam Berlin)
*/
public class ThrowingProviderBinder {
@@ -92,13 +106,27 @@
public static Module forModule(Module module) {
return CheckedProviderMethodsModule.forModule(module);
}
-
- public <P extends CheckedProvider> SecondaryBinder<P>
- bind(final Class<P> interfaceType, final Type valueType) {
- return new SecondaryBinder<P>(interfaceType, valueType);
+
+ /**
+ * @deprecated Use {@link #bind(Class, Class)} or {@link #bind(Class, TypeLiteral)} instead.
+ */
+ @Deprecated
+ public <P extends CheckedProvider> SecondaryBinder<P, ?>
+ bind(Class<P> interfaceType, Type clazz) {
+ return new SecondaryBinder<P, Object>(interfaceType, clazz);
}
- public class SecondaryBinder<P extends CheckedProvider> {
+ public <P extends CheckedProvider, T> SecondaryBinder<P, T>
+ bind(Class<P> interfaceType, Class<T> clazz) {
+ return new SecondaryBinder<P, T>(interfaceType, clazz);
+ }
+
+ public <P extends CheckedProvider, T> SecondaryBinder<P, T>
+ bind(Class<P> interfaceType, TypeLiteral<T> typeLiteral) {
+ return new SecondaryBinder<P, T>(interfaceType, typeLiteral.getType());
+ }
+
+ public class SecondaryBinder<P extends CheckedProvider, T> {
private final Class<P> interfaceType;
private final Type valueType;
private final List<Class<? extends Throwable>> exceptionTypes;
@@ -128,17 +156,17 @@
return interfaceKey;
}
- public SecondaryBinder<P> annotatedWith(Class<? extends Annotation> annotationType) {
+ public SecondaryBinder<P, T> annotatedWith(Class<? extends Annotation> annotationType) {
if (!(this.annotationType == null && this.annotation == null)) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Cannot set annotation twice");
}
this.annotationType = annotationType;
return this;
}
- public SecondaryBinder<P> annotatedWith(Annotation annotation) {
+ public SecondaryBinder<P, T> annotatedWith(Annotation annotation) {
if (!(this.annotationType == null && this.annotation == null)) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Cannot set annotation twice");
}
this.annotation = annotation;
return this;
@@ -149,16 +177,79 @@
binder.bind(targetKey).toInstance(target);
return to(targetKey);
}
-
+
public ScopedBindingBuilder to(Class<? extends P> targetType) {
return to(Key.get(targetType));
}
+ public ScopedBindingBuilder providing(Class<? extends T> cxtorClass) {
+ return providing(TypeLiteral.get(cxtorClass));
+ }
+
+ @SuppressWarnings("unchecked") // safe because this is the cxtor of the literal
+ public ScopedBindingBuilder providing(TypeLiteral<? extends T> cxtorLiteral) {
+ // Find the injection point of the class we want to create & get its constructor.
+ InjectionPoint ip = null;
+ try {
+ ip = InjectionPoint.forConstructorOf(cxtorLiteral);
+ } catch (ConfigurationException ce) {
+ for (Message message : ce.getErrorMessages()) {
+ binder.addError(message);
+ }
+ }
+
+ final Provider<T> typeProvider;
+ final Key<? extends T> typeKey;
+ // If we found an injection point, then bind the cxtor to a unique key
+ if (ip != null) {
+ Constructor<? extends T> cxtor = (Constructor<? extends T>) ip.getMember();
+ // Validate the exceptions are consistent with the CheckedProvider interface.
+ CheckedProvideUtils.validateExceptions(
+ binder, cxtorLiteral.getExceptionTypes(cxtor), exceptionTypes, interfaceType);
+
+ typeKey = Key.get(cxtorLiteral, UniqueAnnotations.create());
+ binder.bind(typeKey).toConstructor((Constructor) cxtor).in(Scopes.NO_SCOPE);
+ typeProvider = binder.getProvider((Key<T>) typeKey);
+ } else {
+ // never used, but need it assigned.
+ typeProvider = null;
+ typeKey = null;
+ }
+
+ // Create a CheckedProvider that calls our cxtor
+ CheckedProvider<T> checkedProvider = new CheckedProviderWithDependencies<T>() {
+ @Override
+ public T get() throws Exception {
+ try {
+ return typeProvider.get();
+ } catch (ProvisionException pe) {
+ // Rethrow the provision cause as the actual exception
+ if (pe.getCause() instanceof Exception) {
+ throw (Exception) pe.getCause();
+ } else if (pe.getCause() instanceof Error) {
+ throw (Error) pe.getCause();
+ } else {
+ throw new AssertionError(pe.getCause()); // Impossible!
+ }
+ }
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return ImmutableSet.<Dependency<?>>of(Dependency.get(typeKey));
+ }
+ };
+
+ Key<CheckedProvider> targetKey = Key.get(CheckedProvider.class, UniqueAnnotations.create());
+ binder.bind(targetKey).toInstance(checkedProvider);
+ return toInternal(targetKey);
+ }
+
ScopedBindingBuilder toProviderMethod(CheckedProviderMethod<?> target) {
Key<CheckedProviderMethod> targetKey =
- Key.get(CheckedProviderMethod.class, UniqueAnnotations.create());
+ Key.get(CheckedProviderMethod.class, UniqueAnnotations.create());
binder.bind(targetKey).toInstance(target);
-
+
return toInternal(targetKey);
}
diff --git a/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java b/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
index 3d58791..62ab1e9 100644
--- a/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
+++ b/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
@@ -42,6 +42,7 @@
import java.net.BindException;
import java.rmi.AccessException;
import java.rmi.RemoteException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -50,34 +51,68 @@
/**
* @author jmourits@google.com (Jerome Mourits)
* @author jessewilson@google.com (Jesse Wilson)
+ * @author sameb@google.com (Sam Berlin)
*/
public class CheckedProviderTest extends TestCase {
+
+ private static final Function<Dependency<?>, Key<?>> DEPENDENCY_TO_KEY =
+ new Function<Dependency<?>, Key<?>>() {
+ public Key<?> apply(Dependency<?> from) {
+ return from.getKey();
+ }
+ };
- private final TypeLiteral<RemoteProvider<String>> remoteProviderOfString
- = new TypeLiteral<RemoteProvider<String>>() { };
- private final MockRemoteProvider<String> mockRemoteProvider = new MockRemoteProvider<String>();
+ private final TypeLiteral<RemoteProvider<Foo>> remoteProviderOfFoo
+ = new TypeLiteral<RemoteProvider<Foo>>() { };
+ private final MockRemoteProvider<Foo> mockRemoteProvider = new MockRemoteProvider<Foo>();
private final TestScope testScope = new TestScope();
- private Injector bindInjector = Guice.createInjector(new AbstractModule() {
- protected void configure() {
- ThrowingProviderBinder.create(binder())
- .bind(RemoteProvider.class, String.class)
- .to(mockRemoteProvider)
- .in(testScope);
- }
- });
- private Injector providesInjector = Guice.createInjector(new AbstractModule() {
- protected void configure() {
- install(ThrowingProviderBinder.forModule(this));
- bindScope(TestScope.Scoped.class, testScope);
- }
+
+ private Injector bindInjector;
+ private Injector providesInjector;
+ private Injector cxtorInjector;
+
+ @Override
+ protected void setUp() throws Exception {
+ MockFoo.nextToThrow = null;
+ MockFoo.nextToReturn = null;
+ AnotherMockFoo.nextToThrow = null;
+ AnotherMockFoo.nextToReturn = null;
- @SuppressWarnings("unused")
- @CheckedProvides(RemoteProvider.class)
- @TestScope.Scoped
- String throwOrGet() throws RemoteException, BindException {
- return mockRemoteProvider.get();
- }
- });
+ bindInjector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .to(mockRemoteProvider)
+ .in(testScope);
+ }
+ });
+
+ providesInjector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ install(ThrowingProviderBinder.forModule(this));
+ bindScope(TestScope.Scoped.class, testScope);
+ }
+
+ @SuppressWarnings("unused")
+ @CheckedProvides(RemoteProvider.class)
+ @TestScope.Scoped
+ Foo throwOrGet() throws RemoteException, BindException {
+ return mockRemoteProvider.get();
+ }
+ });
+
+ cxtorInjector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .providing(MockFoo.class)
+ .in(testScope);
+ }
+ });
+ }
public void testExceptionsThrown_Bind() throws Exception {
tExceptionsThrown(bindInjector);
@@ -87,11 +122,16 @@
tExceptionsThrown(providesInjector);
}
+ public void testExceptionsThrown_Cxtor() throws Exception {
+ tExceptionsThrown(cxtorInjector);
+ }
+
private void tExceptionsThrown(Injector injector) throws Exception {
- RemoteProvider<String> remoteProvider =
- injector.getInstance(Key.get(remoteProviderOfString));
+ RemoteProvider<Foo> remoteProvider =
+ injector.getInstance(Key.get(remoteProviderOfFoo));
mockRemoteProvider.throwOnNextGet(new BindException("kaboom!"));
+ MockFoo.nextToThrow = new BindException("kaboom!");
try {
remoteProvider.get();
fail();
@@ -109,17 +149,28 @@
}
private void tValuesScoped(Injector injector) throws Exception {
- RemoteProvider<String> remoteProvider =
- injector.getInstance(Key.get(remoteProviderOfString));
+ RemoteProvider<Foo> remoteProvider =
+ injector.getInstance(Key.get(remoteProviderOfFoo));
- mockRemoteProvider.setNextToReturn("A");
- assertEquals("A", remoteProvider.get());
+ mockRemoteProvider.setNextToReturn(new SimpleFoo("A"));
+ assertEquals("A", remoteProvider.get().s());
- mockRemoteProvider.setNextToReturn("B");
- assertEquals("A", remoteProvider.get());
+ mockRemoteProvider.setNextToReturn(new SimpleFoo("B"));
+ assertEquals("A", remoteProvider.get().s());
testScope.beginNewScope();
- assertEquals("B", remoteProvider.get());
+ assertEquals("B", remoteProvider.get().s());
+ }
+
+ public void testValuesScoped_Cxtor() throws Exception {
+ RemoteProvider<Foo> remoteProvider =
+ cxtorInjector.getInstance(Key.get(remoteProviderOfFoo));
+
+ Foo retrieved = remoteProvider.get();
+ assertSame(retrieved, remoteProvider.get()); // same, not in new scope.
+
+ testScope.beginNewScope();
+ assertNotSame(retrieved, remoteProvider.get()); // different, new scope.
}
public void testExceptionsScoped_Bind() throws Exception {
@@ -130,11 +181,16 @@
tExceptionsScoped(providesInjector);
}
+ public void testExceptionScopes_Cxtor() throws Exception {
+ tExceptionsScoped(cxtorInjector);
+ }
+
private void tExceptionsScoped(Injector injector) throws Exception {
- RemoteProvider<String> remoteProvider =
- injector.getInstance(Key.get(remoteProviderOfString));
+ RemoteProvider<Foo> remoteProvider =
+ injector.getInstance(Key.get(remoteProviderOfFoo));
mockRemoteProvider.throwOnNextGet(new RemoteException("A"));
+ MockFoo.nextToThrow = new RemoteException("A");
try {
remoteProvider.get();
fail();
@@ -143,6 +199,7 @@
}
mockRemoteProvider.throwOnNextGet(new RemoteException("B"));
+ MockFoo.nextToThrow = new RemoteException("B");
try {
remoteProvider.get();
fail();
@@ -152,17 +209,18 @@
}
public void testAnnotations_Bind() throws Exception {
- final MockRemoteProvider<String> mockRemoteProviderA = new MockRemoteProvider<String>();
- final MockRemoteProvider<String> mockRemoteProviderB = new MockRemoteProvider<String>();
+ final MockRemoteProvider<Foo> mockRemoteProviderA = new MockRemoteProvider<Foo>();
+ final MockRemoteProvider<Foo> mockRemoteProviderB = new MockRemoteProvider<Foo>();
bindInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
ThrowingProviderBinder.create(binder())
- .bind(RemoteProvider.class, String.class)
+ .bind(RemoteProvider.class, Foo.class)
.annotatedWith(Names.named("a"))
.to(mockRemoteProviderA);
ThrowingProviderBinder.create(binder())
- .bind(RemoteProvider.class, String.class)
+ .bind(RemoteProvider.class, Foo.class)
.to(mockRemoteProviderB);
}
});
@@ -170,9 +228,10 @@
}
public void testAnnotations_Provides() throws Exception {
- final MockRemoteProvider<String> mockRemoteProviderA = new MockRemoteProvider<String>();
- final MockRemoteProvider<String> mockRemoteProviderB = new MockRemoteProvider<String>();
+ final MockRemoteProvider<Foo> mockRemoteProviderA = new MockRemoteProvider<Foo>();
+ final MockRemoteProvider<Foo> mockRemoteProviderB = new MockRemoteProvider<Foo>();
providesInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -180,28 +239,51 @@
@SuppressWarnings("unused")
@CheckedProvides(RemoteProvider.class)
@Named("a")
- String throwOrGet() throws RemoteException, BindException {
+ Foo throwOrGet() throws RemoteException, BindException {
return mockRemoteProviderA.get();
}
@SuppressWarnings("unused")
@CheckedProvides(RemoteProvider.class)
- String throwOrGet2() throws RemoteException, BindException {
+ Foo throwOrGet2() throws RemoteException, BindException {
return mockRemoteProviderB.get();
}
});
tAnnotations(providesInjector, mockRemoteProviderA, mockRemoteProviderB);
}
- private void tAnnotations(Injector injector, MockRemoteProvider<String> mockA,
- MockRemoteProvider<String> mockB) throws Exception {
- mockA.setNextToReturn("A");
- mockB.setNextToReturn("B");
+ private void tAnnotations(Injector injector, MockRemoteProvider<Foo> mockA,
+ MockRemoteProvider<Foo> mockB) throws Exception {
+ mockA.setNextToReturn(new SimpleFoo("A"));
+ mockB.setNextToReturn(new SimpleFoo("B"));
assertEquals("A",
- injector.getInstance(Key.get(remoteProviderOfString, Names.named("a"))).get());
+ injector.getInstance(Key.get(remoteProviderOfFoo, Names.named("a"))).get().s());
assertEquals("B",
- injector.getInstance(Key.get(remoteProviderOfString)).get());
+ injector.getInstance(Key.get(remoteProviderOfFoo)).get().s());
+ }
+
+ public void testAnnotations_Cxtor() throws Exception {
+ cxtorInjector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .annotatedWith(Names.named("a"))
+ .providing(MockFoo.class);
+
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .providing(AnotherMockFoo.class);
+ }
+ });
+ MockFoo.nextToReturn = "A";
+ AnotherMockFoo.nextToReturn = "B";
+ assertEquals("A",
+ cxtorInjector.getInstance(Key.get(remoteProviderOfFoo, Names.named("a"))).get().s());
+
+ assertEquals("B",
+ cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)).get().s());
}
public void testUndeclaredExceptions_Bind() throws Exception {
@@ -211,11 +293,16 @@
public void testUndeclaredExceptions_Provides() throws Exception {
tUndeclaredExceptions(providesInjector);
}
+
+ public void testUndeclaredExceptions_Cxtor() throws Exception {
+ tUndeclaredExceptions(cxtorInjector);
+ }
private void tUndeclaredExceptions(Injector injector) throws Exception {
- RemoteProvider<String> remoteProvider =
- injector.getInstance(Key.get(remoteProviderOfString));
+ RemoteProvider<Foo> remoteProvider =
+ injector.getInstance(Key.get(remoteProviderOfFoo));
mockRemoteProvider.throwOnNextGet(new IndexOutOfBoundsException("A"));
+ MockFoo.nextToThrow = new IndexOutOfBoundsException("A");
try {
remoteProvider.get();
fail();
@@ -225,6 +312,7 @@
// undeclared exceptions shouldn't be scoped
mockRemoteProvider.throwOnNextGet(new IndexOutOfBoundsException("B"));
+ MockFoo.nextToThrow = new IndexOutOfBoundsException("B");
try {
remoteProvider.get();
fail();
@@ -235,28 +323,30 @@
public void testThrowingProviderSubclassing() throws Exception {
final SubMockRemoteProvider aProvider = new SubMockRemoteProvider();
- aProvider.setNextToReturn("A");
+ aProvider.setNextToReturn(new SimpleFoo("A"));
bindInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
ThrowingProviderBinder.create(binder())
- .bind(RemoteProvider.class, String.class)
+ .bind(RemoteProvider.class, Foo.class)
.to(aProvider);
}
});
assertEquals("A",
- bindInjector.getInstance(Key.get(remoteProviderOfString)).get());
+ bindInjector.getInstance(Key.get(remoteProviderOfFoo)).get().s());
}
- static class SubMockRemoteProvider extends MockRemoteProvider<String> { }
+ static class SubMockRemoteProvider extends MockRemoteProvider<Foo> { }
public void testBindingToNonInterfaceType_Bind() throws Exception {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
ThrowingProviderBinder.create(binder())
- .bind(MockRemoteProvider.class, String.class)
+ .bind(MockRemoteProvider.class, Foo.class)
.to(mockRemoteProvider);
}
});
@@ -270,13 +360,14 @@
public void testBindingToNonInterfaceType_Provides() throws Exception {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@SuppressWarnings("unused")
@CheckedProvides(MockRemoteProvider.class)
- String foo() {
+ Foo foo() {
return null;
}
});
@@ -290,9 +381,10 @@
public void testBindingToSubSubInterface_Bind() throws Exception {
try {
bindInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
ThrowingProviderBinder.create(binder())
- .bind(SubRemoteProvider.class, String.class);
+ .bind(SubRemoteProvider.class, Foo.class);
}
});
fail();
@@ -305,13 +397,14 @@
public void testBindingToSubSubInterface_Provides() throws Exception {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@SuppressWarnings("unused")
@CheckedProvides(SubRemoteProvider.class)
- String foo() {
+ Foo foo() {
return null;
}
});
@@ -327,9 +420,10 @@
public void testBindingToInterfaceWithExtraMethod_Bind() throws Exception {
try {
bindInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
ThrowingProviderBinder.create(binder())
- .bind(RemoteProviderWithExtraMethod.class, String.class);
+ .bind(RemoteProviderWithExtraMethod.class, Foo.class);
}
});
fail();
@@ -343,13 +437,14 @@
public void testBindingToInterfaceWithExtraMethod_Provides() throws Exception {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@SuppressWarnings("unused")
@CheckedProvides(RemoteProviderWithExtraMethod.class)
- String foo() {
+ Foo foo() {
return null;
}
});
@@ -363,19 +458,20 @@
public void testDependencies_Bind() {
bindInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
bind(String.class).toInstance("Foo");
bind(Integer.class).toInstance(5);
bind(Double.class).toInstance(5d);
bind(Long.class).toInstance(5L);
ThrowingProviderBinder.create(binder())
- .bind(RemoteProvider.class, String.class)
+ .bind(RemoteProvider.class, Foo.class)
.to(DependentRemoteProvider.class);
}
});
HasDependencies hasDependencies =
- (HasDependencies)bindInjector.getBinding(Key.get(remoteProviderOfString));
+ (HasDependencies)bindInjector.getBinding(Key.get(remoteProviderOfFoo));
hasDependencies =
(HasDependencies)bindInjector.getBinding(
Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey());
@@ -385,18 +481,14 @@
// And make sure DependentRemoteProvider has the proper dependencies.
hasDependencies = (HasDependencies)bindInjector.getBinding(DependentRemoteProvider.class);
Set<Key<?>> dependencyKeys = ImmutableSet.copyOf(
- Iterables.transform(hasDependencies.getDependencies(),
- new Function<Dependency<?>, Key<?>>() {
- public Key<?> apply(Dependency<?> from) {
- return from.getKey();
- }
- }));
+ Iterables.transform(hasDependencies.getDependencies(), DEPENDENCY_TO_KEY));
assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class),
Key.get(Long.class), Key.get(Double.class)), dependencyKeys);
}
public void testDependencies_Provides() {
providesInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
bind(String.class).toInstance("Foo");
bind(Integer.class).toInstance(5);
@@ -407,27 +499,60 @@
@SuppressWarnings("unused")
@CheckedProvides(RemoteProvider.class)
- String foo(String s, Integer i, Double d, Long l) {
+ Foo foo(String s, Integer i, Double d, Long l) {
return null;
}
});
HasDependencies hasDependencies =
- (HasDependencies)providesInjector.getBinding(Key.get(remoteProviderOfString));
+ (HasDependencies) providesInjector.getBinding(Key.get(remoteProviderOfFoo));
// RemoteProvider<String> is dependent on the provider method..
- hasDependencies =
- (HasDependencies)providesInjector.getBinding(
- Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey());
+ hasDependencies = (HasDependencies) providesInjector.getBinding(
+ Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey());
// And the provider method has our real dependencies..
hasDependencies = (HasDependencies)providesInjector.getBinding(
Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey());
Set<Key<?>> dependencyKeys = ImmutableSet.copyOf(
- Iterables.transform(hasDependencies.getDependencies(),
- new Function<Dependency<?>, Key<?>>() {
- public Key<?> apply(Dependency<?> from) {
- return from.getKey();
- }
- }));
+ Iterables.transform(hasDependencies.getDependencies(), DEPENDENCY_TO_KEY));
+ assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class),
+ Key.get(Long.class), Key.get(Double.class)), dependencyKeys);
+ }
+
+ public void testDependencies_Cxtor() {
+ cxtorInjector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ bind(String.class).toInstance("Foo");
+ bind(Integer.class).toInstance(5);
+ bind(Double.class).toInstance(5d);
+ bind(Long.class).toInstance(5L);
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .providing(DependentMockFoo.class);
+ }
+ });
+
+ Key<?> key = Key.get(remoteProviderOfFoo);
+
+ // RemoteProvider<String> is dependent on Result.
+ HasDependencies hasDependencies = (HasDependencies) cxtorInjector.getBinding(key);
+ key = Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey();
+ assertEquals(Result.class, key.getTypeLiteral().getRawType());
+
+ // Result is dependent on the fake CheckedProvider impl
+ hasDependencies = (HasDependencies) cxtorInjector.getBinding(key);
+ key = Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey();
+ assertTrue(CheckedProvider.class.isAssignableFrom(key.getTypeLiteral().getRawType()));
+
+ // And the CheckedProvider is dependent on DependentMockFoo...
+ hasDependencies = (HasDependencies) cxtorInjector.getBinding(key);
+ key = Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey();
+ assertEquals(DependentMockFoo.class, key.getTypeLiteral().getRawType());
+
+ // And DependentMockFoo is dependent on the goods.
+ hasDependencies = (HasDependencies) cxtorInjector.getBinding(key);
+ Set<Key<?>> dependencyKeys = ImmutableSet.copyOf(
+ Iterables.transform(hasDependencies.getDependencies(), DEPENDENCY_TO_KEY));
assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class),
Key.get(Long.class), Key.get(Double.class)), dependencyKeys);
}
@@ -440,6 +565,20 @@
public T get() throws RemoteException, BindException;
}
+ static class DependentMockFoo implements Foo {
+ @Inject double foo;
+
+ @Inject public DependentMockFoo(String foo, int bar) {
+ }
+
+ @Inject void initialize(long foo) {}
+
+ @Override
+ public String s() {
+ return null;
+ }
+ }
+
static class DependentRemoteProvider<T> implements RemoteProvider<T> {
@Inject double foo;
@@ -448,11 +587,91 @@
@Inject void initialize(long foo) {}
- public T get() throws RemoteException {
+ public T get() {
return null;
}
}
+ interface Foo {
+ String s();
+ }
+
+ static class SimpleFoo implements Foo {
+ private String s;
+
+ SimpleFoo(String s) {
+ this.s = s;
+ }
+
+ @Override
+ public String s() {
+ return s;
+ }
+
+ @Override
+ public String toString() {
+ return s;
+ }
+ }
+
+ static class MockFoo implements Foo {
+ static Exception nextToThrow;
+ static String nextToReturn;
+
+ MockFoo() throws RemoteException, BindException {
+ if (nextToThrow instanceof RemoteException) {
+ throw (RemoteException) nextToThrow;
+ } else if (nextToThrow instanceof BindException) {
+ throw (BindException) nextToThrow;
+ } else if (nextToThrow instanceof RuntimeException) {
+ throw (RuntimeException) nextToThrow;
+ } else if (nextToThrow == null) {
+ // Do nothing, return this.
+ } else {
+ throw new AssertionError("nextToThrow must be a runtime or remote exception");
+ }
+ }
+
+ @Override
+ public String s() {
+ return nextToReturn;
+ }
+
+ @Override
+ public String toString() {
+ return nextToReturn;
+ }
+ }
+
+ static class AnotherMockFoo implements Foo {
+ static Exception nextToThrow;
+ static String nextToReturn;
+
+ AnotherMockFoo() throws RemoteException, BindException {
+ if (nextToThrow instanceof RemoteException) {
+ throw (RemoteException) nextToThrow;
+ } else if (nextToThrow instanceof BindException) {
+ throw (BindException) nextToThrow;
+ } else if (nextToThrow instanceof RuntimeException) {
+ throw (RuntimeException) nextToThrow;
+ } else if (nextToThrow == null) {
+ // Do nothing, return this.
+ } else {
+ throw new AssertionError("nextToThrow must be a runtime or remote exception");
+ }
+ }
+
+ @Override
+ public String s() {
+ return nextToReturn;
+ }
+
+ @Override
+ public String toString() {
+ return nextToReturn;
+ }
+ }
+
static class MockRemoteProvider<T> implements RemoteProvider<T> {
Exception nextToThrow;
T nextToReturn;
@@ -482,11 +701,12 @@
public void testBindingToInterfaceWithBoundValueType_Bind() throws RemoteException {
bindInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
ThrowingProviderBinder.create(binder())
.bind(StringRemoteProvider.class, String.class)
.to(new StringRemoteProvider() {
- public String get() throws RemoteException {
+ public String get() {
return "A";
}
});
@@ -498,6 +718,7 @@
public void testBindingToInterfaceWithBoundValueType_Provides() throws RemoteException {
providesInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -516,13 +737,34 @@
String get() throws RemoteException;
}
+ @SuppressWarnings("deprecation")
public void testBindingToInterfaceWithGeneric_Bind() throws Exception {
bindInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
ThrowingProviderBinder.create(binder())
.bind(RemoteProvider.class, new TypeLiteral<List<String>>() { }.getType())
.to(new RemoteProvider<List<String>>() {
- public List<String> get() throws RemoteException {
+ public List<String> get() {
+ return Arrays.asList("A", "B");
+ }
+ });
+ }
+ });
+
+ Key<RemoteProvider<List<String>>> key
+ = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { });
+ assertEquals(Arrays.asList("A", "B"), bindInjector.getInstance(key).get());
+ }
+
+ public void testBindingToInterfaceWithGeneric_BindUsingTypeLiteral() throws Exception {
+ bindInjector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, new TypeLiteral<List<String>>() {})
+ .to(new RemoteProvider<List<String>>() {
+ public List<String> get() {
return Arrays.asList("A", "B");
}
});
@@ -536,6 +778,7 @@
public void testBindingToInterfaceWithGeneric_Provides() throws Exception {
providesInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -552,9 +795,25 @@
assertEquals(Arrays.asList("A", "B"), providesInjector.getInstance(key).get());
}
+ public void testBindingToInterfaceWithGeneric_Cxtor() throws Exception {
+ cxtorInjector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, new TypeLiteral<List<String>>() {})
+ .providing(new TypeLiteral<ArrayList<String>>() {});
+ }
+ });
+
+ Key<RemoteProvider<List<String>>> key
+ = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { });
+ assertEquals(Arrays.asList(), cxtorInjector.getInstance(key).get());
+ }
+
public void testProviderMethodWithWrongException() {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -577,21 +836,53 @@
}
}
+ public void testCxtorWithWrongException() {
+ try {
+ Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .providing(WrongExceptionFoo.class);
+ }
+ });
+ fail();
+ } catch (CreationException ce) {
+ assertEquals(InterruptedException.class.getName()
+ + " is not compatible with the exceptions (["
+ + RemoteException.class + ", " + BindException.class
+ + "]) declared in the CheckedProvider interface ("
+ + RemoteProvider.class.getName()
+ + ")",
+ Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
+ }
+ }
+
+ static class WrongExceptionFoo implements Foo {
+ @SuppressWarnings("unused")
+ public WrongExceptionFoo() throws InterruptedException {
+ }
+
+ @Override
+ public String s() { return null; }
+ }
+
public void testProviderMethodWithSubclassOfExceptionIsOk() throws Exception {
providesInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@SuppressWarnings("unused")
@CheckedProvides(RemoteProvider.class)
- String foo() throws AccessException {
+ Foo foo() throws AccessException {
throw new AccessException("boo!");
}
});
- RemoteProvider<String> remoteProvider =
- providesInjector.getInstance(Key.get(remoteProviderOfString));
+ RemoteProvider<Foo> remoteProvider =
+ providesInjector.getInstance(Key.get(remoteProviderOfFoo));
try {
remoteProvider.get();
@@ -602,16 +893,48 @@
}
}
- public void testProviderMethodWithSuperclassFails() {
+ public void testCxtorWithSubclassOfExceptionIsOk() throws Exception {
+ cxtorInjector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .providing(SubclassExceptionFoo.class);
+ }
+ });
+
+ RemoteProvider<Foo> remoteProvider =
+ cxtorInjector.getInstance(Key.get(remoteProviderOfFoo));
+
+ try {
+ remoteProvider.get();
+ fail();
+ } catch (RemoteException expected) {
+ assertTrue(expected instanceof AccessException);
+ assertEquals("boo!", expected.getMessage());
+ }
+ }
+
+ static class SubclassExceptionFoo implements Foo {
+ public SubclassExceptionFoo() throws AccessException {
+ throw new AccessException("boo!");
+ }
+
+ @Override
+ public String s() { return null; }
+ }
+
+ public void testProviderMethodWithSuperclassExceptionFails() {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@SuppressWarnings("unused")
@CheckedProvides(RemoteProvider.class)
- String foo() throws IOException {
+ Foo foo() throws IOException {
return null;
}
});
@@ -627,21 +950,53 @@
}
}
+ public void testCxtorWithSuperclassExceptionFails() {
+ try {
+ Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .providing(SuperclassExceptionFoo.class);
+ }
+ });
+ fail();
+ } catch (CreationException ce) {
+ assertEquals(IOException.class.getName()
+ + " is not compatible with the exceptions (["
+ + RemoteException.class + ", " + BindException.class
+ + "]) declared in the CheckedProvider interface ("
+ + RemoteProvider.class.getName()
+ + ")",
+ Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
+ }
+ }
+
+ static class SuperclassExceptionFoo implements Foo {
+ @SuppressWarnings("unused")
+ public SuperclassExceptionFoo() throws IOException {
+ }
+
+ @Override
+ public String s() { return null; }
+ }
+
public void testProviderMethodWithRuntimeExceptionsIsOk() throws Exception {
providesInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@SuppressWarnings("unused")
@CheckedProvides(RemoteProvider.class)
- String foo() throws RuntimeException {
+ Foo foo() throws RuntimeException {
throw new RuntimeException("boo!");
}
});
- RemoteProvider<String> remoteProvider =
- providesInjector.getInstance(Key.get(remoteProviderOfString));
+ RemoteProvider<Foo> remoteProvider =
+ providesInjector.getInstance(Key.get(remoteProviderOfFoo));
try {
remoteProvider.get();
@@ -651,11 +1006,42 @@
}
}
+ public void testCxtorWithRuntimeExceptionsIsOk() throws Exception {
+ cxtorInjector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .providing(RuntimeExceptionFoo.class);
+ }
+ });
+
+ RemoteProvider<Foo> remoteProvider =
+ cxtorInjector.getInstance(Key.get(remoteProviderOfFoo));
+
+ try {
+ remoteProvider.get();
+ fail();
+ } catch (RuntimeException expected) {
+ assertEquals("boo!", expected.getCause().getMessage());
+ }
+ }
+
+ static class RuntimeExceptionFoo implements Foo {
+ public RuntimeExceptionFoo() throws RuntimeException {
+ throw new RuntimeException("boo!");
+ }
+
+ @Override
+ public String s() { return null; }
+ }
+
private static class SubBindException extends BindException {}
public void testProviderMethodWithManyExceptions() {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -690,9 +1076,58 @@
}
}
+ public void testCxtorWithManyExceptions() {
+ try {
+ Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .providing(ManyExceptionFoo.class);
+ }
+ });
+ fail();
+ } catch (CreationException ce) {
+ // The only two that should fail are Interrupted & TooManyListeners.. the rest are OK.
+ List<Message> errors = ImmutableList.copyOf(ce.getErrorMessages());
+ assertEquals(InterruptedException.class.getName()
+ + " is not compatible with the exceptions (["
+ + RemoteException.class + ", " + BindException.class
+ + "]) declared in the CheckedProvider interface ("
+ + RemoteProvider.class.getName()
+ + ")",
+ errors.get(0).getMessage());
+ assertEquals(TooManyListenersException.class.getName()
+ + " is not compatible with the exceptions (["
+ + RemoteException.class + ", " + BindException.class
+ + "]) declared in the CheckedProvider interface ("
+ + RemoteProvider.class.getName()
+ + ")",
+ errors.get(1).getMessage());
+ assertEquals(2, errors.size());
+ }
+ }
+
+ static class ManyExceptionFoo implements Foo {
+ @SuppressWarnings("unused")
+ public ManyExceptionFoo()
+ throws InterruptedException,
+ RuntimeException,
+ RemoteException,
+ AccessException,
+ TooManyListenersException,
+ BindException,
+ SubBindException {
+ }
+
+ @Override
+ public String s() { return null; }
+ }
+
public void testMoreTypeParameters() {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -713,6 +1148,7 @@
public void testWrongThrowingProviderType() {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -735,6 +1171,7 @@
public void testOneMethodThatIsntGet() {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -756,6 +1193,7 @@
public void testManyMethods() {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -777,11 +1215,12 @@
public void testIncorrectPredefinedType_Bind() {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
ThrowingProviderBinder.create(binder())
.bind(StringRemoteProvider.class, Integer.class)
.to(new StringRemoteProvider() {
- public String get() throws RemoteException {
+ public String get() {
return "A";
}
});
@@ -798,6 +1237,7 @@
public void testIncorrectPredefinedType_Provides() {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -851,6 +1291,7 @@
public void testEarlyBindingError() {
try {
Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
ThrowingProviderBinder.create(binder())
.bind(StringRemoteProvider.class, String.class)
@@ -875,4 +1316,59 @@
return null;
}
}
+
+ public void testNoInjectionPointForUsing() {
+ try {
+ Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .providing(InvalidFoo.class);
+ }
+ });
+ fail();
+ } catch (CreationException ce) {
+ assertEquals("Could not find a suitable constructor in " + InvalidFoo.class.getName()
+ + ". Classes must have either one (and only one) constructor annotated with "
+ + "@Inject or a zero-argument constructor that is not private.",
+ Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
+ }
+ }
+
+ static class InvalidFoo implements Foo {
+ public InvalidFoo(String dep) {
+ }
+
+ @Override public String s() { return null; }
+ }
+
+ public void testUsingDoesntClashWithBindingsOfSameType() throws Exception {
+ cxtorInjector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ ThrowingProviderBinder.create(binder())
+ .bind(RemoteProvider.class, Foo.class)
+ .providing(MockFoo.class);
+ bind(Foo.class).to(MockFoo.class);
+ bind(MockFoo.class).to(SubMockFoo.class);
+ }
+ });
+
+ RemoteProvider<Foo> remoteProvider =
+ cxtorInjector.getInstance(Key.get(remoteProviderOfFoo));
+ Foo providerGot = remoteProvider.get();
+ Foo fooGot = cxtorInjector.getInstance(Foo.class);
+ Foo mockGot = cxtorInjector.getInstance(MockFoo.class);
+
+ assertEquals(MockFoo.class, providerGot.getClass());
+ assertEquals(SubMockFoo.class, fooGot.getClass());
+ assertEquals(SubMockFoo.class, mockGot.getClass());
+ }
+
+ static class SubMockFoo extends MockFoo {
+ public SubMockFoo() throws RemoteException, BindException {
+ }
+
+ }
}