Author: limpbizkit
Date: Mon Dec  8 22:26:00 2008
New Revision: 723

Added:
     
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
       - copied, changed from r714,  
/trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Factories.java
     
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java
       - copied, changed from r714,  
/trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoriesTest.java
Removed:
     
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Factories.java
     
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoriesTest.java
Modified:
     
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Assisted.java
     
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/AssistedInject.java
     
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider.java
     
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProviderTest.java
    trunk/src/com/google/inject/spi/InjectionPoint.java

Log:
Big API change to AssistedInject Deluxe.

I unified the API - both old and new use the same API, and the code detects  
which to use (by looking for the presence or absence of an @AssistedInject  
annotation)

This means that:
  - Upgrading from new to old is extremely easy
  - Unified Javadocs for old and new. The new Javadocs just have a section  
pointing out the differences when @AssistedInject is used instead of  
@Assisted
  - It's a little clumsier to make sure you're getting the right one. This  
is mitigated by some new checks on the factory interface to ensure the old  
constructor isn't used with the newer factories.

Also applying local variable naming fixes to InjectionPoint, as pointed out  
by Brian Harris.


Modified:  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Assisted.java
==============================================================================
---  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Assisted.java
       
(original)
+++  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Assisted.java
       
Mon Dec  8 22:26:00 2008
@@ -32,5 +32,10 @@
   */
  @BindingAnnotation @Target({ FIELD, PARAMETER, METHOD })  
@Retention(RUNTIME)
  public @interface Assisted {
+
+  /**
+   * The unique name for this parameter. This is matched to the [EMAIL 
PROTECTED]  
@Assisted} constructor
+   * parameter with the same value.
+   */
    String value() default "";
  }

Modified:  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/AssistedInject.java
==============================================================================
---  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/AssistedInject.java
         
(original)
+++  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/AssistedInject.java
         
Mon Dec  8 22:26:00 2008
@@ -22,16 +22,22 @@
  import java.lang.annotation.Target;

  /**
- * Constructors annotated with <code>@AssistedInject</code> indicate that  
will
- * can be instantiated by the [EMAIL PROTECTED] FactoryProvider}.  Each 
constructor  
must
- * exactly one corresponding factory method within the Factory Interface.
+ * <p>Constructors annotated with [EMAIL PROTECTED] @AssistedInject} indicate 
that  
will can be instantiated by
+ * the [EMAIL PROTECTED] FactoryProvider}. Each constructor must exactly one  
corresponding factory method
+ * within the factory interface.
   *
- * <p>Constructor parameters must be either supplied by the Factory  
Interface and
- * marked with <code>@Assisted</code>, or they must be injectable.
+ * <p>Constructor parameters must be either supplied by the factory  
interface and marked with
+ * <code>@Assisted</code>, or they must be injectable.
   *
+ * @deprecated [EMAIL PROTECTED] FactoryProvider} now works better with the 
standard  
[EMAIL PROTECTED] @Inject}
+ *     annotation. When using that annotation, parameters are matched by  
name and type rather than
+ *     by position. In addition, values that use the standard [EMAIL 
PROTECTED]  
@Inject} constructor
+ *     annotation are eligible for method interception.
+ *
   * @author [EMAIL PROTECTED] (Jerome Mourits)
   * @author [EMAIL PROTECTED] (Jesse Wilson)
   */
  @Target({CONSTRUCTOR})
  @Retention(RUNTIME)
[EMAIL PROTECTED]
  public @interface AssistedInject {}

Modified:  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider.java
==============================================================================
---  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider.java
        
(original)
+++  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider.java
        
Mon Dec  8 22:26:00 2008
@@ -16,15 +16,18 @@

  package com.google.inject.assistedinject;

+import com.google.common.collect.ImmutableMap;
  import com.google.common.collect.ImmutableSet;
  import com.google.common.collect.Lists;
  import com.google.common.collect.Maps;
  import com.google.inject.ConfigurationException;
  import com.google.inject.Inject;
  import com.google.inject.Injector;
+import com.google.inject.Key;
  import com.google.inject.Provider;
  import com.google.inject.internal.Errors;
  import com.google.inject.spi.Message;
