issue 506 - fail fast & with a useful error message when an AssistedInject factory has Provider<T> as a factory type.  patch ( slightly modified) by ffaber.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@1192 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryModuleBuilder.java b/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryModuleBuilder.java
index 5e3cf37..713068b 100644
--- a/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryModuleBuilder.java
+++ b/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryModuleBuilder.java
@@ -173,6 +173,10 @@
  *       .implement(Car.class, Names.named("clean"), Prius.class)
  *       .build(CarFactory.class));
  * }</pre>
+ * 
+ * <h3>Implementation limitations</h3>
+ * As a limitation of the implementation, it is prohibited to declare a factory method that
+ * accepts a {@code Provider} as one of its arguments.
  *
  * @author schmitt@google.com (Peter Schmitt)
  */
diff --git a/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java b/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
index d599166..d7ad255 100644
--- a/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
+++ b/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
@@ -179,6 +179,13 @@
         List<Key<?>> keys = Lists.newArrayList();
         for (TypeLiteral<?> param : params) {
           Key<?> paramKey = getKey(param, method, paramAnnotations[p++], errors);
+          Class<?> underlylingType = paramKey.getTypeLiteral().getRawType();
+          if (underlylingType.equals(Provider.class)
+              || underlylingType.equals(javax.inject.Provider.class)) {
+            errors.addMessage("A Provider may not be a type in a factory method of an AssistedInject."
+                    + "\n  Offending instance is parameter [%s] with key [%s] on method [%s]",
+                    p, paramKey, method);
+          }
           keys.add(assistKey(method, paramKey, errors));
         }
         ImmutableList<Key<?>> immutableParamList = ImmutableList.copyOf(keys);
@@ -407,7 +414,7 @@
     }
     return false;
   }
-  
+
   /**
    * Returns a key similar to {@code key}, but with an {@literal @}Assisted binding annotation.
    * This fails if another binding annotation is clobbered in the process. If the key already has
@@ -466,7 +473,7 @@
     final Key<?> assistedReturnType = Key.get(returnType.getTypeLiteral(), Assisted.class);
 
     Module assistedModule = new AbstractModule() {
-      @SuppressWarnings("unchecked") // raw keys are necessary for the args array and return value
+      @Override @SuppressWarnings("unchecked") // raw keys are necessary for the args array and return value
       protected void configure() {
         Binder binder = binder().withSource(method);
 
diff --git a/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java b/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java
index bd40290..58869ce 100644
--- a/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java
+++ b/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java
@@ -560,6 +560,73 @@
     assertNull(subaru.colorProvider.get());
   }
 
+  interface ProviderBasedColoredCarFactory {
+    Car createCar(Provider<Color> colorProvider, Provider<String> stringProvider);
+    Mustang createMustang(@Assisted("color") Provider<Color> colorProvider);
+  }
+
+  public void testAssistedProviderIsDisallowed() {
+    try {
+      Guice.createInjector(new AbstractModule() {
+          @Override protected void configure() {
+            bind(ProviderBasedColoredCarFactory.class).toProvider(
+                FactoryProvider.newFactory(ProviderBasedColoredCarFactory.class, Subaru.class));
+          }
+      });
+      fail();
+    } catch (CreationException expected) {
+      assertContains(expected.getMessage(),
+          "1) A Provider may not be a type in a factory method of an AssistedInject."
+            + "\n  Offending instance is parameter [1] with key"
+            + " [com.google.inject.Provider<java.awt.Color>] on method ["
+            + ProviderBasedColoredCarFactory.class.getName() + ".createCar()]",
+          "2) A Provider may not be a type in a factory method of an AssistedInject."
+            + "\n  Offending instance is parameter [2] with key"
+            + " [com.google.inject.Provider<java.lang.String>] on method ["
+            + ProviderBasedColoredCarFactory.class.getName() + ".createCar()]",
+          "3) A Provider may not be a type in a factory method of an AssistedInject."
+            + "\n  Offending instance is parameter [1] with key"
+            + " [com.google.inject.Provider<java.awt.Color>"
+            + " annotated with @com.google.inject.assistedinject.Assisted(value=color)]"
+            + " on method [" + ProviderBasedColoredCarFactory.class.getName() + ".createMustang()]"
+      );
+      
+    }
+  }
+
+  interface JavaxProviderBasedColoredCarFactory {
+    Car createCar(javax.inject.Provider<Color> colorProvider, javax.inject.Provider<String> stringProvider);
+    Mustang createMustang(@Assisted("color") javax.inject.Provider<Color> colorProvider);
+  }
+
+  public void testAssistedJavaxProviderIsDisallowed() {
+    try {
+      Guice.createInjector(new AbstractModule() {
+          @Override protected void configure() {
+            bind(JavaxProviderBasedColoredCarFactory.class).toProvider(
+                FactoryProvider.newFactory(JavaxProviderBasedColoredCarFactory.class, Subaru.class));
+          }
+      });
+      fail();
+    } catch (CreationException expected) {
+      assertContains(expected.getMessage(),
+          "1) A Provider may not be a type in a factory method of an AssistedInject."
+            + "\n  Offending instance is parameter [1] with key"
+            + " [com.google.inject.Provider<java.awt.Color>] on method ["
+            + JavaxProviderBasedColoredCarFactory.class.getName() + ".createCar()]",
+          "2) A Provider may not be a type in a factory method of an AssistedInject."
+            + "\n  Offending instance is parameter [2] with key"
+            + " [com.google.inject.Provider<java.lang.String>] on method ["
+            + JavaxProviderBasedColoredCarFactory.class.getName() + ".createCar()]",
+          "3) A Provider may not be a type in a factory method of an AssistedInject."
+            + "\n  Offending instance is parameter [1] with key"
+            + " [com.google.inject.Provider<java.awt.Color>"
+            + " annotated with @com.google.inject.assistedinject.Assisted(value=color)]"
+            + " on method [" + JavaxProviderBasedColoredCarFactory.class.getName() + ".createMustang()]"
+      );
+    }
+  }
+
   public void testFactoryUseBeforeInitialization() {
     ColoredCarFactory carFactory = FactoryProvider.newFactory(ColoredCarFactory.class, Subaru.class)
         .get();