Revision: 8557c775d526
Author: Sam Berlin <[email protected]>
Date: Thu Mar 1 11:21:26 2012
Log: 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
http://code.google.com/p/google-guice/source/detail?r=8557c775d526
Added:
/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvideUtils.java
/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderWithDependencies.java
Modified:
/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java
/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java
/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
=======================================
--- /dev/null
+++
/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvideUtils.java
Thu Mar 1 11:21:26 2012
@@ -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 [email protected] (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);
+ }
+ }
+ }
+
+}
=======================================
--- /dev/null
+++
/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderWithDependencies.java
Thu Mar 1 11:21:26 2012
@@ -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 [email protected] (Sam Berlin)
+ */
+interface CheckedProviderWithDependencies<T> extends CheckedProvider<T>,
HasDependencies {
+
+}
=======================================
---
/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java
Thu Jul 7 17:34:16 2011
+++
/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java
Thu Mar 1 11:21:26 2012
@@ -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 {
=======================================
---
/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java
Thu Jul 7 17:34:16 2011
+++
/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java
Thu Mar 1 11:21:26 2012
@@ -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()));
}
=======================================
---
/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
Thu Jul 7 17:34:16 2011
+++
/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
Thu Mar 1 11:21:26 2012
@@ -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;
@@ -65,10 +71,18 @@
* return creator.getCustomerOrThrow();
* }
* }
+ * </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 [email protected] (Jerome Mourits)
* @author [email protected] (Jesse Wilson)
+ * @author [email protected] (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 <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> {
+ 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);
}
=======================================
---
/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
Thu Jul 7 17:34:16 2011
+++
/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
Thu Mar 1 11:21:26 2012
@@ -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 [email protected] (Jerome Mourits)
* @author [email protected] (Jesse Wilson)
+ * @author [email protected] (Sam Berlin)
*/
public class CheckedProviderTest extends TestCase {
-
- private final TypeLiteral<RemoteProvider<String>> remoteProviderOfString
- = new TypeLiteral<RemoteProvider<String>>() { };
- private final MockRemoteProvider<String> mockRemoteProvider = new
MockRemoteProvider<String>();
+
+ 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<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);
- }
-
- @SuppressWarnings("unused")
- @CheckedProvides(RemoteProvider.class)
- @TestScope.Scoped
- String throwOrGet() throws RemoteException, BindException {
- return mockRemoteProvider.get();
- }
- });
+
+ 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;
+
+ 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);
@@ -86,12 +121,17 @@
public void testExceptionsThrown_Provides() throws Exception {
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));
-
- mockRemoteProvider.setNextToReturn("A");
- assertEquals("A", remoteProvider.get());
-
- mockRemoteProvider.setNextToReturn("B");
- assertEquals("A", remoteProvider.get());
+ RemoteProvider<Foo> remoteProvider =
+ injector.getInstance(Key.get(remoteProviderOfFoo));
+
+ mockRemoteProvider.setNextToReturn(new SimpleFoo("A"));
+ assertEquals("A", remoteProvider.get().s());
+
+ 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 {
@@ -129,12 +180,17 @@
public void testExceptionsScoped_Provides() throws Exception {
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,30 +499,63 @@
@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);
+ }
interface RemoteProviderWithExtraMethod<T> extends CheckedProvider<T> {
T get(T defaultValue) throws RemoteException, BindException;
@@ -439,6 +564,20 @@
interface RemoteProvider<T> extends CheckedProvider<T> {
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,10 +587,90 @@
@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;
@@ -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,19 +737,40 @@
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");
+ }
+ });
+ }
+ });
+
Key<RemoteProvider<List<String>>> key
= Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { });
assertEquals(Arrays.asList("A", "B"),
bindInjector.getInstance(key).get());
@@ -536,6 +778,7 @@
public void testBindingToInterfaceWithGeneric_Provides() throws
Exception {
providesInjector = Guice.createInjector(new AbstractModule() {
+ @Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
}
@@ -551,10 +794,26 @@
= Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { });
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));
}
@@ -576,22 +835,54 @@
Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
}
}
+
+ 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;
}
});
@@ -626,22 +949,54 @@
Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
}
}
+
+ 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();
@@ -650,12 +1005,43 @@
assertEquals("boo!", expected.getCause().getMessage());
}
}
+
+ 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));
}
@@ -689,10 +1075,59 @@
assertEquals(2, errors.size());
}
}
+
+ 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 {
***The diff for this file has been truncated for email.***
--
You received this message because you are subscribed to the Google Groups
"google-guice-dev" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice-dev?hl=en.