+import java.lang.annotation.Annotation;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
@@ -33,77 +36,130 @@
  import java.util.Map;

  /**
- * Provides a mechanism to combine user-specified paramters with
- * [EMAIL PROTECTED] Injector}-specified paramters when creating new objects.
+ * Provides a factory that combines caller-provided parameters with  
injector-provided values when
+ * constructing objects.
   *
- * <p>To use a [EMAIL PROTECTED] FactoryProvider}:
+ * <h3>Defining a factory</h3>
+ * Create an interface whose methods return the constructed type, or its  
supertypes. The method's
+ * parameters are the arguments required to build the constructed type.
+ * <pre>public interface PaymentFactory {
+ *   Payment create(Date startDate, Money amount);
+ * }</pre>
+ * You can name your factory methods whatever you like, such as  
<i>create</i>, <i>createPayment</i>
+ * or <i>newPayment</i>.
   *
- * <p>Annotate your implementation class' constructor with the
- * [EMAIL PROTECTED] @[EMAIL PROTECTED] AssistedInject} and the user-specified 
parameters  
with
- * [EMAIL PROTECTED] @[EMAIL PROTECTED] Assisted}:
- * <pre><code>public class RealPayment implements Payment {
- *    [EMAIL PROTECTED] @}AssistedInject
- *    public RealPayment(CreditService creditService, AuthService  
authService,
- *      [EMAIL PROTECTED] @}Assisted Date startDate, [EMAIL PROTECTED] 
@}Assisted Money  
amount) {
+ * <h3>Creating a type that accepts factory parameters</h3>
+ * [EMAIL PROTECTED] constructedType} is a concrete class with an [EMAIL 
PROTECTED] @[EMAIL PROTECTED]  
Inject}-annotated
+ * constructor. In addition to injector-provided parameters, the  
constructor should have
+ * parameters that match each of the factory method's parameters. Each  
factory-provided parameter
+ * requires an [EMAIL PROTECTED] @[EMAIL PROTECTED] Assisted} annotation. This 
serves to  
document that the parameter
+ * is not bound by your application's modules.
+ * <pre>public class RealPayment implements Payment {
+ *   [EMAIL PROTECTED] @}Inject
+ *   public RealPayment(
+ *      CreditService creditService,
+ *      AuthService authService,
+ *      <strong>[EMAIL PROTECTED] @}Assisted Date startDate</strong>,
+ *      <strong>[EMAIL PROTECTED] @}Assisted Money amount</strong>) {
   *     ...
- *  }
- * }</code></pre>
+ *   }
+ * }</pre>
   *
- * <p>Write an interface with a <i>create</i> method that accepts the  
user-specified
- * parameters in the same order as they appear in the implementation  
class' constructor:
- * <pre><code>public interface PaymentFactory {
- *    Payment create(Date startDate, Money amount);
- * }</code></pre>
- *
- * <p>You can name your create methods whatever you like, such as  
<i>create</i>,
- * or <i>createPayment</i> or <i>newPayment</i>. The concrete class must
- * be assignable to the return type of your create method. You can also  
provide
- * multiple factory methods, but there must be exactly one
- * [EMAIL PROTECTED] @[EMAIL PROTECTED] AssistedInject} constructor on the 
implementation  
class for each.
- *
- * <p>In your Guice [EMAIL PROTECTED] com.google.inject.Module module}, bind 
your  
factory
- * interface to an instance of [EMAIL PROTECTED] FactoryProvider} that was 
created  
with
- * the same factory interface and implementation type:
- * <pre><code>  bind(PaymentFactory.class).toProvider(
- *     FactoryProvider.newFactory(PaymentFactory.class,  
RealPayment.class));</code></pre>
- *
- * <p>Now you can [EMAIL PROTECTED] @[EMAIL PROTECTED] Inject} your factory 
interface into  
your
- * Guice-injected classes. When you invoke the create method on that  
factory,
- * the [EMAIL PROTECTED] FactoryProvider} will instantiate the implementation 
class  
using
- * parameters from the injector and the factory method.
- *
- * <pre><code>public class PaymentAction {
- *    [EMAIL PROTECTED] @}Inject private PaymentFactory paymentFactory;
- *
- *    public void doPayment(Money amount) {
- *       Payment payment = paymentFactory.create(new Date(), amount);
- *       payment.apply();
- *    }
- * }</code></pre>
+ * <h3>Configuring factories</h3>
+ * In your [EMAIL PROTECTED] com.google.inject.Module module}, bind the 
factory  
interface to the returned
+ * factory:
+ * <pre>bind(PaymentFactory.class).toInstance(
+ *     FactoryProvider.newFactory(PaymentFactory.class,  
RealPayment.class));</pre>
+ * As a side-effect of this binding, Guice will inject the factory to  
initialize it for use. The
+ * factory cannot be used until the injector has been initialized.
+ *
+ * <h3>Using the factory</h3>
+ * Inject your factory into your application classes. When you use the  
factory, your arguments
+ * will be combined with values from the injector to produce a concrete  
instance.
+ * <pre>public class PaymentAction {
+ *   [EMAIL PROTECTED] @}Inject private PaymentFactory paymentFactory;
+ *
+ *   public void doPayment(Money amount) {
+ *     Payment payment = paymentFactory.create(new Date(), amount);
+ *     payment.apply();
+ *   }
+ * }</pre>
+ *
+ * <h3>Making parameter types distinct</h3>
+ * The types of the factory method's parameters must be distinct. To use  
multiple parameters of
+ * the same type, use a named [EMAIL PROTECTED] @[EMAIL PROTECTED] Assisted} 
annotation to  
disambiguate the
+ * parameters. The names must be applied to the factory method's  
parameters:
+ *
+ * <pre>public interface PaymentFactory {
+ *   Payment create(
+ *       <strong>[EMAIL PROTECTED] @}Assisted("startDate")</strong> Date 
startDate,
+ *       <strong>[EMAIL PROTECTED] @}Assisted("dueDate")</strong> Date dueDate,
+ *       Money amount);
+ * } </pre>
+ * ...and to the concrete type's constructor parameters:
+ * <pre>public class RealPayment implements Payment {
+ *   [EMAIL PROTECTED] @}Inject
+ *   public RealPayment(
+ *      CreditService creditService,
+ *      AuthService authService,
+ *      <strong>[EMAIL PROTECTED] @}Assisted("startDate")</strong> Date 
startDate,
+ *      <strong>[EMAIL PROTECTED] @}Assisted("dueDate")</strong> Date dueDate,
+ *      <strong>[EMAIL PROTECTED] @}Assisted</strong> Money amount) {
+ *     ...
+ *   }
+ * }</pre>
+ *
+ * <h3>Values are created by Guice</h3>
+ * Returned factories use child injectors to create values. The values are  
eligible for method
+ * interception. In addition, [EMAIL PROTECTED] @[EMAIL PROTECTED] Inject} 
members will  
be injected before they are
+ * returned.
+ *
+ * <h3>Backwards compatibility using [EMAIL PROTECTED] @}AssistedInject</h3>
+ * Instead of the [EMAIL PROTECTED] @}Inject annotation, you may annotate the  
constructed classes with
+ * [EMAIL PROTECTED] @[EMAIL PROTECTED] AssistedInject}. This triggers a 
limited  
backwards-compatability mode.
+ *
+ * <p>Instead of matching factory method arguments to constructor  
parameters using their names, the
+ * <strong>parameters are matched by their order</strong>. The first  
factory method argument is
+ * used for the first [EMAIL PROTECTED] @}Assisted constructor parameter, 
etc..  
Annotation names have no
+ * effect.
+ *
+ * <p>Returned values are <strong>not created by Guice</strong>. These  
types are not eligible for
+ * method interception. They do receive post-construction member injection.
   *
   * @param <F> The factory interface
- * @param <R> The concrete class to be created.
   *
   * @author [EMAIL PROTECTED] (Jerome Mourits)
   * @author [EMAIL PROTECTED] (Jesse Wilson)
+ * @author [EMAIL PROTECTED] (Daniel Martin)
   */
