Author: limpbizkit
Date: Fri Feb 27 13:59:15 2009
New Revision: 871

Modified:
     
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/AssistedConstructor.java
     
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider.java
     
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
     
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Parameter.java
     
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java
     
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProviderTest.java

Log:
Applying ilya.firman's patch for issue 218. I tweaked the patch to use  
TypeLiteral's new type resolution methods like  
TypeLiteral.getReturnType(Method) etc., which makes it so we always just  
do-the-right-thing for matching type variables.

Modified:  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/AssistedConstructor.java
==============================================================================
---  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/AssistedConstructor.java
    
(original)
+++  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/AssistedConstructor.java
    
Fri Feb 27 13:59:15 2009
@@ -17,6 +17,8 @@
  package com.google.inject.assistedinject;

  import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+import com.google.inject.internal.Lists;
  import java.lang.annotation.Annotation;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationTargetException;
@@ -41,18 +43,17 @@
    private final List<Parameter> allParameters;

    @SuppressWarnings("unchecked")
-  public AssistedConstructor(Constructor<T> constructor) {
+  public AssistedConstructor(Constructor<T> constructor,  
List<TypeLiteral<?>> parameterTypes) {
      this.constructor = constructor;

-    Type[] parameterTypes = constructor.getGenericParameterTypes();
      Annotation[][] annotations = constructor.getParameterAnnotations();

-    List<Type> typeList = new ArrayList<Type>();
+    List<Type> typeList = Lists.newArrayList();
      allParameters = new ArrayList<Parameter>();

      // categorize params as @Assisted or @Injected
-    for (int i = 0; i < parameterTypes.length; i++) {
-      Parameter parameter = new Parameter(parameterTypes[i],  
annotations[i]);
+    for (int i = 0; i < parameterTypes.size(); i++) {
+      Parameter parameter = new Parameter(parameterTypes.get(i).getType(),  
annotations[i]);
        allParameters.add(parameter);
        if (parameter.isProvidedByFactory()) {
          typeList.add(parameter.getType());

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
        
Fri Feb 27 13:59:15 2009
@@ -21,6 +21,7 @@
  import com.google.inject.Injector;
  import com.google.inject.Key;
  import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
  import com.google.inject.internal.Errors;
  import com.google.inject.internal.ImmutableMap;
  import com.google.inject.internal.ImmutableSet;
@@ -34,6 +35,7 @@
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
@@ -144,11 +146,16 @@

    private Injector injector;

-  private final Class<F> factoryType;
+  private final TypeLiteral<F> factoryType;
    private final Map<Method, AssistedConstructor<?>>  
factoryMethodToConstructor;

    public static <F> Provider<F> newFactory(
        Class<F> factoryType, Class<?> implementationType){
+    return newFactory(TypeLiteral.get(factoryType),  
TypeLiteral.get(implementationType));
+  }
+
+  public static <F> Provider<F> newFactory(
+      TypeLiteral<F> factoryType, TypeLiteral<?> implementationType) {
      Map<Method, AssistedConstructor<?>> factoryMethodToConstructor
          = createMethodMapping(factoryType, implementationType);

@@ -159,7 +166,7 @@
      }
    }

-  private FactoryProvider(Class<F> factoryType,
+  private FactoryProvider(TypeLiteral<F> factoryType,
        Map<Method, AssistedConstructor<?>> factoryMethodToConstructor) {
      this.factoryType = factoryType;
      this.factoryMethodToConstructor = factoryMethodToConstructor;
@@ -208,14 +215,16 @@
      return parameter.isBound(injector);
    }

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

-    for (Constructor<?> c : implementationType.getDeclaredConstructors()) {
-      if (c.getAnnotation(AssistedInject.class) != null) {
-        constructors.add(new AssistedConstructor(c));
+    for (Constructor<?> constructor :  
implementationType.getRawType().getDeclaredConstructors()) {
+      if (constructor.getAnnotation(AssistedInject.class) != null) {
+        @SuppressWarnings("unchecked") // the constructor type and  
implementation type agree
+        AssistedConstructor assistedConstructor = new AssistedConstructor(
+            constructor,  
implementationType.getParameterTypes(constructor));
+        constructors.add(assistedConstructor);
        }
      }

@@ -223,10 +232,12 @@
        return ImmutableMap.of();
      }

-    if (constructors.size() != factoryType.getMethods().length) {
+    Method[] factoryMethods = factoryType.getRawType().getMethods();
+
+    if (constructors.size() != factoryMethods.length) {
        throw newConfigurationException("Constructor mismatch: %s has %s  
@AssistedInject "
-          + "constructors, factory %s has %s creation methods",  
implementationType.getSimpleName(),
-          constructors.size(), factoryType.getSimpleName(),  
factoryType.getMethods().length);
+          + "constructors, factory %s has %s creation methods",  
implementationType,
+          constructors.size(), factoryType, factoryMethods.length);
      }

      Map<ParameterListKey, AssistedConstructor> paramsToConstructor =  
Maps.newHashMap();
@@ -239,13 +250,17 @@
      }

      Map<Method, AssistedConstructor<?>> result = Maps.newHashMap();
-    for (Method method : factoryType.getMethods()) {
-      if (!method.getReturnType().isAssignableFrom(implementationType)) {
-        throw new RuntimeException(String.format("Return type of method  
\"%s\""
-            + " is not assignable from class \"%s\"", method,
-            implementationType.getName()));
+    for (Method method : factoryMethods) {
+      if  
(!method.getReturnType().isAssignableFrom(implementationType.getRawType()))  
{
+        throw newConfigurationException("Return type of method %s is not  
assignable from %s",
+            method, implementationType);
+      }
+
+      List<Type> parameterTypes = Lists.newArrayList();
+      for (TypeLiteral<?> parameterType :  
factoryType.getParameterTypes(method)) {
+        parameterTypes.add(parameterType.getType());
        }
-      ParameterListKey methodParams = new  
ParameterListKey(method.getGenericParameterTypes());
+      ParameterListKey methodParams = new ParameterListKey(parameterTypes);

        if (!paramsToConstructor.containsKey(methodParams)) {
          throw newConfigurationException("%s has no @AssistInject  
constructor that takes the "
@@ -319,8 +334,10 @@
        }
      };

-    return  
factoryType.cast(Proxy.newProxyInstance(factoryType.getClassLoader(),
-        new Class[] {factoryType}, invocationHandler));
+    @SuppressWarnings("unchecked") // we imprecisely treat the class  
literal of T as a Class<T>
+    Class<F> factoryRawType = (Class) factoryType.getRawType();
+    return  
factoryRawType.cast(Proxy.newProxyInstance(factoryRawType.getClassLoader(),
+        new Class[] { factoryRawType }, invocationHandler));
    }

    private static ConfigurationException newConfigurationException(String  
format, Object... args) {

Modified:  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
==============================================================================
---  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
       
(original)
+++  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
       
Fri Feb 27 13:59:15 2009
@@ -41,7 +41,6 @@
  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 java.util.List;

@@ -94,25 +93,29 @@
     * @param producedType a concrete type that is assignable to the return  
types of all factory
     *      methods.
     */
-  FactoryProvider2(Class<F> factoryType, Key<?> producedType) {
+  FactoryProvider2(TypeLiteral<F> factoryType, Key<?> producedType) {
      this.producedType = producedType;

      Errors errors = new Errors();
+
+    @SuppressWarnings("unchecked") // we imprecisely treat the class  
literal of T as a Class<T>
+    Class<F> factoryRawType = (Class) factoryType.getRawType();
+
      try {
        ImmutableMap.Builder<Method, Key<?>> returnTypesBuilder =  
ImmutableMap.builder();
        ImmutableMap.Builder<Method, ImmutableList<Key<?>>> paramTypesBuilder
            = ImmutableMap.builder();
        // TODO: also grab methods from superinterfaces
-      for (Method method : factoryType.getMethods()) {
-        Key<?> returnType =  
getKey(TypeLiteral.get(method.getGenericReturnType()),
-            method, method.getAnnotations(), errors);
+      for (Method method : factoryRawType.getMethods()) {
+        Key<?> returnType = getKey(
+            factoryType.getReturnType(method), method,  
method.getAnnotations(), errors);
          returnTypesBuilder.put(method, returnType);
-        Type[] params = method.getGenericParameterTypes();
+        List<TypeLiteral<?>> params =  
factoryType.getParameterTypes(method);
          Annotation[][] paramAnnotations = method.getParameterAnnotations();
          int p = 0;
          List<Key<?>> keys = Lists.newArrayList();
-        for (Type param : params) {
-          Key<?> paramKey = getKey(TypeLiteral.get(param), method,  
paramAnnotations[p++], errors);
+        for (TypeLiteral<?> param : params) {
+          Key<?> paramKey = getKey(param, method, paramAnnotations[p++],  
errors);
            keys.add(assistKey(method, paramKey, errors));
          }
          paramTypesBuilder.put(method, ImmutableList.copyOf(keys));
@@ -123,8 +126,8 @@
        throw new ConfigurationException(e.getErrors().getMessages());
      }

-    factory =  
factoryType.cast(Proxy.newProxyInstance(factoryType.getClassLoader(),
-        new Class[] { factoryType }, this));
+    factory =  
factoryRawType.cast(Proxy.newProxyInstance(factoryRawType.getClassLoader(),
+        new Class[] { factoryRawType }, this));
    }

    public F get() {

Modified:  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Parameter.java
==============================================================================
---  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Parameter.java
      
(original)
+++  
trunk/extensions/assistedinject/src/com/google/inject/assistedinject/Parameter.java
      
Fri Feb 27 13:59:15 2009
@@ -93,11 +93,10 @@
    }

    private boolean isBound(Injector injector, Key<?> key) {
-    /* This method is particularly lame - we really need an API that can  
test
-       for any binding, implicit or explicit */
+    // This method is particularly lame - we really need an API that can  
test
+    // for any binding, implicit or explicit
      try {
-      return injector.getBinding(key) != null
-          || injector.getProvider(key) != null;
+      return injector.getBinding(key) != null;
      } catch (ConfigurationException e) {
        return false;
      }
@@ -123,12 +122,12 @@
    }

    private Type getProvidedType(Type type) {
-    return ((ParameterizedType)type).getActualTypeArguments()[0];
+    return ((ParameterizedType) type).getActualTypeArguments()[0];
    }

    private boolean isProvider(Type type) {
      return type instanceof ParameterizedType
-        && ((ParameterizedType)type).getRawType() == Provider.class;
+        && ((ParameterizedType) type).getRawType() == Provider.class;
    }

    private Key<?> getBindingForType(Type type) {

Modified:  
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java
==============================================================================
---  
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java
  
(original)
+++  
trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryProvider2Test.java
  
Fri Feb 27 13:59:15 2009
@@ -24,6 +24,7 @@
  import com.google.inject.Guice;
  import com.google.inject.Inject;
  import com.google.inject.Injector;
+import com.google.inject.Key;
  import com.google.inject.Provider;
  import com.google.inject.TypeLiteral;
  import com.google.inject.matcher.Matchers;
@@ -687,5 +688,195 @@
          =  
Subaru.class.getDeclaredField("colorProvider").getAnnotation(Assisted.class);
      assertEqualsBothWays(FactoryProvider2.DEFAULT_ANNOTATION,  
plainAssisted);
      assertEquals(FactoryProvider2.DEFAULT_ANNOTATION.toString(),  
plainAssisted.toString());
+  }
+
+
+  interface GenericColoredCarFactory<T extends Car> {
+    T create(Color color);
+  }
+
+  public void testGenericAssistedFactory() {
+    final TypeLiteral<GenericColoredCarFactory<Mustang>> mustangTypeLiteral
+        = new TypeLiteral<GenericColoredCarFactory<Mustang>>() {};
+    final TypeLiteral<GenericColoredCarFactory<Camaro>> camaroTypeLiteral
+        = new TypeLiteral<GenericColoredCarFactory<Camaro>>() {};
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(Double.class).toInstance(5.0d);
+         
bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250);
+         
bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984);
+        bind(mustangTypeLiteral)
+            .toProvider(FactoryProvider.newFactory(mustangTypeLiteral,  
TypeLiteral.get(Mustang.class)));
+        bind(camaroTypeLiteral)
+            .toProvider(FactoryProvider.newFactory(camaroTypeLiteral,  
TypeLiteral.get(Camaro.class)));
+      }
+    });
+
+    GenericColoredCarFactory<Mustang> mustangFactory
+        = injector.getInstance(Key.get(mustangTypeLiteral));
+    GenericColoredCarFactory<Camaro> camaroFactory
+        = injector.getInstance(Key.get(camaroTypeLiteral));
+
+    Mustang blueMustang = mustangFactory.create(Color.BLUE);
+    assertEquals(Color.BLUE, blueMustang.color);
+    assertEquals(5.0d, blueMustang.engineSize);
+
+    Camaro redCamaro = camaroFactory.create(Color.RED);
+    assertEquals(Color.RED, redCamaro.color);
+    assertEquals(1984, redCamaro.modelYear);
+    assertEquals(250, redCamaro.horsePower);
+  }
+
+  public interface Insurance<T extends Car> {
+  }
+
+  public static class MustangInsurance implements Insurance<Mustang> {
+    private final double premium;
+    private final double limit;
+    private Mustang car;
+
+    @Inject
+    public MustangInsurance(@Named("lowLimit") double limit, @Assisted  
Mustang car,
+        @Assisted double premium) {
+      this.premium = premium;
+      this.limit = limit;
+      this.car = car;
+    }
+
+    public void sell() {}
+  }
+
+  public static class CamaroInsurance implements Insurance<Camaro> {
+    private final double premium;
+    private final double limit;
+    private Camaro car;
+
+    @Inject
+    public CamaroInsurance(@Named("highLimit") double limit, @Assisted  
Camaro car,
+        @Assisted double premium) {
+      this.premium = premium;
+      this.limit = limit;
+      this.car = car;
+    }
+
+    public void sell() {}
+  }
+
+  public interface MustangInsuranceFactory {
+    public Insurance<Mustang> create(Mustang car, double premium);
+  }
+
+  public interface CamaroInsuranceFactory {
+    public Insurance<Camaro> create(Camaro car, double premium);
+  }
+
+  public void testAssistedFactoryForConcreteType() {
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+         
bind(Double.class).annotatedWith(Names.named("lowLimit")).toInstance(50000.0d);
+         
bind(Double.class).annotatedWith(Names.named("highLimit")).toInstance(100000.0d);
+        bind(MustangInsuranceFactory.class).toProvider(
+            FactoryProvider.newFactory(MustangInsuranceFactory.class,  
MustangInsurance.class));
+        bind(CamaroInsuranceFactory.class).toProvider(
+            FactoryProvider.newFactory(CamaroInsuranceFactory.class,  
CamaroInsurance.class));
+      }
+    });
+
+    MustangInsuranceFactory mustangInsuranceFactory =
+        injector.getInstance(MustangInsuranceFactory.class);
+    CamaroInsuranceFactory camaroInsuranceFactory =
+        injector.getInstance(CamaroInsuranceFactory.class);
+
+    Mustang mustang = new Mustang(5000d, Color.BLACK);
+    MustangInsurance mustangPolicy =
+        (MustangInsurance) mustangInsuranceFactory.create(mustang, 800.0d);
+    assertEquals(800.0d, mustangPolicy.premium);
+    assertEquals(50000.0d, mustangPolicy.limit);
+
+    Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
+    CamaroInsurance camaroPolicy = (CamaroInsurance)  
camaroInsuranceFactory.create(camaro, 800.0d);
+    assertEquals(800.0d, camaroPolicy.premium);
+    assertEquals(100000.0d, camaroPolicy.limit);
+  }
+
+  public interface InsuranceFactory<T extends Car> {
+    public Insurance<T> create(T car, double premium);
+  }
+
+  public void testAssistedFactoryForParameterizedType() {
+    final TypeLiteral<InsuranceFactory<Mustang>>  
mustangInsuranceFactoryType =
+        new TypeLiteral<InsuranceFactory<Mustang>>() {};
+    final TypeLiteral<InsuranceFactory<Camaro>> camaroInsuranceFactoryType  
=
+        new TypeLiteral<InsuranceFactory<Camaro>>() {};
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+         
bind(Double.class).annotatedWith(Names.named("lowLimit")).toInstance(50000.0d);
+         
bind(Double.class).annotatedWith(Names.named("highLimit")).toInstance(100000.0d);
+         
bind(mustangInsuranceFactoryType).toProvider(FactoryProvider.newFactory(
+            mustangInsuranceFactoryType,  
TypeLiteral.get(MustangInsurance.class)));
+         
bind(camaroInsuranceFactoryType).toProvider(FactoryProvider.newFactory(
+            camaroInsuranceFactoryType,  
TypeLiteral.get(CamaroInsurance.class)));
+      }
+    });
+
+    InsuranceFactory<Mustang> mustangInsuranceFactory =
+        injector.getInstance(Key.get(mustangInsuranceFactoryType));
+    InsuranceFactory<Camaro> camaroInsuranceFactory =
+        injector.getInstance(Key.get(camaroInsuranceFactoryType));
+
+    Mustang mustang = new Mustang(5000d, Color.BLACK);
+    MustangInsurance mustangPolicy =
+        (MustangInsurance) mustangInsuranceFactory.create(mustang, 800.0d);
+    assertEquals(800.0d, mustangPolicy.premium);
+    assertEquals(50000.0d, mustangPolicy.limit);
+
+    Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
+    CamaroInsurance camaroPolicy = (CamaroInsurance)  
camaroInsuranceFactory.create(camaro, 800.0d);
+    assertEquals(800.0d, camaroPolicy.premium);
+    assertEquals(100000.0d, camaroPolicy.limit);
+  }
+
+  public static class AutoInsurance<T extends Car> implements Insurance<T>  
{
+    private final double premium;
+    private final double limit;
+    private final T car;
+
+    @Inject
+    public AutoInsurance(double limit, @Assisted T car, @Assisted double  
premium) {
+      this.limit = limit;
+      this.car = car;
+      this.premium = premium;
+    }
+
+    public void sell() {}
+  }
+
+  public void testAssistedFactoryForTypeVariableParameters() {
+    final TypeLiteral<InsuranceFactory<Camaro>> camaroInsuranceFactoryType  
=
+        new TypeLiteral<InsuranceFactory<Camaro>>() {};
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(Double.class).toInstance(50000.0d);
+         
bind(camaroInsuranceFactoryType).toProvider(FactoryProvider.newFactory(
+            camaroInsuranceFactoryType, new  
TypeLiteral<AutoInsurance<Camaro>>() {}));
+      }
+    });
+
+    InsuranceFactory<Camaro> camaroInsuranceFactory =
+        injector.getInstance(Key.get(camaroInsuranceFactoryType));
+
+    Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
+    AutoInsurance camaroPolicy = (AutoInsurance)  
camaroInsuranceFactory.create(camaro, 800.0d);
+    assertEquals(800.0d, camaroPolicy.premium);
+    assertEquals(50000.0d, camaroPolicy.limit);
+    assertEquals(camaro, camaroPolicy.car);
    }
  }

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
   
