add more tests for @CheckedProvides methods, fix bug exposed with @Exposed methods, cleanup class names & javadoc.
git-svn-id: https://google-guice.googlecode.com/svn/trunk@1427 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethod.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java
similarity index 94%
rename from extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethod.java
rename to extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java
index 0b013dc..de345c6 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethod.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java
@@ -40,7 +40,7 @@
*
* @author sameb@google.com (Sam Berlin)
*/
-class ThrowingProviderMethod<T> implements CheckedProvider<T>, HasDependencies {
+class CheckedProviderMethod<T> implements CheckedProvider<T>, HasDependencies {
private final Key<T> key;
private final Class<? extends Annotation> scopeAnnotation;
private final Object instance;
@@ -51,7 +51,7 @@
private final Class<? extends CheckedProvider> checkedProvider;
private final List<TypeLiteral<?>> exceptionTypes;
- ThrowingProviderMethod(
+ CheckedProviderMethod(
Key<T> key,
Method method,
Object instance,
@@ -73,15 +73,7 @@
method.setAccessible(true);
}
- public Key<T> getKey() {
- return key;
- }
-
- public Method getMethod() {
- return method;
- }
-
- public void configure(Binder binder) {
+ void configure(Binder binder) {
binder = binder.withSource(method);
SecondaryBinder<?> sbinder =
@@ -100,7 +92,7 @@
if (exposed) {
// the cast is safe 'cause the only binder we have implements PrivateBinder. If there's a
// misplaced @Exposed, calling this will add an error to the binder's error queue
- ((PrivateBinder) binder).expose(key);
+ ((PrivateBinder) binder).expose(sbinder.getKey());
}
// Validate the exceptions in the method match the exceptions
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethodsModule.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java
similarity index 87%
rename from extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethodsModule.java
rename to extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java
index cfb46a4..335bc48 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethodsModule.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java
@@ -42,11 +42,11 @@
*
* @author sameb@google.com (Sam Berlin)
*/
-final class ThrowingProviderMethodsModule implements Module {
+final class CheckedProviderMethodsModule implements Module {
private final Object delegate;
private final TypeLiteral<?> typeLiteral;
- private ThrowingProviderMethodsModule(Object delegate) {
+ private CheckedProviderMethodsModule(Object delegate) {
this.delegate = checkNotNull(delegate, "delegate");
this.typeLiteral = TypeLiteral.get(this.delegate.getClass());
}
@@ -56,21 +56,21 @@
*/
static Module forModule(Module module) {
// avoid infinite recursion, since installing a module always installs itself
- if (module instanceof ThrowingProviderMethodsModule) {
+ if (module instanceof CheckedProviderMethodsModule) {
return Modules.EMPTY_MODULE;
}
- return new ThrowingProviderMethodsModule(module);
+ return new CheckedProviderMethodsModule(module);
}
public synchronized void configure(Binder binder) {
- for (ThrowingProviderMethod<?> throwingProviderMethod : getProviderMethods(binder)) {
+ for (CheckedProviderMethod<?> throwingProviderMethod : getProviderMethods(binder)) {
throwingProviderMethod.configure(binder);
}
}
- List<ThrowingProviderMethod<?>> getProviderMethods(Binder binder) {
- List<ThrowingProviderMethod<?>> result = Lists.newArrayList();
+ List<CheckedProviderMethod<?>> getProviderMethods(Binder binder) {
+ List<CheckedProviderMethod<?>> result = Lists.newArrayList();
for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) {
for (Method method : c.getDeclaredMethods()) {
CheckedProvides checkedProvides =
@@ -83,7 +83,7 @@
return result;
}
- <T> ThrowingProviderMethod<T> createProviderMethod(Binder binder, final Method method,
+ <T> CheckedProviderMethod<T> createProviderMethod(Binder binder, final Method method,
Class<? extends CheckedProvider> throwingProvider) {
binder = binder.withSource(method);
Errors errors = new Errors(method);
@@ -119,7 +119,7 @@
binder.addError(message);
}
- return new ThrowingProviderMethod<T>(key, method, delegate, ImmutableSet.copyOf(dependencies),
+ return new CheckedProviderMethod<T>(key, method, delegate, ImmutableSet.copyOf(dependencies),
parameterProviders, scopeAnnotation, throwingProvider, exceptionTypes);
}
@@ -129,8 +129,8 @@
}
@Override public boolean equals(Object o) {
- return o instanceof ThrowingProviderMethodsModule
- && ((ThrowingProviderMethodsModule) o).delegate == delegate;
+ return o instanceof CheckedProviderMethodsModule
+ && ((CheckedProviderMethodsModule) o).delegate == delegate;
}
@Override public int hashCode() {
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvides.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvides.java
index df9feb2..983b6ec 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvides.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvides.java
@@ -23,9 +23,13 @@
import java.lang.annotation.Target;
/**
- * Annotates methods of a {@link Module} to create a provider method binding that can throw
- * exceptions. The method's return type is bound to it's returned value. Guice will pass
- * dependencies to the method as parameters.
+ * Annotates methods of a {@link Module} to create a {@link CheckedProvider}
+ * method binding that can throw exceptions. The method's return type is bound
+ * to a {@link CheckedProvider} that can be injected. Guice will pass
+ * dependencies to the method as parameters. Install {@literal @}CheckedProvides
+ * methods by using
+ * {@link ThrowingProviderBinder#forModule(com.google.inject.Module)} on the
+ * module where the methods are declared.
*
* @author sameb@google.com (Sam Berlin)
* @since 3.0
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
index 04fe743..0dbbdf1 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
@@ -89,7 +89,7 @@
* @since 3.0
*/
public static Module forModule(Module module) {
- return ThrowingProviderMethodsModule.forModule(module);
+ return CheckedProviderMethodsModule.forModule(module);
}
public <P extends CheckedProvider> SecondaryBinder<P>
@@ -100,11 +100,13 @@
public class SecondaryBinder<P extends CheckedProvider> {
private final Class<P> interfaceType;
private final Type valueType;
- private Class<? extends Annotation> annotationType;
- private Annotation annotation;
private final List<Class<? extends Throwable>> exceptionTypes;
private final boolean valid;
+ private Class<? extends Annotation> annotationType;
+ private Annotation annotation;
+ private Key<P> interfaceKey;
+
public SecondaryBinder(Class<P> interfaceType, Type valueType) {
this.interfaceType = checkNotNull(interfaceType, "interfaceType");
this.valueType = checkNotNull(valueType, "valueType");
@@ -114,12 +116,16 @@
} else {
valid = false;
this.exceptionTypes = ImmutableList.of();
- }
+ }
}
List<Class<? extends Throwable>> getExceptionTypes() {
return exceptionTypes;
}
+
+ Key<P> getKey() {
+ return interfaceKey;
+ }
public SecondaryBinder<P> annotatedWith(Class<? extends Annotation> annotationType) {
if (!(this.annotationType == null && this.annotation == null)) {
@@ -147,9 +153,9 @@
return to(Key.get(targetType));
}
- ScopedBindingBuilder toProviderMethod(ThrowingProviderMethod<?> target) {
- Key<ThrowingProviderMethod> targetKey =
- Key.get(ThrowingProviderMethod.class, UniqueAnnotations.create());
+ ScopedBindingBuilder toProviderMethod(CheckedProviderMethod<?> target) {
+ Key<CheckedProviderMethod> targetKey =
+ Key.get(CheckedProviderMethod.class, UniqueAnnotations.create());
binder.bind(targetKey).toInstance(target);
return toInternal(targetKey);
@@ -162,13 +168,13 @@
private ScopedBindingBuilder toInternal(final Key<? extends CheckedProvider> targetKey) {
final Key<Result> resultKey = Key.get(Result.class, UniqueAnnotations.create());
- final Key<P> key = createKey();
final Provider<Result> resultProvider = binder.getProvider(resultKey);
final Provider<? extends CheckedProvider> targetProvider = binder.getProvider(targetKey);
+ interfaceKey = createKey();
// don't bother binding the proxy type if this is in an invalid state.
if(valid) {
- binder.bind(key).toProvider(new ProviderWithDependencies<P>() {
+ binder.bind(interfaceKey).toProvider(new ProviderWithDependencies<P>() {
private final P instance = interfaceType.cast(Proxy.newProxyInstance(
interfaceType.getClassLoader(), new Class<?>[] { interfaceType },
new InvocationHandler() {
@@ -218,7 +224,6 @@
* Returns the exception type declared to be thrown by the get method of
* {@code interfaceType}.
*/
- @SuppressWarnings({"unchecked"})
private List<Class<? extends Throwable>> getExceptionType(Class<P> interfaceType) {
try {
Method getMethod = interfaceType.getMethod("get");
@@ -379,7 +384,6 @@
}
}
- @SuppressWarnings("unused")
- private static long serialVersionUID = 0L;
+ private static final long serialVersionUID = 0L;
}
}
diff --git a/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderMethodsModuleTest.java b/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderMethodsModuleTest.java
new file mode 100644
index 0000000..4f5a485
--- /dev/null
+++ b/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderMethodsModuleTest.java
@@ -0,0 +1,181 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+package com.google.inject.throwingproviders;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.BindingAnnotation;
+import com.google.inject.Exposed;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.PrivateModule;
+import com.google.inject.Provides;
+import com.google.inject.TypeLiteral;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
+
+import junit.framework.TestCase;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.BindException;
+import java.rmi.RemoteException;
+
+/**
+ * Test methods for {@link CheckedProviderMethodsModule}.
+ */
+public class CheckedProviderMethodsModuleTest extends TestCase {
+
+ private final TypeLiteral<RpcProvider<String>> rpcProviderOfString
+ = new TypeLiteral<RpcProvider<String>>() { };
+ private final TypeLiteral<RpcProvider<Integer>> rpcProviderOfInteger
+ = new TypeLiteral<RpcProvider<Integer>>() { };
+ private final TypeLiteral<RpcProvider<Long>> rpcProviderOfLong
+ = new TypeLiteral<RpcProvider<Long>>() { };
+ private final TypeLiteral<RpcProvider<Float>> rpcProviderOfFloat
+ = new TypeLiteral<RpcProvider<Float>>() { };
+ private final TypeLiteral<RpcProvider<Pair<Double, String>>> rpcProviderOfPair
+ = new TypeLiteral<RpcProvider<Pair<Double, String>>>() { };
+
+ private final TestScope testScope = new TestScope();
+
+ interface RpcProvider<T> extends CheckedProvider<T> {
+ T get() throws RemoteException, BindException;
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @BindingAnnotation
+ @interface TestAnnotation {
+ }
+
+ class TestModule extends AbstractModule {
+
+ private int nextIntToReturn = 100;
+
+ @Override
+ protected void configure() {
+ bindScope(TestScope.Scoped.class, testScope);
+ install(ThrowingProviderBinder.forModule(this));
+ install(new TestPrivateModule());
+ }
+
+ @CheckedProvides(RpcProvider.class)
+ String getSomeStringFromServer() {
+ return "Works";
+ }
+
+ @CheckedProvides(RpcProvider.class) @TestScope.Scoped
+ int getSomeIntegerFromServer() {
+ return nextIntToReturn;
+ }
+
+ @CheckedProvides(RpcProvider.class) @TestAnnotation
+ long getSomeLongFromServer() {
+ return 0xffL;
+ }
+
+ @Provides
+ double getSomeDouble() {
+ return 2.0d;
+ }
+
+ @CheckedProvides(RpcProvider.class)
+ Pair<Double, String> getSomePair(Double input) {
+ return new Pair<Double, String>(input * 2, "foo");
+ }
+
+ @CheckedProvides(RpcProvider.class)
+ float getFloat() throws BindException {
+ throw new BindException("foo");
+ }
+
+ void setNextIntToReturn(int next) {
+ nextIntToReturn = next;
+ }
+ }
+
+ class TestPrivateModule extends PrivateModule {
+
+ @Override
+ protected void configure() {
+ install(ThrowingProviderBinder.forModule(this));
+ }
+
+ @CheckedProvides(RpcProvider.class) @Named("fruit") @Exposed
+ String provideApples() {
+ return "apple";
+ }
+ }
+
+
+ public void testNoAnnotationNoScope() throws BindException, RemoteException {
+ Injector injector = Guice.createInjector(new TestModule());
+ RpcProvider<String> provider = injector
+ .getInstance(Key.get(rpcProviderOfString));
+ assertEquals("Works", provider.get());
+ }
+
+ public void testWithScope() throws BindException, RemoteException {
+ TestModule testModule = new TestModule();
+ Injector injector = Guice.createInjector(testModule);
+ RpcProvider<Integer> provider = injector
+ .getInstance(Key.get(rpcProviderOfInteger));
+
+ assertEquals((Integer)100, provider.get());
+ testModule.setNextIntToReturn(120);
+ assertEquals((Integer)100, provider.get());
+ testScope.beginNewScope();
+ assertEquals((Integer)120, provider.get());
+ }
+
+ public void testWithAnnotation() throws BindException, RemoteException {
+ TestModule testModule = new TestModule();
+ Injector injector = Guice.createInjector(testModule);
+ RpcProvider<Long> provider = injector
+ .getInstance(Key.get(rpcProviderOfLong, TestAnnotation.class));
+ assertEquals((Long)0xffL, provider.get());
+ }
+
+ public void testWithInjectedParameters() throws BindException, RemoteException {
+ TestModule testModule = new TestModule();
+ Injector injector = Guice.createInjector(testModule);
+ RpcProvider<Pair<Double, String>> provider = injector
+ .getInstance(Key.get(rpcProviderOfPair));
+ Pair<Double, String> pair = provider.get();
+ assertEquals(pair.first, 4.0d);
+ }
+
+ public void testWithThrownException() {
+ TestModule testModule = new TestModule();
+ Injector injector = Guice.createInjector(testModule);
+ RpcProvider<Float> provider = injector
+ .getInstance(Key.get(rpcProviderOfFloat));
+ try {
+ provider.get();
+ fail();
+ } catch (RemoteException e) {
+ fail();
+ } catch (BindException e) {
+ // good
+ }
+ }
+
+ public void testExposedMethod() throws BindException, RemoteException {
+ TestModule testModule = new TestModule();
+ Injector injector = Guice.createInjector(testModule);
+ RpcProvider<String> provider = injector
+ .getInstance(Key.get(rpcProviderOfString, Names.named("fruit")));
+ assertEquals("apple", provider.get());
+
+ }
+
+ private static class Pair<A, B> {
+ A first;
+ B second;
+
+ Pair(A a, B b) {
+ this.first= a;
+ this.second = b;
+ }
+ }
+}
\ No newline at end of file