-public class FactoryProvider<F, R> implements Provider<F> {
+public class FactoryProvider<F> implements Provider<F> {
+
+  /*
+   * This class implements the old @AssistedInject implementation that  
manually matches constructors
+   * to factory methods. The new child injector implementation lives in  
FactoryProvider2.
+   */

    private Injector injector;

    private final Class<F> factoryType;
-  private final Class<R> implementationType;
    private final Map<Method, AssistedConstructor<?>>  
factoryMethodToConstructor;

-  public static <X,Y> FactoryProvider<X,Y> newFactory(
-      Class<X> factoryType, Class<Y> implementationType){
-    return new FactoryProvider<X, Y>(factoryType,implementationType);
+  public static <F> Provider<F> newFactory(
+      Class<F> factoryType, Class<?> implementationType){
+    Map<Method, AssistedConstructor<?>> factoryMethodToConstructor
+        = createMethodMapping(factoryType, implementationType);
+
+    if (!factoryMethodToConstructor.isEmpty()) {
+      return new FactoryProvider<F>(factoryType,  
factoryMethodToConstructor);
+    } else {
+      return new FactoryProvider2<F>(factoryType,  
Key.get(implementationType));
+    }
    }

-  private FactoryProvider(Class<F> factoryType, Class<R>  
implementationType) {
+  private FactoryProvider(Class<F> factoryType,
+      Map<Method, AssistedConstructor<?>> factoryMethodToConstructor) {
      this.factoryType = factoryType;
-    this.implementationType = implementationType;
-    this.factoryMethodToConstructor = createMethodMapping();
+    this.factoryMethodToConstructor = factoryMethodToConstructor;
      checkDeclaredExceptionsMatch();
    }

@@ -150,7 +206,8 @@
    }

    @SuppressWarnings({"unchecked"})
-  private Map<Method, AssistedConstructor<?>> createMethodMapping() {
+  private static Map<Method, AssistedConstructor<?>> createMethodMapping(
+      Class<?> factoryType, Class<?> implementationType) {
      List<AssistedConstructor<?>> constructors = Lists.newArrayList();

      for (Constructor<?> c : implementationType.getDeclaredConstructors()) {
@@ -159,6 +216,10 @@
        }
      }

+    if (constructors.isEmpty()) {
+      return ImmutableMap.of();
+    }
+
      if (constructors.size() != factoryType.getMethods().length) {
        throw newConfigurationException("Constructor mismatch: %s has %s  
@AssistedInject "
            + "constructors, factory %s has %s creation methods",  
implementationType.getSimpleName(),
@@ -188,6 +249,19 @@
              + "@Assisted parameters %s in that order. @AssistInject  
constructors are %s",
              implementationType, methodParams,  
paramsToConstructor.values());
        }
+
+      method.getParameterAnnotations();
+      for (Annotation[] parameterAnnotations :  
method.getParameterAnnotations()) {
+        for (Annotation parameterAnnotation : parameterAnnotations) {
+          if (parameterAnnotation.annotationType() == Assisted.class) {
+            throw newConfigurationException("Factory method %s has an  
@Assisted parameter, which "
+                + "is incompatible with the deprecated @AssistedInject  
annotation. Please replace "
+                + "@AssistedInject with @Inject on the %s constructor.",
+                method, implementationType);
+          }
+        }
+      }
+
        AssistedConstructor matchingConstructor =  
paramsToConstructor.remove(methodParams);

        result.put(method, matchingConstructor);
@@ -204,8 +278,7 @@
          }

          AssistedConstructor<?> constructor =  
factoryMethodToConstructor.get(method);
-        Object[] constructorArgs = gatherArgsForConstructor(
-            constructor, creationArgs);
+        Object[] constructorArgs = gatherArgsForConstructor(constructor,  
creationArgs);
          Object objectToReturn = constructor.newInstance(constructorArgs);
          injector.injectMembers(objectToReturn);
          return objectToReturn;
@@ -235,7 +308,7 @@
          new Class[] {factoryType}, invocationHandler));
    }

-  private ConfigurationException newConfigurationException(String format,  
Object... args) {
+  private static ConfigurationException newConfigurationException(String  
format, Object... args) {
      return new ConfigurationException(ImmutableSet.of(new  
Message(Errors.format(format, args))));
    }
  }

Copied:  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
  
(from r714,  
/trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Factories.java)
==============================================================================
---  
/trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Factories.java
     
(original)
+++  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
       
Mon Dec  8 22:26:00 2008
@@ -38,25 +38,24 @@
  import com.google.inject.spi.Message;
  import com.google.inject.util.Providers;
  import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
  import java.lang.reflect.Type;
  import java.util.Arrays;
-import net.sf.cglib.proxy.Enhancer;
-import net.sf.cglib.proxy.InvocationHandler;
+

  /**
- * Static utility methods for creating and working with factory interfaces.
+ * The newer implementation of factory provider. This implementation uses  
a child injector to
+ * create values.
   *
- * @author [EMAIL PROTECTED] (Jerome Mourits)
   * @author [EMAIL PROTECTED] (Jesse Wilson)
   * @author [EMAIL PROTECTED] (Daniel Martin)
   */
