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