deprecated ThrowingProvider in favor of CheckedProvider, which lets you specify more than one exception type.  remove tentative @ThrowingProvides in favor of @CheckedProvides.  add tests.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@1373 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvider.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvider.java
new file mode 100644
index 0000000..7cd22a6
--- /dev/null
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvider.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.throwingproviders;
+
+/**
+ * Alternative to the Guice {@link com.google.inject.Provider} that throws
+ * a checked Exception. Users may not inject {@code T} directly.
+ *
+ * <p>This interface must be extended to use application-specific exception types.
+ * Such subinterfaces may not define new methods, but may narrow the exception type.
+ * <pre>
+ * public interface RemoteProvider&lt;T&gt; extends CheckedProvider&lt;T&gt; { 
+ *   T get() throws CustomExceptionOne, CustomExceptionTwo;
+ * }
+ * </pre>
+ *
+ * <p>When this type is bound using {@link ThrowingProviderBinder}, the value returned
+ * or exception thrown by {@link #get} will be scoped. As a consequence, {@link #get}
+ * will invoked at most once within each scope.
+ */
+public interface CheckedProvider<T> {
+  T get() throws Exception;
+}
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProvides.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvides.java
similarity index 87%
rename from extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProvides.java
rename to extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvides.java
index d680202..df9feb2 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProvides.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvides.java
@@ -31,11 +31,11 @@
  * @since 3.0
  */
 @Documented @Target(METHOD) @Retention(RUNTIME)