-public final class Factories {
-  private Factories() {}
-
-  private static final Class[] ONLY_RIH = { RealInvocationHandler.class };
+final class FactoryProvider2<F> implements InvocationHandler, Provider<F> {

-  static final Assisted DEFAULT_ASSISTED = new Assisted() {
+  /** if a factory method parameter isn't annotated, it gets this  
annotation. */
+  static final Assisted DEFAULT_ANNOTATION = new Assisted() {
      public String value() {
        return "";
      }
@@ -79,268 +78,158 @@
      }
    };

-  /**
-   * Returns a factory that combines caller-provided parameters with  
injector-provided values when
-   * constructing objects.
-   *
-   * <h3>Defining a Factory</h3>
-   * [EMAIL PROTECTED] factoryInterface} is an interface whose methods return 
the  
constructed type, or its
-   * supertypes. The method's parameters are the arguments required to  
build the constructed type.
-   *
-   * <pre>
-   * public interface PaymentFactory {
-   *   Payment create(Date startDate, Money amount);
-   * } </pre>
-   *
-   * You can name your factory methods whatever you like, such as  
<i>create</i>,
-   * <i>createPayment</i> or <i>newPayment</i>.  You may include multiple  
factory methods in the
-   * same interface but they must all construct the same type.
-   *
-   * <h3>Creating a type that accepts factory parameters</h3>
-   * [EMAIL PROTECTED] constructedType} is a concrete class with an [EMAIL 
PROTECTED]  
@[EMAIL PROTECTED] Inject}-annotated
-   * constructor. In addition to injector-provided parameters, the  
constructor should have
-   * parameters that match each of the factory method's parameters. Each  
factory-provided parameter
-   * requires an [EMAIL PROTECTED] @[EMAIL PROTECTED] Assisted} annotation. 
This serves to  
document that the parameter
-   * is not bound in the injector.
-   *
-   * <pre>
-   * public class RealPayment implements Payment {
-   *   [EMAIL PROTECTED] @}Inject
-   *   public RealPayment(
-   *      CreditService creditService,
-   *      AuthService authService,
-   *      <strong>[EMAIL PROTECTED] @}Assisted Date startDate</strong>,
-   *      <strong>[EMAIL PROTECTED] @}Assisted Money amount</strong>) {
-   *     ...
-   *   }
-   * }</pre>
-   *
-   * <h3>Configuring factories</h3>
-   * In your [EMAIL PROTECTED] com.google.inject.Module module}, bind the 
factory  
interface to the returned
-   * factory:
-   *
-   * <pre>
-   * bind(PaymentFactory.class).toInstance(
-   *     Factories.create(PaymentFactory.class, RealPayment.class));</pre>
-   * As a side-effect of this binding, Guice will inject the factory to  
initialize it for use. The
-   * factory cannot be used until it has been initialized.
-   *
-   * <h3>Using the Factory</h3>
-   * Inject your factory into your application classes. When you use the  
factory, your arguments
-   * will be combined with values from the injector to produce a concrete  
instance.
-   *
-   * <pre>
-   * public class PaymentAction {
-   *   [EMAIL PROTECTED] @}Inject private PaymentFactory paymentFactory;
-   *
-   *   public void doPayment(Money amount) {
-   *     Payment payment = paymentFactory.create(new Date(), amount);
-   *     payment.apply();
-   *   }
-   * }</pre>
-   *
-   * <h3>Making Parameter Types Distinct</h3>
-   * The types of the factory method's parameters must be distinct. To use  
multiple parameters of
-   * the same type, use a named [EMAIL PROTECTED] @[EMAIL PROTECTED] Assisted} 
annotation to  
disambiguate the
-   * parameters. The names must be applied to the factory method's  
parameters:
-   *
-   * <pre>
-   * public interface PaymentFactory {
-   *   Payment create(
-   *       <strong>[EMAIL PROTECTED] @}Assisted("startDate")</strong> Date  
startDate,
-   *       <strong>[EMAIL PROTECTED] @}Assisted("dueDate")</strong> Date 
dueDate,
-   *       Money amount);
-   * } </pre>
-   * ...and to the concrete type's constructor parameters:
-   * <pre>
-   * public class RealPayment implements Payment {
-   *   [EMAIL PROTECTED] @}Inject
-   *   public RealPayment(
-   *      CreditService creditService,
-   *      AuthService authService,
-   *      <strong>[EMAIL PROTECTED] @}Assisted("startDate")</strong> Date  
startDate,
-   *      <strong>[EMAIL PROTECTED] @}Assisted("dueDate")</strong> Date 
dueDate,
-   *      <strong>[EMAIL PROTECTED] @}Assisted</strong> Money amount) {
-   *     ...
-   *   }
-   * }</pre>
-   *
-   * <h3>MethodInterceptor support</h3>
-   * Returned factories delegate to the injector to construct returned  
values. The values are
-   * eligible for method interception.
-   *
-   * @param factoryInterface a Java interface that defines one or more  
create methods.
-   * @param constructedType a concrete type that is assignable to the  
return types of all factory
-   *     methods.
-   */
-  public static <F> F create(Class<F> factoryInterface, Class<?>  
constructedType) {
-    RealInvocationHandler<F> invocationHandler
-        = new RealInvocationHandler<F>(factoryInterface,  
Key.get(constructedType));
-    Enhancer enhancer = new Enhancer();
-    enhancer.setSuperclass(Base.class);
-    enhancer.setInterfaces(new Class[] { factoryInterface });
-    enhancer.setCallback(invocationHandler);
-    return factoryInterface.cast(enhancer.create(ONLY_RIH, new Object[] {  
invocationHandler }));
-  }
+  /** the produced type, or null if all methods return concrete types */
+  private final Key<?> producedType;
+  private final ImmutableMap<Method, Key<?>> returnTypesByMethod;
+  private final ImmutableMultimap<Method, Key<?>> paramTypes;
+
+  /** the hosting injector, or null if we haven't been initialized yet */
+  private Injector injector;
+
+  /** the factory interface, implemented and provided */
+  private final F factory;

    /**
-   * Generated factories extend this class, which gives us a hook to get  
injected by Guice. Normal
-   * Java proxies can't be injected, so we use cglib.
+   * @param factoryType a Java interface that defines one or more create  
methods.
+   * @param producedType a concrete type that is assignable to the return  
types of all factory
+   *      methods.
     */
-  private static class Base {
-    private final RealInvocationHandler<?> invocationHandler;
+  FactoryProvider2(Class<F> factoryType, Key<?> producedType) {
+    this.producedType = producedType;

-    protected Base(RealInvocationHandler<?> invocationHandler) {
-      this.invocationHandler = invocationHandler;
+    Errors errors = new Errors();
+    try {
+      ImmutableMap.Builder<Method, Key<?>> returnTypesBuilder =  
ImmutableMap.builder();
+      ImmutableMultimap.Builder<Method, Key<?>> paramTypesBuilder =  
ImmutableMultimap.builder();
+      // TODO: also grab methods from superinterfaces
+      for (Method method : factoryType.getMethods()) {
+        Key<?> returnType =  
getKey(TypeLiteral.get(method.getGenericReturnType()),
+            method, method.getAnnotations(), errors);
+        returnTypesBuilder.put(method, returnType);
+        Type[] params = method.getGenericParameterTypes();
+        Annotation[][] paramAnnotations = method.getParameterAnnotations();
+        int p = 0;
+        for (Type param : params) {
+          Key<?> paramKey = getKey(TypeLiteral.get(param), method,  
paramAnnotations[p++], errors);
+          paramTypesBuilder.put(method, assistKey(method, paramKey,  
errors));
+        }
+      }
+      returnTypesByMethod = returnTypesBuilder.build();
+      paramTypes = paramTypesBuilder.build();
+    } catch (ErrorsException e) {
+      throw new ConfigurationException(e.getErrors().getMessages());
      }

-    @SuppressWarnings("unused")
-    @Inject private void initialize(Injector injector) {
-      invocationHandler.initialize(injector);
-    }
+    factory =  
factoryType.cast(Proxy.newProxyInstance(factoryType.getClassLoader(),
+        new Class[] { factoryType }, this));
    }

-  // TODO: also grab methods from superinterfaces
+  public F get() {
+    return factory;
+  }

-  private static class RealInvocationHandler<F> implements  
InvocationHandler {
-    /** the produced type, or null if all methods return concrete types */
-    private final Key<?> producedType;
-    private final ImmutableMap<Method, Key<?>> returnTypesByMethod;
-    private final ImmutableMultimap<Method, Key<?>> paramTypes;
-
-    /** the hosting injector, or null if we haven't been initialized yet */
-    private Injector injector;
-
-    private RealInvocationHandler(Class<F> factoryType, Key<?>  
producedType) {
-      this.producedType = producedType;
-
-      Errors errors = new Errors();
-      try {
-        ImmutableMap.Builder<Method, Key<?>> returnTypesBuilder =  
ImmutableMap.builder();
-        ImmutableMultimap.Builder<Method, Key<?>> paramTypesBuilder =  
ImmutableMultimap.builder();
-        for (Method method : factoryType.getMethods()) {
-          Key<?> returnType =  
getKey(TypeLiteral.get(method.getGenericReturnType()),
-              method, method.getAnnotations(), errors);
-          returnTypesBuilder.put(method, returnType);
-          Type[] params = method.getGenericParameterTypes();
-          Annotation[][] paramAnnotations =  
method.getParameterAnnotations();
-          int p = 0;
-          for (Type param : params) {
-            Key<?> paramKey = getKey(TypeLiteral.get(param), method,  
paramAnnotations[p++], errors);
-            paramTypesBuilder.put(method, assistKey(method, paramKey,  
errors));
-          }
-        }
-        returnTypesByMethod = returnTypesBuilder.build();
-        paramTypes = paramTypesBuilder.build();
-      } catch (ErrorsException e) {
-        throw new ConfigurationException(e.getErrors().getMessages());
-      }
+  /**
+   * Returns a key similar to [EMAIL PROTECTED] key}, but with an [EMAIL 
PROTECTED]  
@}Assisted binding annotation.
+   * This fails if another binding annotation is clobbered in the process.  
If the key already has
+   * the [EMAIL PROTECTED] @}Assisted annotation, it is returned as-is to 
preserve  
any String value.
+   */
+  private <T> Key<T> assistKey(Method method, Key<T> key, Errors errors)  
throws ErrorsException {
+    if (key.getAnnotationType() == null) {
+      return Key.get(key.getTypeLiteral(), DEFAULT_ANNOTATION);
+    } else if (key.getAnnotationType() == Assisted.class) {
+      return key;
+    } else {
+      errors.withSource(method).addMessage(
+          "Only @Assisted is allowed for factory parameters, but found  
@%s",
+          key.getAnnotationType());
+      throw errors.toException();
      }
+  }

-    /**
-     * Returns a key similar to [EMAIL PROTECTED] key}, but with an [EMAIL 
PROTECTED]  
@}Assisted binding annotation.
-     * This fails if another binding annotation is clobbered in the  
process. If the key already has
-     * the [EMAIL PROTECTED] @}Assisted annotation, it is returned as-is to  
preserve any String value.
-     */
-    private <T> Key<T> assistKey(Method method, Key<T> key, Errors errors)  
throws ErrorsException {
-      if (key.getAnnotationType() == null) {
-        return Key.get(key.getTypeLiteral(), DEFAULT_ASSISTED);
-      } else if (key.getAnnotationType() == Assisted.class) {
-        return key;
-      } else {
-        errors.withSource(method).addMessage(
-            "Only @Assisted is allowed for factory parameters, but found  
@%s",
-            key.getAnnotationType());
-        throw errors.toException();
-      }
+  /**
+   * At injector-creation time, we initialize the invocation handler. At  
this time we make sure
+   * all factory methods will be able to build the target types.
+   */
+  @Inject
+  void initialize(Injector injector) {
+    if (this.injector != null) {
+      throw new ConfigurationException(ImmutableList.of(new  
Message(FactoryProvider2.class,
+          "Factories.create() factories may only be used in one  
Injector!")));
      }

-    /**
-     * At injector-creation time, we initialize the invocation handler. At  
this time we make sure
-     * all factory methods will be able to build the target types.
-     */
-    void initialize(Injector injector) {
-      if (this.injector != null) {
-        throw new ConfigurationException(ImmutableList.of(new  
Message(Factories.class,
-            "Factories.create() factories may only be used in one  
Injector!")));
-      }
+    this.injector = injector;
+
+    for (Method method : returnTypesByMethod.keySet()) {
+      Object[] args = new Object[method.getParameterTypes().length];
+      Arrays.fill(args, "dummy object for validating Factories");
+      getBindingFromNewInjector(method, args); // throws if the binding  
isn't properly configured
+    }
+  }

-      this.injector = injector;
+  /**
+   * Creates a child injector that binds the args, and returns the binding  
for the method's result.
+   */
+  public Binding<?> getBindingFromNewInjector(final Method method, final  
Object[] args) {
+    checkState(injector != null,
+        "Factories.create() factories cannot be used until they're  
initialized by Guice.");
+
+    final Key<?> returnType = returnTypesByMethod.get(method);
+
+    Module assistedModule = new AbstractModule() {
+      @SuppressWarnings("unchecked") // raw keys are necessary for the  
args array and return value
+      protected void configure() {
+        Binder binder = binder().withSource(method);
+
+        int p = 0;
+        for (Key<?> paramKey : paramTypes.get(method)) {
+          // Wrap in a Provider to cover null, and to prevent Guice from  
injecting the parameter
+          binder.bind((Key) paramKey).toProvider(Providers.of(args[p++]));
+        }

-      for (Method method : returnTypesByMethod.keySet()) {
-        Object[] args = new Object[method.getParameterTypes().length];
-        Arrays.fill(args, "dummy object for validating Factories");
-        getBindingFromNewInjector(method, args); // throws if the binding  
isn't properly configured
+        if (producedType != null && !returnType.equals(producedType)) {
+          binder.bind(returnType).to((Key) producedType);
+        } else {
+          binder.bind(returnType);
+        }
        }
-    }
+    };

-    /**
-     * Creates a child injector that binds the args, and returns the  
binding for the method's
-     * result.
-     */
-    public Binding<?> getBindingFromNewInjector(final Method method, final  
Object[] args) {
-      checkState(injector != null,
-          "Factories.create() factories cannot be used until they're  
initialized by Guice.");
-
-      final Key<?> returnType = returnTypesByMethod.get(method);
-
-      Module assistedModule = new AbstractModule() {
-        @SuppressWarnings("unchecked") // raw keys are necessary for the  
args array and return value
-        protected void configure() {
-          Binder binder = binder().withSource(method);
-
-          int p = 0;
-          for (Key<?> paramKey : paramTypes.get(method)) {
-            // Wrap in a Provider to cover null, and to prevent Guice from  
injecting the parameter
-            binder.bind((Key)  
paramKey).toProvider(Providers.of(args[p++]));
-          }
-
-          if (producedType != null && !returnType.equals(producedType)) {
-            binder.bind(returnType).to((Key) producedType);
-          } else {
-            binder.bind(returnType);
-          }
-        }
-      };
+    Injector forCreate = injector.createChildInjector(assistedModule);
+    return forCreate.getBinding(returnType);
+  }

-      Injector forCreate = injector.createChildInjector(assistedModule);
-      return forCreate.getBinding(returnType);
+  /**
+   * When a factory method is invoked, we create a child injector that  
binds all parameters, then
+   * use that to get an instance of the return type.
+   */
+  public Object invoke(Object proxy, final Method method, final Object[]  
args) throws Throwable {
+    if (method.getDeclaringClass() == Object.class) {
+      return method.invoke(this, args);
      }

-    /**
-     * When a factory method is invoked, we create a child injector that  
binds all parameters, then
-     * use that to get an instance of the return type.
-     */
-    public Object invoke(Object proxy, final Method method, final Object[]  
args) throws Throwable {
-      if (method.getDeclaringClass() == Object.class) {
-        return method.invoke(this, args);
-      }
-
-      Provider<?> provider = getBindingFromNewInjector(method,  
args).getProvider();
-      try {
-        return provider.get();
-      } catch (ProvisionException e) {
-        // if this is an exception declared by the factory method, throw  
it as-is
-        if (e.getErrorMessages().size() == 1) {
-          Message onlyError = getOnlyElement(e.getErrorMessages());
-          Throwable cause = onlyError.getCause();
-          if (cause != null && canRethrow(method, cause)) {
-            throw cause;
-          }
+    Provider<?> provider = getBindingFromNewInjector(method,  
args).getProvider();
+    try {
+      return provider.get();
+    } catch (ProvisionException e) {
+      // if this is an exception declared by the factory method, throw it  
as-is
+      if (e.getErrorMessages().size() == 1) {
+        Message onlyError = getOnlyElement(e.getErrorMessages());
+        Throwable cause = onlyError.getCause();
+        if (cause != null && canRethrow(method, cause)) {
+          throw cause;
          }
-        throw e;
        }
+      throw e;
      }
+  }

-    @Override public String toString() {
-      return "Factory";
-    }
+  @Override public String toString() {
+    return factory.getClass().getInterfaces()[0].getName()
+        + " for " + producedType.getTypeLiteral();
+  }

-    @Override public boolean equals(Object o) {
-      // this equals() is wacky; we pretend it's defined on the Proxy  
object rather than here
-      return o instanceof Base
-          && ((Base) o).invocationHandler == this;
-    }
+  @Override public boolean equals(Object o) {
+    return o == this || o == factory;
    }

    /** Returns true if [EMAIL PROTECTED] thrown} can be thrown by [EMAIL 
PROTECTED] invoked}  
without wrapping. */

Copied:  
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java
  
(from r714,  
/trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoriesTest.java)
==============================================================================
---  
/trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoriesTest.java
        
(original)
+++  
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java
  
Mon Dec  8 22:26:00 2008
@@ -37,15 +37,15 @@
  import org.aopalliance.intercept.MethodInterceptor;
  import org.aopalliance.intercept.MethodInvocation;

-public class FactoriesTest extends TestCase {
+public class FactoryProvider2Test extends TestCase {

    public void testAssistedFactory() {
      Injector injector = Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
          bind(Double.class).toInstance(5.0d);
-        bind(ColoredCarFactory.class).toInstance(
-            Factories.create(ColoredCarFactory.class, Mustang.class));
+        bind(ColoredCarFactory.class).toProvider(
+            FactoryProvider.newFactory(ColoredCarFactory.class,  
Mustang.class));
        }
      });
      ColoredCarFactory carFactory =  
injector.getInstance(ColoredCarFactory.class);
@@ -65,8 +65,8 @@
        protected void configure() {
           
bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250);
           
bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984);
-        bind(ColoredCarFactory.class).toInstance(
-            Factories.create(ColoredCarFactory.class, Camaro.class));
+        bind(ColoredCarFactory.class).toProvider(
+            FactoryProvider.newFactory(ColoredCarFactory.class,  
Camaro.class));
        }
      });

@@ -99,9 +99,7 @@
        this.color = color;
      }

-    public String drive() {
-      return "vroom!";
-    }
+    public void drive() {}
    }

    public static class Camaro implements Car {
@@ -124,13 +122,13 @@
      Car create(Color color, boolean convertable);
    }

-  public void testFactoryWithMultipleMethods() {
+  public void testFactoryUsesInjectedConstructor() {
      Injector injector = Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
          bind(float.class).toInstance(140f);
-        bind(SummerCarFactory.class).toInstance(
-            Factories.create(SummerCarFactory.class, Corvette.class));
+        bind(SummerCarFactory.class).toProvider(
+            FactoryProvider.newFactory(SummerCarFactory.class,  
Corvette.class));
        }
      });

@@ -162,8 +160,8 @@
    public void testConstructorDoesntNeedAllFactoryMethodArguments() {
      Injector injector = Guice.createInjector(new AbstractModule() {
        protected void configure() {
-        bind(SummerCarFactory.class).toInstance(
-            Factories.create(SummerCarFactory.class, Beetle.class));
+        bind(SummerCarFactory.class).toProvider(
+            FactoryProvider.newFactory(SummerCarFactory.class,  
Beetle.class));
        }
      });
      SummerCarFactory factory =  
injector.getInstance(SummerCarFactory.class);
@@ -187,8 +185,8 @@
          bind(String.class).toInstance("turbo");
          bind(int.class).toInstance(911);
          bind(double.class).toInstance(50000d);
-        bind(ColoredCarFactory.class).toInstance(
-            Factories.create(ColoredCarFactory.class, Porshe.class));
+        bind(ColoredCarFactory.class).toProvider(
+            FactoryProvider.newFactory(ColoredCarFactory.class,  
Porshe.class));
        }
      });
      ColoredCarFactory carFactory =  
injector.getInstance(ColoredCarFactory.class);
@@ -222,8 +220,8 @@
        @Override
        protected void configure() {
          bind(String.class).toInstance("trans am");
-        bind(ColoredCarFactory.class).toInstance(
-            Factories.create(ColoredCarFactory.class, Firebird.class));
+        bind(ColoredCarFactory.class).toProvider(
+            FactoryProvider.newFactory(ColoredCarFactory.class,  
Firebird.class));
        }
      });
      ColoredCarFactory carFactory =  
injector.getInstance(ColoredCarFactory.class);
@@ -250,8 +248,8 @@
        protected void configure() {
          bind(new TypeLiteral<Set<String>>()  
{}).toInstance(Collections.singleton("Flux Capacitor"));
          bind(new TypeLiteral<Set<Integer>>()  
{}).toInstance(Collections.singleton(88));
-        bind(ColoredCarFactory.class).toInstance(
-            Factories.create(ColoredCarFactory.class, DeLorean.class));
+        bind(ColoredCarFactory.class).toProvider(
+            FactoryProvider.newFactory(ColoredCarFactory.class,  
DeLorean.class));
        }
      });
      ColoredCarFactory carFactory =  
injector.getInstance(ColoredCarFactory.class);
@@ -281,8 +279,8 @@
        @Override
        protected void configure() {
          bind(new TypeLiteral<Set<String>>() {  
}).toInstance(Collections.singleton("Datsun"));
-        bind(ColoredCarFactory.class).toInstance(
-            Factories.create(ColoredCarFactory.class, Z.class));
+        bind(ColoredCarFactory.class).toProvider(
+            FactoryProvider.newFactory(ColoredCarFactory.class, Z.class));
        }
      });
      ColoredCarFactory carFactory =  
injector.getInstance(ColoredCarFactory.class);
@@ -317,8 +315,8 @@
      Injector injector = Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
-        bind(ColoredCarFactory.class).toInstance(
-            Factories.create(ColoredCarFactory.class, Prius.class));
+        bind(ColoredCarFactory.class).toProvider(
+            FactoryProvider.newFactory(ColoredCarFactory.class,  
Prius.class));
        }
      });
      Car car =  
injector.getInstance(ColoredCarFactory.class).create(Color.ORANGE);
@@ -335,8 +333,8 @@
      Injector injector = Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
-        bind(ColoredCarFactory.class).toInstance(
-            Factories.create(ColoredCarFactory.class, ExplodingCar.class));
+        bind(ColoredCarFactory.class).toProvider(
+            FactoryProvider.newFactory(ColoredCarFactory.class,  
ExplodingCar.class));
        }
      });
      try {
@@ -373,8 +371,8 @@
      Injector injector = Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
-        bind(CorrectDefectiveCarFactory.class).toInstance(
-            Factories.create(CorrectDefectiveCarFactory.class,  
DefectiveCar.class));
+        bind(CorrectDefectiveCarFactory.class).toProvider(
+            FactoryProvider.newFactory(CorrectDefectiveCarFactory.class,  
DefectiveCar.class));
        }
      });
      try {
@@ -386,13 +384,6 @@
      }
    }

