Change the new ThrowingProviderBinder.providing to look for @ThrowingInject instead of @Inject.

Revision created by MOE tool push_codebase.
MOE_MIGRATION=4875
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvideUtils.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvideUtils.java
index 17885c1..3d8a001 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvideUtils.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvideUtils.java
@@ -4,6 +4,13 @@
 
 import com.google.inject.Binder;
 import com.google.inject.TypeLiteral;
+import com.google.inject.internal.Annotations;
+import com.google.inject.internal.Errors;
+import com.google.inject.spi.Message;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
 
 /**
  * Utilities for the throwing provider module.
@@ -14,6 +21,43 @@
   
   private CheckedProvideUtils() {}
   
+  private static final String CONSTRUCTOR_RULES =
+      "Classes must have either one (and only one) constructor annotated with @ThrowingInject.";
+  
+  @SuppressWarnings("unchecked") // safe because it's a constructor of the typeLiteral
+  static <T> Constructor<? extends T> findThrowingConstructor(
+      TypeLiteral<? extends T> typeLiteral, Binder binder) {
+    
+    Class<?> rawType = typeLiteral.getRawType();
+    Errors errors = new Errors(rawType);
+    Constructor<?> cxtor = null;
+    for (Constructor<?> constructor : rawType.getDeclaredConstructors()) {
+      if (constructor.isAnnotationPresent(ThrowingInject.class)) {
+        if (cxtor != null) {
+          errors.addMessage("%s has more than one constructor annotated with @ThrowingInject. "
+              + CONSTRUCTOR_RULES, rawType);
+        }
+
+        cxtor = constructor;
+        Annotation misplacedBindingAnnotation = Annotations.findBindingAnnotation(
+            errors, cxtor, ((AnnotatedElement) cxtor).getAnnotations());
+        if (misplacedBindingAnnotation != null) {
+          errors.misplacedBindingAnnotation(cxtor, misplacedBindingAnnotation);
+        }
+      }
+    }
+    
+    if (cxtor == null) {
+      errors.addMessage(
+          "Could not find a suitable constructor in %s. " + CONSTRUCTOR_RULES, rawType);
+    }
+
+    for (Message msg : errors.getMessages()) {
+      binder.addError(msg);
+    }
+    return (Constructor<? extends T>) cxtor;
+  }
+  
   /** Adds errors to the binder if the exceptions aren't valid. */
   static void validateExceptions(Binder binder,
       Iterable<TypeLiteral<?>> actualExceptionTypes,
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingInject.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingInject.java
new file mode 100644
index 0000000..6d18882
--- /dev/null
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingInject.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2012 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;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.Inject;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * A version of {@literal @}{@link Inject} designed for ThrowingProviders.  Use by:
+ * <pre><code>ThrowingProviderBinder.create(binder())
+ *    .bind(RemoteProvider.class, Customer.class)
+ *    .providing(CustomerImpl.class);
+ * </code></pre>
+ * where CustomerImpl has a constructor annotated with ThrowingInject.
+ *
+ * @author sameb@google.com (Sam Berlin)
+ */
+@Target({ CONSTRUCTOR })
+@Retention(RUNTIME)
+@Documented
+public @interface ThrowingInject {
+}
diff --git a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
index 8131b2d..3b649b8 100644
--- a/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
+++ b/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java
@@ -188,21 +188,14 @@
     
     @SuppressWarnings("unchecked") // safe because this is the cxtor of the literal
     public ScopedBindingBuilder providing(TypeLiteral<? extends T> cxtorLiteral) {     
-      // Find the injection point of the class we want to create & get its constructor.
-      InjectionPoint ip = null;
-      try {
-        ip = InjectionPoint.forConstructorOf(cxtorLiteral);
-      } catch (ConfigurationException ce) {
-        for (Message message : ce.getErrorMessages()) {
-          binder.addError(message);
-        }
-      }
+      // Find a constructor that has @ThrowingInject.
+      Constructor<? extends T> cxtor =
+          CheckedProvideUtils.findThrowingConstructor(cxtorLiteral, binder);
 
       final Provider<T> typeProvider;
       final Key<? extends T> typeKey;
       // If we found an injection point, then bind the cxtor to a unique key
-      if (ip != null) {
-        Constructor<? extends T> cxtor = (Constructor<? extends T>) ip.getMember();
+      if (cxtor != null) {
         // Validate the exceptions are consistent with the CheckedProvider interface.
         CheckedProvideUtils.validateExceptions(
             binder, cxtorLiteral.getExceptionTypes(cxtor), exceptionTypes, interfaceType);
diff --git a/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java b/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
index 62ab1e9..94c47f3 100644
--- a/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
+++ b/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderTest.java
@@ -568,7 +568,7 @@
   static class DependentMockFoo implements Foo {
     @Inject double foo;
     
-    @Inject public DependentMockFoo(String foo, int bar) {
+    @ThrowingInject public DependentMockFoo(String foo, int bar) {
     }
     
     @Inject void initialize(long foo) {}
@@ -618,6 +618,7 @@
     static Exception nextToThrow;    
     static String nextToReturn;
     
+    @ThrowingInject
     MockFoo() throws RemoteException, BindException {
       if (nextToThrow instanceof RemoteException) {
         throw (RemoteException) nextToThrow;
@@ -647,6 +648,7 @@
     static Exception nextToThrow;    
     static String nextToReturn;
     
+    @ThrowingInject
     AnotherMockFoo() throws RemoteException, BindException {
       if (nextToThrow instanceof RemoteException) {
         throw (RemoteException) nextToThrow;
@@ -801,7 +803,7 @@
       protected void configure() {
         ThrowingProviderBinder.create(binder())
         .bind(RemoteProvider.class, new TypeLiteral<List<String>>() {})
-        .providing(new TypeLiteral<ArrayList<String>>() {});
+        .providing(new TypeLiteral<ThrowingArrayList<String>>() {});
       }
     });
 
@@ -810,6 +812,12 @@
     assertEquals(Arrays.asList(), cxtorInjector.getInstance(key).get());
   }
   
+  private static class ThrowingArrayList<T> extends ArrayList<T> {
+    @SuppressWarnings("unused")
+    @ThrowingInject
+    ThrowingArrayList() {}
+  }
+  
   public void testProviderMethodWithWrongException() {
     try {
       Guice.createInjector(new AbstractModule() {
@@ -860,6 +868,7 @@
   
   static class WrongExceptionFoo implements Foo {
     @SuppressWarnings("unused")
+    @ThrowingInject
     public WrongExceptionFoo() throws InterruptedException {
     }
     
@@ -916,6 +925,7 @@
   }
   
   static class SubclassExceptionFoo implements Foo {
+    @ThrowingInject
     public SubclassExceptionFoo() throws AccessException {
       throw new AccessException("boo!");
     }
@@ -974,6 +984,7 @@
   
   static class SuperclassExceptionFoo implements Foo {
     @SuppressWarnings("unused")
+    @ThrowingInject
     public SuperclassExceptionFoo() throws IOException {
     }
     
@@ -1028,6 +1039,7 @@
   }
     
   static class RuntimeExceptionFoo implements Foo {
+    @ThrowingInject
     public RuntimeExceptionFoo() throws RuntimeException {
       throw new RuntimeException("boo!");
     }
@@ -1110,6 +1122,7 @@
   
   static class ManyExceptionFoo implements Foo {
     @SuppressWarnings("unused")
+    @ThrowingInject
     public ManyExceptionFoo()
         throws InterruptedException,
         RuntimeException,
@@ -1331,7 +1344,7 @@
     } catch (CreationException ce) {
       assertEquals("Could not find a suitable constructor in " + InvalidFoo.class.getName()
           + ". Classes must have either one (and only one) constructor annotated with "
-          + "@Inject or a zero-argument constructor that is not private.",
+          + "@ThrowingInject.",
           Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
     }
   }
@@ -1343,6 +1356,33 @@
     @Override public String s() { return null; }
   }
   
+  public void testNoThrowingInject() {
+    try {
+      Guice.createInjector(new AbstractModule() {
+        @Override
+        protected void configure() {
+          ThrowingProviderBinder.create(binder())
+              .bind(RemoteProvider.class, Foo.class)
+              .providing(NormalInjectableFoo.class);
+        }
+      });
+      fail();
+    } catch (CreationException ce) {
+      assertEquals("Could not find a suitable constructor in " + NormalInjectableFoo.class.getName()
+          + ". Classes must have either one (and only one) constructor annotated with "
+          + "@ThrowingInject.",
+          Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
+    }
+  }
+  
+  static class NormalInjectableFoo implements Foo {
+    @Inject
+    public NormalInjectableFoo() {
+    }
+    
+    @Override public String s() { return null; }
+  }
+  
   public void testUsingDoesntClashWithBindingsOfSameType() throws Exception {
     cxtorInjector = Guice.createInjector(new AbstractModule() {
         @Override