-public @interface ThrowingProvides {
+public @interface CheckedProvides {
   
   /**
-   * The interface that provides this value, a subinterface of ThrowingProvider.
+   * The interface that provides this value, a subinterface of {@link CheckedProvider}.
    */
-  Class<? extends ThrowingProvider> value();
+  Class<? extends CheckedProvider> value();
   
 }
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProvider.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProvider.java
index a4189cf..4ecab4d 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProvider.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProvider.java
@@ -32,7 +32,9 @@
  *
  * @author jmourits@google.com (Jerome Mourits)
  * @author jessewilson@google.com (Jesse Wilson)
+ * @deprecated use {@link CheckedProvider} instead.
  */
-public interface ThrowingProvider<T,E extends Exception> {
+@Deprecated
+public interface ThrowingProvider<T,E extends Exception> extends CheckedProvider<T> {
   T get() throws E;
 }
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
index 9b62c88..04fe743 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
@@ -24,10 +24,14 @@
 import com.google.inject.binder.ScopedBindingBuilder;
 import static com.google.inject.internal.util.Preconditions.checkNotNull;
 import com.google.inject.internal.UniqueAnnotations;
+import com.google.inject.internal.util.ImmutableList;
 import com.google.inject.internal.util.ImmutableSet;
+import com.google.inject.internal.util.Lists;
 import com.google.inject.spi.Dependency;
 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.InvocationHandler;
 import java.lang.reflect.Method;
@@ -36,10 +40,11 @@
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Set;
 
 /**
- * <p>Builds a binding for a {@link ThrowingProvider}.
+ * <p>Builds a binding for a {@link CheckedProvider}.
  * 
  * <p>You can use a fluent API and custom providers:
  * <pre><code>ThrowingProviderBinder.create(binder())
@@ -53,7 +58,7 @@
  *     ThrowingProviderBinder.install(this, binder());
  *   }
  *   
- *   {@literal @}ThrowingProvides(RemoteProvider.class)
+ *   {@literal @}CheckedProvides(RemoteProvider.class)
  *   {@literal @}RequestScope
  *   Customer provideCustomer(FlakyCustomerCreator creator) throws RemoteException {
  *     return creator.getCustomerOrThrow();
@@ -79,41 +84,41 @@
   }
   
   /**
-   * Installs {@literal @}{@link ThrowingProvides} methods.
+   * Returns a module that installs {@literal @}{@link CheckedProvides} methods.
    * 
    * @since 3.0
    */
-  public static void install(Module module, Binder binder) {
-    binder.install(ThrowingProviderMethodsModule.forModule(module));
+  public static Module forModule(Module module) {
+    return ThrowingProviderMethodsModule.forModule(module);
   }
 
-  public <P extends ThrowingProvider> SecondaryBinder<P> 
+  public <P extends CheckedProvider> SecondaryBinder<P> 
       bind(final Class<P> interfaceType, final Type valueType) {
     return new SecondaryBinder<P>(interfaceType, valueType);
   }
 
-  public class SecondaryBinder<P extends ThrowingProvider> {
+  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 Class<? extends Exception> exceptionType;
+    private final List<Class<? extends Throwable>> exceptionTypes;
     private final boolean valid;
 
     public SecondaryBinder(Class<P> interfaceType, Type valueType) {
       this.interfaceType = checkNotNull(interfaceType, "interfaceType");
       this.valueType = checkNotNull(valueType, "valueType");
       if(checkInterface()) {
-        this.exceptionType = getExceptionType(interfaceType);
+        this.exceptionTypes = getExceptionType(interfaceType);
         valid = true;
       } else {
         valid = false;
-        this.exceptionType = null;
+        this.exceptionTypes = ImmutableList.of();
       }
     }
     
-    Class<? extends Exception> getExceptionType() {
-      return exceptionType;
+    List<Class<? extends Throwable>> getExceptionTypes() {
+      return exceptionTypes;
     }
 
     public SecondaryBinder<P> annotatedWith(Class<? extends Annotation> annotationType) {
@@ -155,11 +160,11 @@
       return toInternal(targetKey);
     }
     
-    private ScopedBindingBuilder toInternal(final Key<? extends ThrowingProvider> targetKey) {
+    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 ThrowingProvider> targetProvider = binder.getProvider(targetKey);
+      final Provider<? extends CheckedProvider> targetProvider = binder.getProvider(targetKey);
 
       // don't bother binding the proxy type if this is in an invalid state.
       if(valid) {
@@ -188,9 +193,13 @@
           try {
             return Result.forValue(targetProvider.get().get());
           } catch (Exception e) {
-            if (exceptionType.isInstance(e)) {
-              return Result.forException(e);
-            } else if (e instanceof RuntimeException) {
+            for(Class<? extends Throwable> exceptionType : exceptionTypes) {
+              if (exceptionType.isInstance(e)) {
+                return Result.forException(e);
+              }
+            }
+            
+            if (e instanceof RuntimeException) {
               throw (RuntimeException) e;
             } else {
               // this should never happen
@@ -210,10 +219,21 @@
      * {@code interfaceType}.
      */
     @SuppressWarnings({"unchecked"})
-    private Class<? extends Exception> getExceptionType(Class<P> interfaceType) {
-      ParameterizedType genericUnreliableProvider
-          = (ParameterizedType) interfaceType.getGenericInterfaces()[0];
-      return (Class<? extends Exception>) genericUnreliableProvider.getActualTypeArguments()[1];
+    private List<Class<? extends Throwable>> getExceptionType(Class<P> interfaceType) {
+      try {
+        Method getMethod = interfaceType.getMethod("get");
+        List<TypeLiteral<?>> exceptionLiterals =
+            TypeLiteral.get(interfaceType).getExceptionTypes(getMethod);
+        List<Class<? extends Throwable>> results = Lists.newArrayList();
+        for (TypeLiteral<?> exLiteral : exceptionLiterals) {
+          results.add(exLiteral.getRawType().asSubclass(Throwable.class));
+        }
+        return results;
+      } catch (SecurityException e) {
+        throw new IllegalStateException("Not allowed to inspect exception types", e);
+      } catch (NoSuchMethodException e) {
+        throw new IllegalStateException("No 'get'method available", e);
+      }
     }
 
     private boolean checkInterface() {
@@ -222,14 +242,18 @@
         return false;
       }
       if(!checkArgument(interfaceType.getGenericInterfaces().length == 1,
-          "%s must extend ThrowingProvider (and only ThrowingProvider)",
+          "%s must extend CheckedProvider (and only CheckedProvider)",
           interfaceType)) {
         return false;
       }
-      if(!checkArgument(interfaceType.getInterfaces()[0] == ThrowingProvider.class,
-          "%s must extend ThrowingProvider (and only ThrowingProvider)",
-          interfaceType)) {
-        return false;
+      
+      boolean tpMode = interfaceType.getInterfaces()[0] == ThrowingProvider.class;      
+      if(!tpMode) {
+        if(!checkArgument(interfaceType.getInterfaces()[0] == CheckedProvider.class,
+            "%s must extend CheckedProvider (and only CheckedProvider)",
+            interfaceType)) {
+          return false;
+        }
       }
 
       // Ensure that T is parameterized and unconstrained.
@@ -239,12 +263,12 @@
         String returnTypeName = interfaceType.getTypeParameters()[0].getName();
         Type returnType = genericThrowingProvider.getActualTypeArguments()[0];
         if(!checkArgument(returnType instanceof TypeVariable,
-            "%s does not properly extend ThrowingProvider, the first type parameter of ThrowingProvider (%s) is not a generic type",
+            "%s does not properly extend CheckedProvider, the first type parameter of CheckedProvider (%s) is not a generic type",
             interfaceType, returnType)) {
           return false;
         }
         if(!checkArgument(returnTypeName.equals(((TypeVariable) returnType).getName()),
-            "The generic type (%s) of %s does not match the generic type of ThrowingProvider (%s)",
+            "The generic type (%s) of %s does not match the generic type of CheckedProvider (%s)",
             returnTypeName, interfaceType, ((TypeVariable)returnType).getName())) {
           return false;
         }
@@ -261,11 +285,13 @@
         }
       }
 
-      Type exceptionType = genericThrowingProvider.getActualTypeArguments()[1];
-      if(!checkArgument(exceptionType instanceof Class,
-          "%s has the wrong Exception generic type (%s) when extending ThrowingProvider",
-          interfaceType, exceptionType)) {
-        return false;
+      if(tpMode) { // only validate exception in ThrowingProvider mode.
+        Type exceptionType = genericThrowingProvider.getActualTypeArguments()[1];
+        if(!checkArgument(exceptionType instanceof Class,
+            "%s has the wrong Exception generic type (%s) when extending CheckedProvider",
+            interfaceType, exceptionType)) {
+          return false;
+        }
       }
       
       if (interfaceType.getDeclaredMethods().length == 1) {
@@ -326,9 +352,9 @@
 
   /**
    * Represents the returned value from a call to {@link
-   * ThrowingProvider#get()}. This is the value that will be scoped by Guice.
+   * CheckedProvider#get()}. This is the value that will be scoped by Guice.
    */
-  private static class Result {
+  static class Result implements Serializable {
     private final Object value;
     private final Exception exception;
 
@@ -352,5 +378,8 @@
         return value;
       }
     }
+    
+    @SuppressWarnings("unused")
+    private static long serialVersionUID = 0L;
   }
 }
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethod.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethod.java
index 0f20949..0b013dc 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethod.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethod.java
@@ -40,7 +40,7 @@
  *
  * @author sameb@google.com (Sam Berlin)
  */
-class ThrowingProviderMethod<T> implements ThrowingProvider<T, Exception>, HasDependencies {
+class ThrowingProviderMethod<T> implements CheckedProvider<T>, HasDependencies {
   private final Key<T> key;
   private final Class<? extends Annotation> scopeAnnotation;
   private final Object instance;
@@ -48,7 +48,7 @@
   private final ImmutableSet<Dependency<?>> dependencies;
   private final List<Provider<?>> parameterProviders;
   private final boolean exposed;
-  private final Class<? extends ThrowingProvider> throwingProvider;
+  private final Class<? extends CheckedProvider> checkedProvider;
   private final List<TypeLiteral<?>> exceptionTypes;
 
   ThrowingProviderMethod(
@@ -58,7 +58,7 @@
       ImmutableSet<Dependency<?>> dependencies,
       List<Provider<?>> parameterProviders,
       Class<? extends Annotation> scopeAnnotation,
-      Class<? extends ThrowingProvider> throwingProvider,
+      Class<? extends CheckedProvider> checkedProvider,
       List<TypeLiteral<?>> exceptionTypes) {
     this.key = key;
     this.scopeAnnotation = scopeAnnotation;
@@ -67,7 +67,7 @@
     this.method = method;
     this.parameterProviders = parameterProviders;
     this.exposed = method.isAnnotationPresent(Exposed.class);
-    this.throwingProvider = throwingProvider;
+    this.checkedProvider = checkedProvider;
     this.exceptionTypes = exceptionTypes;
 
     method.setAccessible(true);
@@ -86,7 +86,7 @@
 
     SecondaryBinder<?> sbinder = 
       ThrowingProviderBinder.create(binder)
-        .bind(throwingProvider, key.getTypeLiteral().getType());
+        .bind(checkedProvider, key.getTypeLiteral().getType());
     if(key.getAnnotation() != null) {
       sbinder = sbinder.annotatedWith(key.getAnnotation());
     } else if(key.getAnnotationType() != null) {
@@ -104,20 +104,26 @@
     }
 
     // Validate the exceptions in the method match the exceptions
-    // in the ThrowingProvider.
+    // in the CheckedProvider.
     for(TypeLiteral<?> exType : exceptionTypes) {
-      // Ignore runtime exceptions.
-      if(RuntimeException.class.isAssignableFrom(exType.getRawType())) {
+      Class<?> exActual = exType.getRawType();
+      // Ignore runtime exceptions & errors.
+      if(RuntimeException.class.isAssignableFrom(exActual) || Error.class.isAssignableFrom(exActual)) {
         continue;
       }
       
-      if(sbinder.getExceptionType() != null) {
-        if (!sbinder.getExceptionType().isAssignableFrom(exType.getRawType())) {
-          binder.addError(
-              "%s is not compatible with the exception (%s) declared in the ThrowingProvider interface (%s)",
-              exType.getRawType(), sbinder.getExceptionType(), throwingProvider);
+      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);
+      }
     }
   }
 
@@ -151,6 +157,6 @@
   }
 
   @Override public String toString() {
-    return "@ThrowingProvides " + StackTraceElements.forMember(method).toString();
+    return "@CheckedProvides " + StackTraceElements.forMember(method).toString();
   }
 }
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethodsModule.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethodsModule.java
index 528782a..cfb46a4 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethodsModule.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethodsModule.java
@@ -37,7 +37,7 @@
 import java.util.logging.Logger;
 
 /**
- * Creates bindings to methods annotated with {@literal @}{@link ThrowingProvides}. Use the scope
+ * Creates bindings to methods annotated with {@literal @}{@link CheckedProvides}. Use the scope
  * and binding annotations on the provider method to configure the binding.
  * 
  * @author sameb@google.com (Sam Berlin)
@@ -73,10 +73,10 @@
     List<ThrowingProviderMethod<?>> result = Lists.newArrayList();
     for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) {
       for (Method method : c.getDeclaredMethods()) {
-        ThrowingProvides throwingProvides =
-          (ThrowingProvides)method.getAnnotation(ThrowingProvides.class);
-        if(throwingProvides != null) {
-          result.add(createProviderMethod(binder, method, throwingProvides.value()));
+        CheckedProvides checkedProvides =
+          (CheckedProvides)method.getAnnotation(CheckedProvides.class);
+        if(checkedProvides != null) {
+          result.add(createProviderMethod(binder, method, checkedProvides.value()));
         }
       }
     }
@@ -84,7 +84,7 @@
   }
 
   <T> ThrowingProviderMethod<T> createProviderMethod(Binder binder, final Method method,
-      Class<? extends ThrowingProvider> throwingProvider) {
+      Class<? extends CheckedProvider> throwingProvider) {
     binder = binder.withSource(method);
     Errors errors = new Errors(method);
 
diff --git a/extensions/throwingproviders/test/com/google/inject/throwingproviders/ThrowingProviderBinderTest.java b/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
similarity index 74%
copy from extensions/throwingproviders/test/com/google/inject/throwingproviders/ThrowingProviderBinderTest.java
copy to extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
index e3fc56f..544484f 100644
--- a/extensions/throwingproviders/test/com/google/inject/throwingproviders/ThrowingProviderBinderTest.java
+++ b/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
@@ -18,6 +18,7 @@
 
 import com.google.inject.AbstractModule;
 
+import com.google.inject.Asserts;
 import com.google.inject.CreationException;
 import com.google.inject.Guice;
 import com.google.inject.Inject;
@@ -34,8 +35,10 @@
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.HasDependencies;
 import com.google.inject.spi.Message;
+import com.google.inject.throwingproviders.ThrowingProviderBinder.Result;
 
 import java.io.IOException;
+import java.net.BindException;
 import java.rmi.AccessException;
 import java.rmi.RemoteException;
 import java.util.Arrays;
@@ -49,7 +52,7 @@
  * @author jmourits@google.com (Jerome Mourits)
  * @author jessewilson@google.com (Jesse Wilson)
  */
-public class ThrowingProviderBinderTest extends TestCase {
+public class CheckedProviderTest extends TestCase {
 
   private final TypeLiteral<RemoteProvider<String>> remoteProviderOfString
       = new TypeLiteral<RemoteProvider<String>>() { };
@@ -65,48 +68,48 @@
   });
   private Injector providesInjector = Guice.createInjector(new AbstractModule() {
     protected void configure() {
-     ThrowingProviderBinder.install(this, binder());
+     install(ThrowingProviderBinder.forModule(this));
      bindScope(TestScope.Scoped.class, testScope);
     }
     
     @SuppressWarnings("unused")
-    @ThrowingProvides(RemoteProvider.class)
+    @CheckedProvides(RemoteProvider.class)
     @TestScope.Scoped
-    String throwOrGet() throws RemoteException {
+    String throwOrGet() throws RemoteException, BindException {
       return mockRemoteProvider.get();
     }
   });
 
-  public void testExceptionsThrown_Bind() {
+  public void testExceptionsThrown_Bind() throws Exception {
     tExceptionsThrown(bindInjector);
   }
   
-  public void testExceptionsThrown_Provides() {
+  public void testExceptionsThrown_Provides() throws Exception {
     tExceptionsThrown(providesInjector);
   }
   
-  private void tExceptionsThrown(Injector injector) {
+  private void tExceptionsThrown(Injector injector) throws Exception {
     RemoteProvider<String> remoteProvider = 
       injector.getInstance(Key.get(remoteProviderOfString));
 
-    mockRemoteProvider.throwOnNextGet("kaboom!");
+    mockRemoteProvider.throwOnNextGet(new BindException("kaboom!"));
     try {
       remoteProvider.get();
       fail();
-    } catch (RemoteException expected) {
+    } catch (BindException expected) {
       assertEquals("kaboom!", expected.getMessage());
     }
   }
 
-  public void testValuesScoped_Bind() throws RemoteException {
+  public void testValuesScoped_Bind() throws Exception  {
     tValuesScoped(bindInjector);
   }
   
-  public void testValuesScoped_Provides() throws RemoteException {
+  public void testValuesScoped_Provides() throws Exception  {
     tValuesScoped(providesInjector);
   }
   
-  private void tValuesScoped(Injector injector) throws RemoteException {
+  private void tValuesScoped(Injector injector) throws Exception {
     RemoteProvider<String> remoteProvider = 
       injector.getInstance(Key.get(remoteProviderOfString));
 
@@ -120,19 +123,19 @@
     assertEquals("B", remoteProvider.get());
   }
 
-  public void testExceptionsScoped_Bind() {
+  public void testExceptionsScoped_Bind() throws Exception {
     tExceptionsScoped(bindInjector);
   }
   
-  public void testExceptionsScoped_Provides() {
+  public void testExceptionsScoped_Provides() throws Exception {
     tExceptionsScoped(providesInjector);
   }
   
-  private void tExceptionsScoped(Injector injector) {
+  private void tExceptionsScoped(Injector injector) throws Exception {
     RemoteProvider<String> remoteProvider = 
         injector.getInstance(Key.get(remoteProviderOfString));
 
-    mockRemoteProvider.throwOnNextGet("A");
+    mockRemoteProvider.throwOnNextGet(new RemoteException("A"));
     try {
       remoteProvider.get();
       fail();
@@ -140,7 +143,7 @@
       assertEquals("A", expected.getMessage());
     }
     
-    mockRemoteProvider.throwOnNextGet("B");
+    mockRemoteProvider.throwOnNextGet(new RemoteException("B"));
     try {
       remoteProvider.get();
       fail();
@@ -149,7 +152,7 @@
     }
   }
   
-  public void testAnnotations_Bind() throws RemoteException {
+  public void testAnnotations_Bind() throws Exception {
     final MockRemoteProvider<String> mockRemoteProviderA = new MockRemoteProvider<String>();
     final MockRemoteProvider<String> mockRemoteProviderB = new MockRemoteProvider<String>();
     bindInjector = Guice.createInjector(new AbstractModule() {
@@ -167,24 +170,24 @@
     tAnnotations(bindInjector, mockRemoteProviderA, mockRemoteProviderB);
   }
   
-  public void testAnnotations_Provides() throws RemoteException {
+  public void testAnnotations_Provides() throws Exception {
     final MockRemoteProvider<String> mockRemoteProviderA = new MockRemoteProvider<String>();
     final MockRemoteProvider<String> mockRemoteProviderB = new MockRemoteProvider<String>();
     providesInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
        }
        
        @SuppressWarnings("unused")
-       @ThrowingProvides(RemoteProvider.class)
+       @CheckedProvides(RemoteProvider.class)
        @Named("a")
-       String throwOrGet() throws RemoteException {
+       String throwOrGet() throws RemoteException, BindException {
          return mockRemoteProviderA.get();
        }
        
        @SuppressWarnings("unused")
-       @ThrowingProvides(RemoteProvider.class)
-       String throwOrGet2() throws RemoteException {
+       @CheckedProvides(RemoteProvider.class)
+       String throwOrGet2() throws RemoteException, BindException {
          return mockRemoteProviderB.get();
        }
     });
@@ -192,7 +195,7 @@
   }
   
   private void tAnnotations(Injector injector, MockRemoteProvider<String> mockA,
-      MockRemoteProvider<String> mockB) throws RemoteException {
+      MockRemoteProvider<String> mockB) throws Exception {
     mockA.setNextToReturn("A");
     mockB.setNextToReturn("B");
     assertEquals("A", 
@@ -202,15 +205,15 @@
         injector.getInstance(Key.get(remoteProviderOfString)).get());
   }
   
-  public void testUndeclaredExceptions_Bind() throws RemoteException {
+  public void testUndeclaredExceptions_Bind() throws Exception {
     tUndeclaredExceptions(bindInjector);
   }
   
-  public void testUndeclaredExceptions_Provides() throws RemoteException {
+  public void testUndeclaredExceptions_Provides() throws Exception {
     tUndeclaredExceptions(providesInjector);
   }
 
-  private void tUndeclaredExceptions(Injector injector) throws RemoteException { 
+  private void tUndeclaredExceptions(Injector injector) throws Exception { 
     RemoteProvider<String> remoteProvider = 
         injector.getInstance(Key.get(remoteProviderOfString));
     mockRemoteProvider.throwOnNextGet(new IndexOutOfBoundsException("A"));
@@ -231,7 +234,7 @@
     }
   }
 
-  public void testThrowingProviderSubclassing() throws RemoteException {
+  public void testThrowingProviderSubclassing() throws Exception {
     final SubMockRemoteProvider aProvider = new SubMockRemoteProvider();
     aProvider.setNextToReturn("A");
 
@@ -249,7 +252,7 @@
 
   static class SubMockRemoteProvider extends MockRemoteProvider<String> { }
 
-  public void testBindingToNonInterfaceType_Bind() throws RemoteException {
+  public void testBindingToNonInterfaceType_Bind() throws Exception {
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
@@ -265,15 +268,15 @@
     }
   }
   
-  public void testBindingToNonInterfaceType_Provides() throws RemoteException {
+  public void testBindingToNonInterfaceType_Provides() throws Exception {
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
           
         @SuppressWarnings("unused")
-        @ThrowingProvides(MockRemoteProvider.class)
+        @CheckedProvides(MockRemoteProvider.class)
         String foo() {
           return null;
         }
@@ -285,7 +288,7 @@
     }
   }  
   
-  public void testBindingToSubSubInterface_Bind() throws RemoteException {
+  public void testBindingToSubSubInterface_Bind() throws Exception {
     try {
       bindInjector = Guice.createInjector(new AbstractModule() {
         protected void configure() {
@@ -295,34 +298,34 @@
       });
       fail();
     } catch (CreationException expected) {
-      assertEquals(SubRemoteProvider.class.getName() + " must extend ThrowingProvider (and only ThrowingProvider)",
+      assertEquals(SubRemoteProvider.class.getName() + " must extend CheckedProvider (and only CheckedProvider)",
           Iterables.getOnlyElement(expected.getErrorMessages()).getMessage());
     }
   }
   
-  public void testBindingToSubSubInterface_Provides() throws RemoteException {
+  public void testBindingToSubSubInterface_Provides() throws Exception {
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
           
         @SuppressWarnings("unused")
-        @ThrowingProvides(SubRemoteProvider.class)
+        @CheckedProvides(SubRemoteProvider.class)
         String foo() {
           return null;
         }
       });
       fail();
     } catch (CreationException expected) {
-      assertEquals(SubRemoteProvider.class.getName() + " must extend ThrowingProvider (and only ThrowingProvider)",
+      assertEquals(SubRemoteProvider.class.getName() + " must extend CheckedProvider (and only CheckedProvider)",
           Iterables.getOnlyElement(expected.getErrorMessages()).getMessage());
     }
   }    
 
   interface SubRemoteProvider extends RemoteProvider<String> { }
 
-  public void testBindingToInterfaceWithExtraMethod_Bind() throws RemoteException {
+  public void testBindingToInterfaceWithExtraMethod_Bind() throws Exception {
     try {
       bindInjector = Guice.createInjector(new AbstractModule() {
         protected void configure() {
@@ -338,15 +341,15 @@
     }
   }
   
-  public void testBindingToInterfaceWithExtraMethod_Provides() throws RemoteException {
+  public void testBindingToInterfaceWithExtraMethod_Provides() throws Exception {
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
           
         @SuppressWarnings("unused")
-        @ThrowingProvides(RemoteProviderWithExtraMethod.class)
+        @CheckedProvides(RemoteProviderWithExtraMethod.class)
         String foo() {
           return null;
         }
@@ -400,11 +403,11 @@
         bind(Integer.class).toInstance(5);
         bind(Double.class).toInstance(5d);
         bind(Long.class).toInstance(5L);
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
       }
       
       @SuppressWarnings("unused")
-      @ThrowingProvides(RemoteProvider.class)
+      @CheckedProvides(RemoteProvider.class)
       String foo(String s, Integer i, Double d, Long l) {
         return null;
       }
@@ -430,11 +433,13 @@
         Key.get(Long.class), Key.get(Double.class)), dependencyKeys);
   }  
 
-  interface RemoteProviderWithExtraMethod<T> extends ThrowingProvider<T, RemoteException> {
-    T get(T defaultValue) throws RemoteException;
+  interface RemoteProviderWithExtraMethod<T> extends CheckedProvider<T> {
+    T get(T defaultValue) throws RemoteException, BindException;
   }
 
-  interface RemoteProvider<T> extends ThrowingProvider<T, RemoteException> { }
+  interface RemoteProvider<T> extends CheckedProvider<T> { 
+    public T get() throws RemoteException, BindException;
+  }
   
   static class DependentRemoteProvider<T> implements RemoteProvider<T> {
     @Inject double foo;
@@ -452,10 +457,6 @@
   static class MockRemoteProvider<T> implements RemoteProvider<T> {
     Exception nextToThrow;
     T nextToReturn;
-    
-    public void throwOnNextGet(String message) {
-      throwOnNextGet(new RemoteException(message));
-    }
 
     public void throwOnNextGet(Exception nextToThrow) {
       this.nextToThrow = nextToThrow;
@@ -465,9 +466,11 @@
       this.nextToReturn = nextToReturn;
     }
     
-    public T get() throws RemoteException {
+    public T get() 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) {
@@ -497,11 +500,11 @@
   public void testBindingToInterfaceWithBoundValueType_Provides() throws RemoteException {
     providesInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
       }
       
       @SuppressWarnings("unused")
-      @ThrowingProvides(StringRemoteProvider.class)
+      @CheckedProvides(StringRemoteProvider.class)
       String foo() throws RemoteException {
           return "A";
       }
@@ -510,9 +513,11 @@
     assertEquals("A", providesInjector.getInstance(StringRemoteProvider.class).get());
   }
 
-  interface StringRemoteProvider extends ThrowingProvider<String, RemoteException> { }
+  interface StringRemoteProvider extends CheckedProvider<String> {
+    String get() throws RemoteException;  
+  }
 
-  public void testBindingToInterfaceWithGeneric_Bind() throws RemoteException {
+  public void testBindingToInterfaceWithGeneric_Bind() throws Exception {
     bindInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
         ThrowingProviderBinder.create(binder())
@@ -530,14 +535,14 @@
     assertEquals(Arrays.asList("A", "B"), bindInjector.getInstance(key).get());
   }
   
-  public void testBindingToInterfaceWithGeneric_Provides() throws RemoteException {
+  public void testBindingToInterfaceWithGeneric_Provides() throws Exception {
     providesInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
       }
       
       @SuppressWarnings("unused")
-      @ThrowingProvides(RemoteProvider.class)
+      @CheckedProvides(RemoteProvider.class)
       List<String> foo() throws RemoteException {
           return Arrays.asList("A", "B");
       }
@@ -552,32 +557,35 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(RemoteProvider.class)
+        @CheckedProvides(RemoteProvider.class)
         String foo() throws InterruptedException {
             return null;
         }
       });
       fail();
     } catch(CreationException ce) {
-      assertEquals(InterruptedException.class.getName() + " is not compatible with the exception ("
-          + RemoteException.class.getName() + ") declared in the ThrowingProvider interface ("
-          + RemoteProvider.class.getName() + ")",
+      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());
     }
   }
   
-  public void testProviderMethodWithSubclassOfExceptionIsOk() {
+  public void testProviderMethodWithSubclassOfExceptionIsOk() throws Exception {
     providesInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
       }
       
       @SuppressWarnings("unused")
-      @ThrowingProvides(RemoteProvider.class)
+      @CheckedProvides(RemoteProvider.class)
       String foo() throws AccessException {
         throw new AccessException("boo!");
       }
@@ -599,32 +607,35 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(RemoteProvider.class)
+        @CheckedProvides(RemoteProvider.class)
         String foo() throws IOException {
             return null;
         }
       });
       fail();
     } catch(CreationException ce) {
-      assertEquals(IOException.class.getName() + " is not compatible with the exception ("
-          + RemoteException.class.getName() + ") declared in the ThrowingProvider interface ("
-          + RemoteProvider.class.getName() + ")",
+      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());
     }
   }
   
-  public void testProviderMethodWithRuntimeExceptionsIsOk() throws RemoteException {
+  public void testProviderMethodWithRuntimeExceptionsIsOk() throws Exception {
     providesInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
       }
       
       @SuppressWarnings("unused")
-      @ThrowingProvides(RemoteProvider.class)
+      @CheckedProvides(RemoteProvider.class)
       String foo() throws RuntimeException {
         throw new RuntimeException("boo!");
       }
@@ -641,17 +652,20 @@
     }
   }
   
+  private static class SubBindException extends BindException {}
+  
   public void testProviderMethodWithManyExceptions() {
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(RemoteProvider.class)
+        @CheckedProvides(RemoteProvider.class)
         String foo() throws InterruptedException, RuntimeException, RemoteException, 
-                            AccessException, TooManyListenersException {
+                            AccessException, TooManyListenersException,
+                            BindException, SubBindException {
             return null;
         }
       });
@@ -659,13 +673,19 @@
     } 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 exception ("
-          + RemoteException.class.getName() + ") declared in the ThrowingProvider interface ("
-          + RemoteProvider.class.getName() + ")",
+      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 exception ("
-          + RemoteException.class.getName() + ") declared in the ThrowingProvider interface ("
-          + RemoteProvider.class.getName() + ")",
+      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());
     }
@@ -675,11 +695,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(TooManyTypeParameters.class)
+        @CheckedProvides(TooManyTypeParameters.class)
         String foo() {
             return null;
         }
@@ -695,11 +715,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(WrongThrowingProviderType.class)
+        @CheckedProvides(WrongThrowingProviderType.class)
         String foo() {
             return null;
         }
@@ -707,7 +727,7 @@
       fail();
     } catch(CreationException ce) {
       assertEquals(WrongThrowingProviderType.class.getName() 
-          + " does not properly extend ThrowingProvider, the first type parameter of ThrowingProvider "
+          + " does not properly extend CheckedProvider, the first type parameter of CheckedProvider "
           + "(java.lang.String) is not a generic type",
           Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
     }    
@@ -717,11 +737,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(OneNoneGetMethod.class)
+        @CheckedProvides(OneNoneGetMethod.class)
         String foo() {
             return null;
         }
@@ -738,11 +758,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(ManyMethods.class)
+        @CheckedProvides(ManyMethods.class)
         String foo() {
             return null;
         }
@@ -780,11 +800,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(StringRemoteProvider.class)
+        @CheckedProvides(StringRemoteProvider.class)
         Integer foo() {
             return null;
         }
@@ -797,18 +817,63 @@
     }
   }
   
-  private static interface TooManyTypeParameters<T, P> extends ThrowingProvider<T, Exception> {    
+  private static interface TooManyTypeParameters<T, P> extends CheckedProvider<T> {    
   }
   
-  private static interface WrongThrowingProviderType<T> extends ThrowingProvider<String, Exception> {    
+  private static interface WrongThrowingProviderType<T> extends CheckedProvider<String> {    
   }
   
-  private static interface OneNoneGetMethod<T> extends ThrowingProvider<T, Exception> {
+  private static interface OneNoneGetMethod<T> extends CheckedProvider<T> {
     T bar();
   }
   
-  private static interface ManyMethods<T> extends ThrowingProvider<T, Exception> {
+  private static interface ManyMethods<T> extends CheckedProvider<T> {
     T bar();
     String baz();
   }
+  
+  public void testResultSerializes() throws Exception {
+    Result result = Result.forValue("foo");
+    result = Asserts.reserialize(result);
+    assertEquals("foo", result.getOrThrow());
+  }
+  
+  public void testResultExceptionSerializes() throws Exception {
+    Result result = Result.forException(new Exception("boo"));
+    result = Asserts.reserialize(result);
+    try {
+      result.getOrThrow();
+      fail();
+    } catch(Exception ex) {
+      assertEquals("boo", ex.getMessage());
+    }
+  }
+  
+  public void testEarlyBindingError() {
+    try {
+      Guice.createInjector(new AbstractModule() {
+        protected void configure() {
+          ThrowingProviderBinder.create(binder())
+              .bind(StringRemoteProvider.class, String.class)
+              .to(FailingProvider.class);
+        }
+      });
+      fail();
+    } catch(CreationException ce) {
+      assertEquals("Could not find a suitable constructor in " + FailingProvider.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());
+    }
+  }
+  
+  private static class FailingProvider implements StringRemoteProvider {
+    // no @Inject.
+    @SuppressWarnings("unused")
+    FailingProvider(Integer foo) {}
+    
+    public String get() {
+      return null;
+    }
+  }
 }
diff --git a/extensions/throwingproviders/test/com/google/inject/throwingproviders/ThrowingProviderBinderTest.java b/extensions/throwingproviders/test/com/google/inject/throwingproviders/ThrowingProviderTest.java
similarity index 90%
rename from extensions/throwingproviders/test/com/google/inject/throwingproviders/ThrowingProviderBinderTest.java
rename to extensions/throwingproviders/test/com/google/inject/throwingproviders/ThrowingProviderTest.java
index e3fc56f..60c6914 100644
--- a/extensions/throwingproviders/test/com/google/inject/throwingproviders/ThrowingProviderBinderTest.java
+++ b/extensions/throwingproviders/test/com/google/inject/throwingproviders/ThrowingProviderTest.java
@@ -49,7 +49,8 @@
  * @author jmourits@google.com (Jerome Mourits)
  * @author jessewilson@google.com (Jesse Wilson)
  */
-public class ThrowingProviderBinderTest extends TestCase {
+@SuppressWarnings("deprecation")
+public class ThrowingProviderTest extends TestCase {
 
   private final TypeLiteral<RemoteProvider<String>> remoteProviderOfString
       = new TypeLiteral<RemoteProvider<String>>() { };
@@ -65,12 +66,12 @@
   });
   private Injector providesInjector = Guice.createInjector(new AbstractModule() {
     protected void configure() {
-     ThrowingProviderBinder.install(this, binder());
+      install(ThrowingProviderBinder.forModule(this));
      bindScope(TestScope.Scoped.class, testScope);
     }
     
     @SuppressWarnings("unused")
-    @ThrowingProvides(RemoteProvider.class)
+    @CheckedProvides(RemoteProvider.class)
     @TestScope.Scoped
     String throwOrGet() throws RemoteException {
       return mockRemoteProvider.get();
@@ -172,18 +173,18 @@
     final MockRemoteProvider<String> mockRemoteProviderB = new MockRemoteProvider<String>();
     providesInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
        }
        
        @SuppressWarnings("unused")
-       @ThrowingProvides(RemoteProvider.class)
+       @CheckedProvides(RemoteProvider.class)
        @Named("a")
        String throwOrGet() throws RemoteException {
          return mockRemoteProviderA.get();
        }
        
        @SuppressWarnings("unused")
-       @ThrowingProvides(RemoteProvider.class)
+       @CheckedProvides(RemoteProvider.class)
        String throwOrGet2() throws RemoteException {
          return mockRemoteProviderB.get();
        }
@@ -269,11 +270,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
           
         @SuppressWarnings("unused")
-        @ThrowingProvides(MockRemoteProvider.class)
+        @CheckedProvides(MockRemoteProvider.class)
         String foo() {
           return null;
         }
@@ -295,7 +296,7 @@
       });
       fail();
     } catch (CreationException expected) {
-      assertEquals(SubRemoteProvider.class.getName() + " must extend ThrowingProvider (and only ThrowingProvider)",
+      assertEquals(SubRemoteProvider.class.getName() + " must extend CheckedProvider (and only CheckedProvider)",
           Iterables.getOnlyElement(expected.getErrorMessages()).getMessage());
     }
   }
@@ -304,18 +305,18 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
           
         @SuppressWarnings("unused")
-        @ThrowingProvides(SubRemoteProvider.class)
+        @CheckedProvides(SubRemoteProvider.class)
         String foo() {
           return null;
         }
       });
       fail();
     } catch (CreationException expected) {
-      assertEquals(SubRemoteProvider.class.getName() + " must extend ThrowingProvider (and only ThrowingProvider)",
+      assertEquals(SubRemoteProvider.class.getName() + " must extend CheckedProvider (and only CheckedProvider)",
           Iterables.getOnlyElement(expected.getErrorMessages()).getMessage());
     }
   }    
@@ -342,11 +343,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
           
         @SuppressWarnings("unused")
-        @ThrowingProvides(RemoteProviderWithExtraMethod.class)
+        @CheckedProvides(RemoteProviderWithExtraMethod.class)
         String foo() {
           return null;
         }
@@ -400,11 +401,11 @@
         bind(Integer.class).toInstance(5);
         bind(Double.class).toInstance(5d);
         bind(Long.class).toInstance(5L);
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
       }
       
       @SuppressWarnings("unused")
-      @ThrowingProvides(RemoteProvider.class)
+      @CheckedProvides(RemoteProvider.class)
       String foo(String s, Integer i, Double d, Long l) {
         return null;
       }
@@ -497,11 +498,11 @@
   public void testBindingToInterfaceWithBoundValueType_Provides() throws RemoteException {
     providesInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
       }
       
       @SuppressWarnings("unused")
-      @ThrowingProvides(StringRemoteProvider.class)
+      @CheckedProvides(StringRemoteProvider.class)
       String foo() throws RemoteException {
           return "A";
       }
@@ -533,11 +534,11 @@
   public void testBindingToInterfaceWithGeneric_Provides() throws RemoteException {
     providesInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
       }
       
       @SuppressWarnings("unused")
-      @ThrowingProvides(RemoteProvider.class)
+      @CheckedProvides(RemoteProvider.class)
       List<String> foo() throws RemoteException {
           return Arrays.asList("A", "B");
       }
@@ -552,19 +553,19 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(RemoteProvider.class)
+        @CheckedProvides(RemoteProvider.class)
         String foo() throws InterruptedException {
             return null;
         }
       });
       fail();
     } catch(CreationException ce) {
-      assertEquals(InterruptedException.class.getName() + " is not compatible with the exception ("
-          + RemoteException.class.getName() + ") declared in the ThrowingProvider interface ("
+      assertEquals(InterruptedException.class.getName() + " is not compatible with the exceptions (["
+          + RemoteException.class + "]) declared in the CheckedProvider interface ("
           + RemoteProvider.class.getName() + ")",
           Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
     }
@@ -573,11 +574,11 @@
   public void testProviderMethodWithSubclassOfExceptionIsOk() {
     providesInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
       }
       
       @SuppressWarnings("unused")
-      @ThrowingProvides(RemoteProvider.class)
+      @CheckedProvides(RemoteProvider.class)
       String foo() throws AccessException {
         throw new AccessException("boo!");
       }
@@ -599,19 +600,19 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(RemoteProvider.class)
+        @CheckedProvides(RemoteProvider.class)
         String foo() throws IOException {
             return null;
         }
       });
       fail();
     } catch(CreationException ce) {
-      assertEquals(IOException.class.getName() + " is not compatible with the exception ("
-          + RemoteException.class.getName() + ") declared in the ThrowingProvider interface ("
+      assertEquals(IOException.class.getName() + " is not compatible with the exceptions (["
+          + RemoteException.class + "]) declared in the CheckedProvider interface ("
           + RemoteProvider.class.getName() + ")",
           Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
     }
@@ -620,11 +621,11 @@
   public void testProviderMethodWithRuntimeExceptionsIsOk() throws RemoteException {
     providesInjector = Guice.createInjector(new AbstractModule() {
       protected void configure() {
-        ThrowingProviderBinder.install(this, binder());
+        install(ThrowingProviderBinder.forModule(this));
       }
       
       @SuppressWarnings("unused")
-      @ThrowingProvides(RemoteProvider.class)
+      @CheckedProvides(RemoteProvider.class)
       String foo() throws RuntimeException {
         throw new RuntimeException("boo!");
       }
@@ -645,11 +646,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(RemoteProvider.class)
+        @CheckedProvides(RemoteProvider.class)
         String foo() throws InterruptedException, RuntimeException, RemoteException, 
                             AccessException, TooManyListenersException {
             return null;
@@ -659,12 +660,12 @@
     } 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 exception ("
-          + RemoteException.class.getName() + ") declared in the ThrowingProvider interface ("
+      assertEquals(InterruptedException.class.getName() + " is not compatible with the exceptions (["
+          + RemoteException.class + "]) declared in the CheckedProvider interface ("
           + RemoteProvider.class.getName() + ")",
           errors.get(0).getMessage());
-      assertEquals(TooManyListenersException.class.getName() + " is not compatible with the exception ("
-          + RemoteException.class.getName() + ") declared in the ThrowingProvider interface ("
+      assertEquals(TooManyListenersException.class.getName() + " is not compatible with the exceptions (["
+          + RemoteException.class + "]) declared in the CheckedProvider interface ("
           + RemoteProvider.class.getName() + ")",
           errors.get(1).getMessage());
       assertEquals(2, errors.size());
@@ -675,11 +676,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(TooManyTypeParameters.class)
+        @CheckedProvides(TooManyTypeParameters.class)
         String foo() {
             return null;
         }
@@ -695,11 +696,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(WrongThrowingProviderType.class)
+        @CheckedProvides(WrongThrowingProviderType.class)
         String foo() {
             return null;
         }
@@ -707,7 +708,7 @@
       fail();
     } catch(CreationException ce) {
       assertEquals(WrongThrowingProviderType.class.getName() 
-          + " does not properly extend ThrowingProvider, the first type parameter of ThrowingProvider "
+          + " does not properly extend CheckedProvider, the first type parameter of CheckedProvider "
           + "(java.lang.String) is not a generic type",
           Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
     }    
@@ -717,11 +718,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(OneNoneGetMethod.class)
+        @CheckedProvides(OneNoneGetMethod.class)
         String foo() {
             return null;
         }
@@ -738,11 +739,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(ManyMethods.class)
+        @CheckedProvides(ManyMethods.class)
         String foo() {
             return null;
         }
@@ -780,11 +781,11 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          ThrowingProviderBinder.install(this, binder());
+          install(ThrowingProviderBinder.forModule(this));
         }
         
         @SuppressWarnings("unused")
-        @ThrowingProvides(StringRemoteProvider.class)
+        @CheckedProvides(StringRemoteProvider.class)
         Integer foo() {
             return null;
         }