-  public static class MultipleConstructorDefectiveCar implements Car {
-    @Inject
-    public MultipleConstructorDefectiveCar(@Assisted Color c) throws  
FireException {
-      throw new FireException();
-    }
-  }
-
    public static class WildcardCollection {

      public interface Factory {
@@ -407,8 +398,8 @@
      Injector injector = Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
-        bind(WildcardCollection.Factory.class).toInstance(
-            Factories.create(WildcardCollection.Factory.class,  
WildcardCollection.class));
+        bind(WildcardCollection.Factory.class).toProvider(
+            FactoryProvider.newFactory(WildcardCollection.Factory.class,  
WildcardCollection.class));
        }
      });
      WildcardCollection.Factory factory =  
injector.getInstance(WildcardCollection.Factory.class);
@@ -434,8 +425,8 @@
      Injector injector = Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
-        bind(ColoredCarFactory.class).toInstance(
-            Factories.create(ColoredCarFactory.class, Fiat.class));
+        bind(ColoredCarFactory.class).toProvider(
+            FactoryProvider.newFactory(ColoredCarFactory.class,  
Fiat.class));
        }
      });

@@ -449,15 +440,15 @@
      try {
        Guice.createInjector(new AbstractModule() {
          @Override protected void configure() {
-          bind(ColoredCarFactory.class).toInstance(
-              Factories.create(ColoredCarFactory.class, Mustang.class));
+          bind(ColoredCarFactory.class).toProvider(
+              FactoryProvider.newFactory(ColoredCarFactory.class,  
Mustang.class));
          }
        });
        fail();
      } catch (CreationException expected) {
        assertContains(expected.getMessage(),
            "Could not find a suitable constructor in java.lang.Double.",
-          "at " + ColoredCarFactory.class.getName()  
+ ".create(FactoriesTest.java");
+          "at " + ColoredCarFactory.class.getName()  
+ ".create(FactoryProvider2Test.java");
      }
    }