Fri Feb 27 13:59:15 2009
@@ -577,4 +577,193 @@
    interface AssistedParamsFactory {
      Car create(@Assisted Color color);
    }
+
+  interface GenericColoredCarFactory<T extends Car> {
+    T create(Color color);
+  }
+
+  public void testGenericAssistedFactory() {
+    final TypeLiteral<GenericColoredCarFactory<Mustang>> mustangTypeLiteral
+        = new TypeLiteral<GenericColoredCarFactory<Mustang>>() {};
+    final TypeLiteral<GenericColoredCarFactory<Camaro>> camaroTypeLiteral
+        = new TypeLiteral<GenericColoredCarFactory<Camaro>>() {};
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(Double.class).toInstance(5.0d);
+         
bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250);
+         
bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984);
+        bind(mustangTypeLiteral).toProvider(
+            FactoryProvider.newFactory(mustangTypeLiteral,  
TypeLiteral.get(Mustang.class)));
+        bind(camaroTypeLiteral).toProvider(
+            FactoryProvider.newFactory(camaroTypeLiteral,  
TypeLiteral.get(Camaro.class)));
+      }
+    });
+
+    GenericColoredCarFactory<Mustang> mustangFactory
+        = injector.getInstance(Key.get(mustangTypeLiteral));
+    GenericColoredCarFactory<Camaro> camaroFactory
+        = injector.getInstance(Key.get(camaroTypeLiteral));
+
+    Mustang blueMustang = mustangFactory.create(Color.BLUE);
+    assertEquals(Color.BLUE, blueMustang.color);
+    assertEquals(5.0d, blueMustang.engineSize);
+
+    Camaro redCamaro = camaroFactory.create(Color.RED);
+    assertEquals(Color.RED, redCamaro.color);
+    assertEquals(1984, redCamaro.modelYear);
+    assertEquals(250, redCamaro.horsePower);
+  }
+
+  public interface Insurance<T extends Car> {
+  }
+
+  public static class MustangInsurance implements Insurance<Mustang> {
+    private final double premium;
+    private final double limit;
+    private Mustang car;
+
+    @AssistedInject
+    public MustangInsurance(@Named("lowLimit") double limit, @Assisted  
Mustang car,
+        @Assisted double premium) {
+      this.premium = premium;
+      this.limit = limit;
+      this.car = car;
+    }
+
+    public void sell() {}
+  }
+
+  public static class CamaroInsurance implements Insurance<Camaro> {
+    private final double premium;
+    private final double limit;
+    private Camaro car;
+
+    @AssistedInject
+    public CamaroInsurance(@Named("highLimit") double limit, @Assisted  
Camaro car,
+        @Assisted double premium) {
+      this.premium = premium;
+      this.limit = limit;
+      this.car = car;
+    }
+
+    public void sell() {}
+  }
+
+  public interface MustangInsuranceFactory {
+    public Insurance<Mustang> create(Mustang car, double premium);
+  }
+
+  public interface CamaroInsuranceFactory {
+    public Insurance<Camaro> create(Camaro car, double premium);
+  }
+
+  public void testAssistedFactoryForConcreteType() {
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+         
bind(Double.class).annotatedWith(Names.named("lowLimit")).toInstance(50000.0d);
+         
bind(Double.class).annotatedWith(Names.named("highLimit")).toInstance(100000.0d);
+        bind(MustangInsuranceFactory.class).toProvider(
+            FactoryProvider.newFactory(MustangInsuranceFactory.class,  
MustangInsurance.class));
+        bind(CamaroInsuranceFactory.class).toProvider(
+            FactoryProvider.newFactory(CamaroInsuranceFactory.class,  
CamaroInsurance.class));
+      }
+    });
+
+    MustangInsuranceFactory mustangInsuranceFactory =
+        injector.getInstance(MustangInsuranceFactory.class);
+    CamaroInsuranceFactory camaroInsuranceFactory =
+        injector.getInstance(CamaroInsuranceFactory.class);
+
+    Mustang mustang = new Mustang(5000d, Color.BLACK);
+    MustangInsurance mustangPolicy =
+        (MustangInsurance) mustangInsuranceFactory.create(mustang, 800.0d);
+    assertEquals(800.0d, mustangPolicy.premium);
+    assertEquals(50000.0d, mustangPolicy.limit);
+
+    Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
+    CamaroInsurance camaroPolicy = (CamaroInsurance)  
camaroInsuranceFactory.create(camaro, 800.0d);
+    assertEquals(800.0d, camaroPolicy.premium);
+    assertEquals(100000.0d, camaroPolicy.limit);
+  }
+
+  public interface InsuranceFactory<T extends Car> {
+    public Insurance<T> create(T car, double premium);
+  }
+
+  public void testAssistedFactoryForParameterizedType() {
+    final TypeLiteral<InsuranceFactory<Mustang>>  
mustangInsuranceFactoryType =
+        new TypeLiteral<InsuranceFactory<Mustang>>() {};
+    final TypeLiteral<InsuranceFactory<Camaro>> camaroInsuranceFactoryType  
=
+        new TypeLiteral<InsuranceFactory<Camaro>>() {};
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+         
bind(Double.class).annotatedWith(Names.named("lowLimit")).toInstance(50000.0d);
+         
bind(Double.class).annotatedWith(Names.named("highLimit")).toInstance(100000.0d);
+         
bind(mustangInsuranceFactoryType).toProvider(FactoryProvider.newFactory(
+            mustangInsuranceFactoryType,  
TypeLiteral.get(MustangInsurance.class)));
+         
bind(camaroInsuranceFactoryType).toProvider(FactoryProvider.newFactory(
+            camaroInsuranceFactoryType,  
TypeLiteral.get(CamaroInsurance.class)));
+      }
+    });
+
+    InsuranceFactory<Mustang> mustangInsuranceFactory =
+        injector.getInstance(Key.get(mustangInsuranceFactoryType));
+    InsuranceFactory<Camaro> camaroInsuranceFactory =
+        injector.getInstance(Key.get(camaroInsuranceFactoryType));
+
+    Mustang mustang = new Mustang(5000d, Color.BLACK);
+    MustangInsurance mustangPolicy =
+        (MustangInsurance) mustangInsuranceFactory.create(mustang, 800.0d);
+    assertEquals(800.0d, mustangPolicy.premium);
+    assertEquals(50000.0d, mustangPolicy.limit);
+
+    Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
+    CamaroInsurance camaroPolicy = (CamaroInsurance)  
camaroInsuranceFactory.create(camaro, 800.0d);
+    assertEquals(800.0d, camaroPolicy.premium);
+    assertEquals(100000.0d, camaroPolicy.limit);
+  }
+
+  public static class AutoInsurance<T extends Car> implements Insurance<T>  
{
+    private final double premium;
+    private final double limit;
+    private final T car;
+
+    @AssistedInject
+    public AutoInsurance(double limit, @Assisted T car, @Assisted double  
premium) {
+      this.limit = limit;
+      this.car = car;
+      this.premium = premium;
+    }
+
+    public void sell() {}
+  }
+
+  public void testAssistedFactoryForTypeVariableParameters() {
+    final TypeLiteral<InsuranceFactory<Camaro>> camaroInsuranceFactoryType  
=
+        new TypeLiteral<InsuranceFactory<Camaro>>() {};
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(Double.class).toInstance(50000.0d);
+         
bind(camaroInsuranceFactoryType).toProvider(FactoryProvider.newFactory(
+            camaroInsuranceFactoryType, new  
TypeLiteral<AutoInsurance<Camaro>>() {}));
+      }
+    });
+
+    InsuranceFactory<Camaro> camaroInsuranceFactory =
+        injector.getInstance(Key.get(camaroInsuranceFactoryType));
+
+    Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
+    AutoInsurance camaroPolicy = (AutoInsurance)  
camaroInsuranceFactory.create(camaro, 800.0d);
+    assertEquals(800.0d, camaroPolicy.premium);
+    assertEquals(50000.0d, camaroPolicy.limit);
+    assertEquals(camaro, camaroPolicy.car);
+  }
  }

--~--~---------~--~----~------------~-------~--~----~
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