@@ -465,15 +456,16 @@
      Injector injector = Guice.createInjector(new AbstractModule() {
          @Override protected void configure() {
            bind(Double.class).toInstance(5.0d);
-          bind(ColoredCarFactory.class).toInstance(
-              Factories.create(ColoredCarFactory.class, Mustang.class));
+          bind(ColoredCarFactory.class).toProvider(
+              FactoryProvider.newFactory(ColoredCarFactory.class,  
Mustang.class));
          }
        });

      ColoredCarFactory carFactory =  
injector.getInstance(ColoredCarFactory.class);

      assertEqualsBothWays(carFactory, carFactory);
-    assertEquals("Factory", carFactory.toString());
+    assertEquals(ColoredCarFactory.class.getName() + " for " +  
Mustang.class.getName(),
+        carFactory.toString());
    }

    static class Subaru implements Car {
@@ -483,8 +475,8 @@
    public void testInjectingProviderOfParameter() {
      Injector injector = Guice.createInjector(new AbstractModule() {
          @Override protected void configure() {
-          bind(ColoredCarFactory.class).toInstance(
-              Factories.create(ColoredCarFactory.class, Subaru.class));
+          bind(ColoredCarFactory.class).toProvider(
+              FactoryProvider.newFactory(ColoredCarFactory.class,  
Subaru.class));
          }
        });

@@ -498,8 +490,8 @@
    public void testInjectingNullParameter() {
      Injector injector = Guice.createInjector(new AbstractModule() {
          @Override protected void configure() {
-          bind(ColoredCarFactory.class).toInstance(
-              Factories.create(ColoredCarFactory.class, Subaru.class));
+          bind(ColoredCarFactory.class).toProvider(
+              FactoryProvider.newFactory(ColoredCarFactory.class,  
Subaru.class));
          }
        });

@@ -511,7 +503,8 @@
    }

    public void testFactoryUseBeforeInitialization() {
-    ColoredCarFactory carFactory =  
Factories.create(ColoredCarFactory.class, Subaru.class);
+    ColoredCarFactory carFactory =  
FactoryProvider.newFactory(ColoredCarFactory.class, Subaru.class)
+        .get();
      try {
        carFactory.create(Color.RED);
        fail();
@@ -530,8 +523,8 @@
        protected void configure() {
          bind(double.class).toInstance(5.0d);
          // note there is no 'thatMakes()' call here:
-        bind(MustangFactory.class).toInstance(
-            Factories.create(MustangFactory.class, Mustang.class));
+        bind(MustangFactory.class).toProvider(
+            FactoryProvider.newFactory(MustangFactory.class,  
Mustang.class));
        }
      });
      MustangFactory factory = injector.getInstance(MustangFactory.class);
@@ -557,8 +550,8 @@
          bind(double.class).toInstance(5.0d);
           
bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250);
           
bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984);
-        FleetFactory fleetFactory = Factories.create(FleetFactory.class,  
Fleet.class);
-        bind(FleetFactory.class).toInstance(fleetFactory);
+         
bind(FleetFactory.class).toProvider(FactoryProvider.newFactory(FleetFactory.class,
+            Fleet.class));
        }
      });

@@ -585,8 +578,8 @@
      Injector injector = Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
-        bind(TwoToneCarFactory.class).toInstance(
-            Factories.create(TwoToneCarFactory.class, Maxima.class));
+        bind(TwoToneCarFactory.class).toProvider(
+            FactoryProvider.newFactory(TwoToneCarFactory.class,  
Maxima.class));
        }
      });

@@ -596,6 +589,25 @@
      assertSame(Color.GRAY, maxima.fabric);
    }

+  interface DoubleToneCarFactory {
+    Car create(@Assisted("paint") Color paint, @Assisted("paint") Color  
morePaint);
+  }
+
+  public void testDuplicateKeys() {
+    try {
+      Guice.createInjector(new AbstractModule() {
+        @Override protected void configure() {
+          bind(DoubleToneCarFactory.class).toProvider(
+              FactoryProvider.newFactory(DoubleToneCarFactory.class,  
Maxima.class));
+        }
+      });
+      fail();
+    } catch (CreationException expected) {
+      assertContains(expected.getMessage(), "A binding to java.awt.Color  
annotated with @"
+          + Assisted.class.getName() + "(value=paint) was already  
configured at");
+    }
+  }
+
    public void testMethodInterceptorsOnAssistedTypes() {
      final AtomicInteger invocationCount = new AtomicInteger();
      final MethodInterceptor interceptor = new MethodInterceptor() {
@@ -610,8 +622,8 @@
        protected void configure() {
          bindInterceptor(Matchers.any(), Matchers.any(), interceptor);
          bind(Double.class).toInstance(5.0d);
-        bind(ColoredCarFactory.class).toInstance(
-            Factories.create(ColoredCarFactory.class, Mustang.class));
+        bind(ColoredCarFactory.class).toProvider(
+            FactoryProvider.newFactory(ColoredCarFactory.class,  
Mustang.class));
        }
      });

@@ -623,7 +635,7 @@
    }

    public void testDefaultAssistedAnnotation() throws NoSuchFieldException {
-    assertEqualsBothWays(Factories.DEFAULT_ASSISTED,
+    assertEqualsBothWays(FactoryProvider2.DEFAULT_ANNOTATION,
           
Subaru.class.getDeclaredField("colorProvider").getAnnotation(Assisted.class));
    }
  }

Modified:  
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProviderTest.java
==============================================================================
---  
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProviderTest.java
   
(original)
+++  
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProviderTest.java
   
Mon Dec  8 22:26:00 2008
@@ -536,5 +536,24 @@
      carFactory.toString();
    }

-  // TODO(jessewilson): test for duplicate constructors
+  public void  
testAssistedInjectConstructorAndAssistedFactoryParameterMustNotMix() {
+    try {
+      Guice.createInjector(new AbstractModule() {
+        @Override protected void configure() {
+          bind(Double.class).toInstance(5.0d);
+          bind(AssistedParamsFactory.class)
+              
.toProvider(FactoryProvider.newFactory(AssistedParamsFactory.class,  
Mustang.class));
+        }
+      });
+      fail();
+    } catch (CreationException expected) {
+      assertContains(expected.getMessage(), "Factory method "
+          + AssistedParamsFactory.class.getName() + ".create() has an  
@Assisted parameter, which "
+          + "is incompatible with the deprecated @AssistedInject  
annotation.");
+    }
+  }
+
+  interface AssistedParamsFactory {
+    Car create(@Assisted Color color);
+  }
  }

Modified: trunk/src/com/google/inject/spi/InjectionPoint.java
==============================================================================
--- trunk/src/com/google/inject/spi/InjectionPoint.java (original)
+++ trunk/src/com/google/inject/spi/InjectionPoint.java Mon Dec  8 22:26:00  
2008
@@ -356,9 +356,9 @@
    }

    private static <M extends Member & AnnotatedElement> void  
addInjectorsForMembers(
-      TypeLiteral<?> typeResolver, Factory<M> factory, boolean statics,
+      TypeLiteral<?> typeLiteral, Factory<M> factory, boolean statics,
        Collection<InjectionPoint> injectionPoints, Errors errors) {
-    for (M member :  
factory.getMembers(getRawType(typeResolver.getType()))) {
+    for (M member : factory.getMembers(getRawType(typeLiteral.getType())))  
{
        if (isStatic(member) != statics) {
          continue;
        }
@@ -369,7 +369,7 @@
        }

        try {
-        injectionPoints.add(factory.create(typeResolver, member, errors));
+        injectionPoints.add(factory.create(typeLiteral, member, errors));
        } catch (ConfigurationException ignorable) {
          if (!inject.optional()) {
            errors.merge(ignorable.getErrorMessages());
@@ -387,8 +387,8 @@
        public Field[] getMembers(Class<?> type) {
          return type.getDeclaredFields();
        }
-      public InjectionPoint create(TypeLiteral<?> typeResolver, Field  
member, Errors errors) {
-        return new InjectionPoint(typeResolver, member);
+      public InjectionPoint create(TypeLiteral<?> typeLiteral, Field  
member, Errors errors) {
+        return new InjectionPoint(typeLiteral, member);
        }
      };

@@ -396,14 +396,14 @@
        public Method[] getMembers(Class<?> type) {
          return type.getDeclaredMethods();
        }
-      public InjectionPoint create(TypeLiteral<?> typeResolver, Method  
member, Errors errors) {
+      public InjectionPoint create(TypeLiteral<?> typeLiteral, Method  
member, Errors errors) {
          checkForMisplacedBindingAnnotations(member, errors);
-        return new InjectionPoint(typeResolver, member);
+        return new InjectionPoint(typeLiteral, member);
        }
      };

      M[] getMembers(Class<?> type);
-    InjectionPoint create(TypeLiteral<?> typeResolver, M member, Errors  
errors);
+    InjectionPoint create(TypeLiteral<?> typeLiteral, M member, Errors  
errors);
    }

    private static final long serialVersionUID = 0;

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"google-guice-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/google-guice-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to