Home | History | Annotate | Download | only in assistedinject
      1 /*
      2  * Copyright (C) 2008 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.inject.assistedinject;
     18 
     19 import static com.google.inject.Asserts.assertContains;
     20 import static com.google.inject.Asserts.assertEqualsBothWays;
     21 
     22 import com.google.inject.AbstractModule;
     23 import com.google.inject.ConfigurationException;
     24 import com.google.inject.CreationException;
     25 import com.google.inject.Guice;
     26 import com.google.inject.Inject;
     27 import com.google.inject.Injector;
     28 import com.google.inject.Key;
     29 import com.google.inject.Provider;
     30 import com.google.inject.Stage;
     31 import com.google.inject.TypeLiteral;
     32 import com.google.inject.assistedinject.FactoryProvider2Test.Equals.ComparisonMethod;
     33 import com.google.inject.assistedinject.FactoryProvider2Test.Equals.Impl;
     34 import com.google.inject.internal.Annotations;
     35 import com.google.inject.matcher.Matchers;
     36 import com.google.inject.name.Named;
     37 import com.google.inject.name.Names;
     38 import java.util.Collection;
     39 import java.util.Collections;
     40 import java.util.Set;
     41 import java.util.concurrent.atomic.AtomicInteger;
     42 import junit.framework.TestCase;
     43 
     44 @SuppressWarnings("deprecation")
     45 public class FactoryProvider2Test extends TestCase {
     46 
     47   private enum Color {
     48     BLUE,
     49     GREEN,
     50     RED,
     51     GRAY,
     52     BLACK,
     53     ORANGE,
     54     PINK
     55   }
     56 
     57   public void testAssistedFactory() {
     58     Injector injector =
     59         Guice.createInjector(
     60             new AbstractModule() {
     61               @Override
     62               protected void configure() {
     63                 bind(Double.class).toInstance(5.0d);
     64                 bind(ColoredCarFactory.class)
     65                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
     66               }
     67             });
     68     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
     69 
     70     Mustang blueMustang = (Mustang) carFactory.create(Color.BLUE);
     71     assertEquals(Color.BLUE, blueMustang.color);
     72     assertEquals(5.0d, blueMustang.engineSize, 0.0);
     73 
     74     Mustang redMustang = (Mustang) carFactory.create(Color.RED);
     75     assertEquals(Color.RED, redMustang.color);
     76     assertEquals(5.0d, redMustang.engineSize, 0.0);
     77   }
     78 
     79   public void testAssistedFactoryWithAnnotations() {
     80     Injector injector =
     81         Guice.createInjector(
     82             new AbstractModule() {
     83               @Override
     84               protected void configure() {
     85                 bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250);
     86                 bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984);
     87                 bind(ColoredCarFactory.class)
     88                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Camaro.class));
     89               }
     90             });
     91 
     92     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
     93 
     94     Camaro blueCamaro = (Camaro) carFactory.create(Color.BLUE);
     95     assertEquals(Color.BLUE, blueCamaro.color);
     96     assertEquals(1984, blueCamaro.modelYear);
     97     assertEquals(250, blueCamaro.horsePower);
     98 
     99     Camaro redCamaro = (Camaro) carFactory.create(Color.RED);
    100     assertEquals(Color.RED, redCamaro.color);
    101     assertEquals(1984, redCamaro.modelYear);
    102     assertEquals(250, redCamaro.horsePower);
    103   }
    104 
    105   public interface Car {}
    106 
    107   interface ColoredCarFactory {
    108     Car create(Color color);
    109   }
    110 
    111   public static class Mustang implements Car {
    112     private final double engineSize;
    113     private final Color color;
    114 
    115     @Inject
    116     public Mustang(double engineSize, @Assisted Color color) {
    117       this.engineSize = engineSize;
    118       this.color = color;
    119     }
    120 
    121     public void drive() {}
    122   }
    123 
    124   public static class Camaro implements Car {
    125     private final int horsePower;
    126     private final int modelYear;
    127     private final Color color;
    128 
    129     @Inject
    130     public Camaro(
    131         @Named("horsePower") int horsePower,
    132         @Named("modelYear") int modelYear,
    133         @Assisted Color color) {
    134       this.horsePower = horsePower;
    135       this.modelYear = modelYear;
    136       this.color = color;
    137     }
    138   }
    139 
    140   interface SummerCarFactory {
    141     Car create(Color color, boolean convertable);
    142   }
    143 
    144   public void testFactoryUsesInjectedConstructor() {
    145     Injector injector =
    146         Guice.createInjector(
    147             new AbstractModule() {
    148               @Override
    149               protected void configure() {
    150                 bind(float.class).toInstance(140f);
    151                 bind(SummerCarFactory.class)
    152                     .toProvider(FactoryProvider.newFactory(SummerCarFactory.class, Corvette.class));
    153               }
    154             });
    155 
    156     SummerCarFactory carFactory = injector.getInstance(SummerCarFactory.class);
    157 
    158     Corvette redCorvette = (Corvette) carFactory.create(Color.RED, false);
    159     assertEquals(Color.RED, redCorvette.color);
    160     assertEquals(140f, redCorvette.maxMph, 0.0f);
    161     assertFalse(redCorvette.isConvertable);
    162   }
    163 
    164   public static class Corvette implements Car {
    165     private boolean isConvertable;
    166     private Color color;
    167     private float maxMph;
    168 
    169     @SuppressWarnings("unused")
    170     public Corvette(Color color, boolean isConvertable) {
    171       throw new IllegalStateException("Not an @AssistedInject constructor");
    172     }
    173 
    174     @Inject
    175     public Corvette(@Assisted Color color, Float maxMph, @Assisted boolean isConvertable) {
    176       this.isConvertable = isConvertable;
    177       this.color = color;
    178       this.maxMph = maxMph;
    179     }
    180   }
    181 
    182   public void testConstructorDoesntNeedAllFactoryMethodArguments() {
    183     Injector injector =
    184         Guice.createInjector(
    185             new AbstractModule() {
    186               @Override
    187               protected void configure() {
    188                 bind(SummerCarFactory.class)
    189                     .toProvider(FactoryProvider.newFactory(SummerCarFactory.class, Beetle.class));
    190               }
    191             });
    192     SummerCarFactory factory = injector.getInstance(SummerCarFactory.class);
    193 
    194     Beetle beetle = (Beetle) factory.create(Color.RED, true);
    195     assertSame(Color.RED, beetle.color);
    196   }
    197 
    198   public static class Beetle implements Car {
    199     private final Color color;
    200 
    201     @Inject
    202     public Beetle(@Assisted Color color) {
    203       this.color = color;
    204     }
    205   }
    206 
    207   public void testMethodsAndFieldsGetInjected() {
    208     Injector injector =
    209         Guice.createInjector(
    210             new AbstractModule() {
    211               @Override
    212               protected void configure() {
    213                 bind(String.class).toInstance("turbo");
    214                 bind(int.class).toInstance(911);
    215                 bind(double.class).toInstance(50000d);
    216                 bind(ColoredCarFactory.class)
    217                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Porsche.class));
    218               }
    219             });
    220     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
    221 
    222     Porsche grayPorsche = (Porsche) carFactory.create(Color.GRAY);
    223     assertEquals(Color.GRAY, grayPorsche.color);
    224     assertEquals(50000d, grayPorsche.price, 0.0);
    225     assertEquals(911, grayPorsche.model);
    226     assertEquals("turbo", grayPorsche.name);
    227   }
    228 
    229   public static class Porsche implements Car {
    230     private final Color color;
    231     private final double price;
    232     private @Inject String name;
    233     private int model;
    234 
    235     @Inject
    236     public Porsche(@Assisted Color color, double price) {
    237       this.color = color;
    238       this.price = price;
    239     }
    240 
    241     @Inject
    242     void setModel(int model) {
    243       this.model = model;
    244     }
    245   }
    246 
    247   public void testProviderInjection() {
    248     Injector injector =
    249         Guice.createInjector(
    250             new AbstractModule() {
    251               @Override
    252               protected void configure() {
    253                 bind(String.class).toInstance("trans am");
    254                 bind(ColoredCarFactory.class)
    255                     .toProvider(
    256                         FactoryProvider.newFactory(ColoredCarFactory.class, Firebird.class));
    257               }
    258             });
    259     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
    260 
    261     Firebird blackFirebird = (Firebird) carFactory.create(Color.BLACK);
    262     assertEquals(Color.BLACK, blackFirebird.color);
    263     assertEquals("trans am", blackFirebird.modifiersProvider.get());
    264   }
    265 
    266   public static class Firebird implements Car {
    267     private final Provider<String> modifiersProvider;
    268     private final Color color;
    269 
    270     @Inject
    271     public Firebird(Provider<String> modifiersProvider, @Assisted Color color) {
    272       this.modifiersProvider = modifiersProvider;
    273       this.color = color;
    274     }
    275   }
    276 
    277   public void testAssistedProviderInjection() {
    278     Injector injector =
    279         Guice.createInjector(
    280             new AbstractModule() {
    281               @Override
    282               protected void configure() {
    283                 bind(String.class).toInstance("trans am");
    284                 bind(ColoredCarFactory.class)
    285                     .toProvider(
    286                         FactoryProvider.newFactory(ColoredCarFactory.class, Flamingbird.class));
    287               }
    288             });
    289     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
    290 
    291     Flamingbird flamingbird = (Flamingbird) carFactory.create(Color.BLACK);
    292     assertEquals(Color.BLACK, flamingbird.colorProvider.get());
    293     assertEquals("trans am", flamingbird.modifiersProvider.get());
    294 
    295     Flamingbird flamingbird2 = (Flamingbird) carFactory.create(Color.RED);
    296     assertEquals(Color.RED, flamingbird2.colorProvider.get());
    297     assertEquals("trans am", flamingbird2.modifiersProvider.get());
    298     // Make sure the original flamingbird is black still.
    299     assertEquals(Color.BLACK, flamingbird.colorProvider.get());
    300   }
    301 
    302   public static class Flamingbird implements Car {
    303     private final Provider<String> modifiersProvider;
    304     private final Provider<Color> colorProvider;
    305 
    306     @Inject
    307     public Flamingbird(
    308         Provider<String> modifiersProvider, @Assisted Provider<Color> colorProvider) {
    309       this.modifiersProvider = modifiersProvider;
    310       this.colorProvider = colorProvider;
    311     }
    312   }
    313 
    314   public void testTypeTokenInjection() {
    315     Injector injector =
    316         Guice.createInjector(
    317             new AbstractModule() {
    318               @Override
    319               protected void configure() {
    320                 bind(new TypeLiteral<Set<String>>() {})
    321                     .toInstance(Collections.singleton("Flux Capacitor"));
    322                 bind(new TypeLiteral<Set<Integer>>() {}).toInstance(Collections.singleton(88));
    323                 bind(ColoredCarFactory.class)
    324                     .toProvider(
    325                         FactoryProvider.newFactory(ColoredCarFactory.class, DeLorean.class));
    326               }
    327             });
    328     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
    329 
    330     DeLorean deLorean = (DeLorean) carFactory.create(Color.GRAY);
    331     assertEquals(Color.GRAY, deLorean.color);
    332     assertEquals("Flux Capacitor", deLorean.features.iterator().next());
    333     assertEquals(Integer.valueOf(88), deLorean.featureActivationSpeeds.iterator().next());
    334   }
    335 
    336   public static class DeLorean implements Car {
    337     private final Set<String> features;
    338     private final Set<Integer> featureActivationSpeeds;
    339     private final Color color;
    340 
    341     @Inject
    342     public DeLorean(
    343         Set<String> extraFeatures, Set<Integer> featureActivationSpeeds, @Assisted Color color) {
    344       this.features = extraFeatures;
    345       this.featureActivationSpeeds = featureActivationSpeeds;
    346       this.color = color;
    347     }
    348   }
    349 
    350   public void testTypeTokenProviderInjection() {
    351     Injector injector =
    352         Guice.createInjector(
    353             new AbstractModule() {
    354               @Override
    355               protected void configure() {
    356                 bind(new TypeLiteral<Set<String>>() {}).toInstance(Collections.singleton("Datsun"));
    357                 bind(ColoredCarFactory.class)
    358                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Z.class));
    359               }
    360             });
    361     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
    362 
    363     Z orangeZ = (Z) carFactory.create(Color.ORANGE);
    364     assertEquals(Color.ORANGE, orangeZ.color);
    365     assertEquals("Datsun", orangeZ.manufacturersProvider.get().iterator().next());
    366   }
    367 
    368   public static class Z implements Car {
    369     private final Provider<Set<String>> manufacturersProvider;
    370     private final Color color;
    371 
    372     @Inject
    373     public Z(Provider<Set<String>> manufacturersProvider, @Assisted Color color) {
    374       this.manufacturersProvider = manufacturersProvider;
    375       this.color = color;
    376     }
    377   }
    378 
    379   public static class Prius implements Car {
    380     final Color color;
    381 
    382     @Inject
    383     private Prius(@Assisted Color color) {
    384       this.color = color;
    385     }
    386   }
    387 
    388   public void testAssistInjectionInNonPublicConstructor() {
    389     Injector injector =
    390         Guice.createInjector(
    391             new AbstractModule() {
    392               @Override
    393               protected void configure() {
    394                 bind(ColoredCarFactory.class)
    395                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Prius.class));
    396               }
    397             });
    398     Prius prius = (Prius) injector.getInstance(ColoredCarFactory.class).create(Color.ORANGE);
    399     assertEquals(prius.color, Color.ORANGE);
    400   }
    401 
    402   public static class ExplodingCar implements Car {
    403     @Inject
    404     public ExplodingCar(@SuppressWarnings("unused") @Assisted Color color) {
    405       throw new IllegalStateException("kaboom!");
    406     }
    407   }
    408 
    409   public void testExceptionDuringConstruction() {
    410     Injector injector =
    411         Guice.createInjector(
    412             new AbstractModule() {
    413               @Override
    414               protected void configure() {
    415                 bind(ColoredCarFactory.class)
    416                     .toProvider(
    417                         FactoryProvider.newFactory(ColoredCarFactory.class, ExplodingCar.class));
    418               }
    419             });
    420     try {
    421       injector.getInstance(ColoredCarFactory.class).create(Color.ORANGE);
    422       fail();
    423     } catch (IllegalStateException e) {
    424       assertEquals("kaboom!", e.getMessage());
    425     }
    426   }
    427 
    428   public static class DefectiveCar implements Car {
    429     @Inject
    430     public DefectiveCar() throws ExplosionException {
    431       throw new ExplosionException();
    432     }
    433   }
    434 
    435   public static class ExplosionException extends Exception {}
    436 
    437   public static class FireException extends Exception {}
    438 
    439   public interface DefectiveCarFactoryWithNoExceptions {
    440     Car createCar();
    441   }
    442 
    443   public interface DefectiveCarFactory {
    444     Car createCar() throws FireException;
    445   }
    446 
    447   public interface CorrectDefectiveCarFactory {
    448     Car createCar() throws FireException, ExplosionException;
    449   }
    450 
    451   public void testConstructorExceptionsAreThrownByFactory() {
    452     Injector injector =
    453         Guice.createInjector(
    454             new AbstractModule() {
    455               @Override
    456               protected void configure() {
    457                 bind(CorrectDefectiveCarFactory.class)
    458                     .toProvider(
    459                         FactoryProvider.newFactory(
    460                             CorrectDefectiveCarFactory.class, DefectiveCar.class));
    461               }
    462             });
    463     try {
    464       injector.getInstance(CorrectDefectiveCarFactory.class).createCar();
    465       fail();
    466     } catch (FireException e) {
    467       fail();
    468     } catch (ExplosionException expected) {
    469     }
    470   }
    471 
    472   public static class WildcardCollection {
    473 
    474     public interface Factory {
    475       WildcardCollection create(Collection<?> items);
    476     }
    477 
    478     @Inject
    479     public WildcardCollection(@SuppressWarnings("unused") @Assisted Collection<?> items) {}
    480   }
    481 
    482   public void testWildcardGenerics() {
    483     Injector injector =
    484         Guice.createInjector(
    485             new AbstractModule() {
    486               @Override
    487               protected void configure() {
    488                 bind(WildcardCollection.Factory.class)
    489                     .toProvider(
    490                         FactoryProvider.newFactory(
    491                             WildcardCollection.Factory.class, WildcardCollection.class));
    492               }
    493             });
    494     WildcardCollection.Factory factory = injector.getInstance(WildcardCollection.Factory.class);
    495     factory.create(Collections.emptyList());
    496   }
    497 
    498   public static class SteeringWheel {}
    499 
    500   public static class Fiat implements Car {
    501     private final SteeringWheel steeringWheel;
    502     private final Color color;
    503 
    504     @Inject
    505     public Fiat(SteeringWheel steeringWheel, @Assisted Color color) {
    506       this.steeringWheel = steeringWheel;
    507       this.color = color;
    508     }
    509   }
    510 
    511   public void testFactoryWithImplicitBindings() {
    512     Injector injector =
    513         Guice.createInjector(
    514             new AbstractModule() {
    515               @Override
    516               protected void configure() {
    517                 bind(ColoredCarFactory.class)
    518                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Fiat.class));
    519               }
    520             });
    521 
    522     ColoredCarFactory coloredCarFactory = injector.getInstance(ColoredCarFactory.class);
    523     Fiat fiat = (Fiat) coloredCarFactory.create(Color.GREEN);
    524     assertEquals(Color.GREEN, fiat.color);
    525     assertNotNull(fiat.steeringWheel);
    526   }
    527 
    528   public void testFactoryFailsWithMissingBinding() {
    529     try {
    530       Guice.createInjector(
    531           new AbstractModule() {
    532             @Override
    533             protected void configure() {
    534               bind(ColoredCarFactory.class)
    535                   .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
    536             }
    537           });
    538       fail();
    539     } catch (CreationException expected) {
    540       assertContains(
    541           expected.getMessage(),
    542           "Could not find a suitable constructor in java.lang.Double.",
    543           "at " + ColoredCarFactory.class.getName() + ".create(FactoryProvider2Test.java");
    544     }
    545   }
    546 
    547   public void testFactoryFailsWithMissingBindingInToolStage() {
    548     try {
    549       Guice.createInjector(
    550           Stage.TOOL,
    551           new AbstractModule() {
    552             @Override
    553             protected void configure() {
    554               bind(ColoredCarFactory.class)
    555                   .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
    556             }
    557           });
    558       fail();
    559     } catch (CreationException expected) {
    560       assertContains(
    561           expected.getMessage(),
    562           "Could not find a suitable constructor in java.lang.Double.",
    563           "at " + ColoredCarFactory.class.getName() + ".create(FactoryProvider2Test.java");
    564     }
    565   }
    566 
    567   public void testMethodsDeclaredInObject() {
    568     Injector injector =
    569         Guice.createInjector(
    570             new AbstractModule() {
    571               @Override
    572               protected void configure() {
    573                 bind(Double.class).toInstance(5.0d);
    574                 bind(ColoredCarFactory.class)
    575                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
    576               }
    577             });
    578 
    579     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
    580 
    581     assertEqualsBothWays(carFactory, carFactory);
    582   }
    583 
    584   static class Subaru implements Car {
    585     @Inject @Assisted Provider<Color> colorProvider;
    586   }
    587 
    588   public void testInjectingProviderOfParameter() {
    589     Injector injector =
    590         Guice.createInjector(
    591             new AbstractModule() {
    592               @Override
    593               protected void configure() {
    594                 bind(ColoredCarFactory.class)
    595                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Subaru.class));
    596               }
    597             });
    598 
    599     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
    600     Subaru subaru = (Subaru) carFactory.create(Color.RED);
    601 
    602     assertSame(Color.RED, subaru.colorProvider.get());
    603     assertSame(Color.RED, subaru.colorProvider.get());
    604 
    605     Subaru sedan = (Subaru) carFactory.create(Color.BLUE);
    606     assertSame(Color.BLUE, sedan.colorProvider.get());
    607     assertSame(Color.BLUE, sedan.colorProvider.get());
    608 
    609     // and make sure the subaru is still red
    610     assertSame(Color.RED, subaru.colorProvider.get());
    611   }
    612 
    613   public void testInjectingNullParameter() {
    614     Injector injector =
    615         Guice.createInjector(
    616             new AbstractModule() {
    617               @Override
    618               protected void configure() {
    619                 bind(ColoredCarFactory.class)
    620                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Subaru.class));
    621               }
    622             });
    623 
    624     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
    625     Subaru subaru = (Subaru) carFactory.create(null);
    626 
    627     assertNull(subaru.colorProvider.get());
    628     assertNull(subaru.colorProvider.get());
    629   }
    630 
    631   interface ProviderBasedColoredCarFactory {
    632     Car createCar(Provider<Color> colorProvider, Provider<String> stringProvider);
    633 
    634     Mustang createMustang(@Assisted("color") Provider<Color> colorProvider);
    635   }
    636 
    637   public void testAssistedProviderIsDisallowed() {
    638     try {
    639       Guice.createInjector(
    640           new AbstractModule() {
    641             @Override
    642             protected void configure() {
    643               bind(ProviderBasedColoredCarFactory.class)
    644                   .toProvider(
    645                       FactoryProvider.newFactory(
    646                           ProviderBasedColoredCarFactory.class, Subaru.class));
    647             }
    648           });
    649       fail();
    650     } catch (CreationException expected) {
    651       assertEquals(expected.getMessage(), 4, expected.getErrorMessages().size());
    652       // Assert each method individually, because JDK7 doesn't guarantee method ordering.
    653       assertContains(
    654           expected.getMessage(),
    655           ") A Provider may not be a type in a factory method of an AssistedInject."
    656               + "\n  Offending instance is parameter [1] with key"
    657               + " [com.google.inject.Provider<"
    658               + Color.class.getName()
    659               + ">] on method ["
    660               + ProviderBasedColoredCarFactory.class.getName()
    661               + ".createCar()]");
    662       assertContains(
    663           expected.getMessage(),
    664           ") A Provider may not be a type in a factory method of an AssistedInject."
    665               + "\n  Offending instance is parameter [2] with key"
    666               + " [com.google.inject.Provider<java.lang.String>] on method ["
    667               + ProviderBasedColoredCarFactory.class.getName()
    668               + ".createCar()]");
    669       assertContains(
    670           expected.getMessage(),
    671           ") A Provider may not be a type in a factory method of an AssistedInject."
    672               + "\n  Offending instance is parameter [1] with key"
    673               + " [com.google.inject.Provider<"
    674               + Color.class.getName()
    675               + ">"
    676               + " annotated with @com.google.inject.assistedinject.Assisted(value="
    677               + Annotations.memberValueString("color")
    678               + ")]"
    679               + " on method ["
    680               + ProviderBasedColoredCarFactory.class.getName()
    681               + ".createMustang()]");
    682       assertContains(
    683           expected.getMessage(),
    684           ") No implementation for com.google.inject.assistedinject."
    685               + "FactoryProvider2Test$ProviderBasedColoredCarFactory was bound.");
    686     }
    687   }
    688 
    689   interface JavaxProviderBasedColoredCarFactory {
    690     Car createCar(
    691         javax.inject.Provider<Color> colorProvider, javax.inject.Provider<String> stringProvider);
    692 
    693     Mustang createMustang(@Assisted("color") javax.inject.Provider<Color> colorProvider);
    694   }
    695 
    696   public void testAssistedJavaxProviderIsDisallowed() {
    697     try {
    698       Guice.createInjector(
    699           new AbstractModule() {
    700             @Override
    701             protected void configure() {
    702               bind(JavaxProviderBasedColoredCarFactory.class)
    703                   .toProvider(
    704                       FactoryProvider.newFactory(
    705                           JavaxProviderBasedColoredCarFactory.class, Subaru.class));
    706             }
    707           });
    708       fail();
    709     } catch (CreationException expected) {
    710       assertEquals(expected.getMessage(), 4, expected.getErrorMessages().size());
    711       assertContains(
    712           expected.getMessage(),
    713           ") A Provider may not be a type in a factory method of an AssistedInject."
    714               + "\n  Offending instance is parameter [1] with key"
    715               + " [com.google.inject.Provider<"
    716               + Color.class.getName()
    717               + ">] on method ["
    718               + JavaxProviderBasedColoredCarFactory.class.getName()
    719               + ".createCar()]");
    720       assertContains(
    721           expected.getMessage(),
    722           ") A Provider may not be a type in a factory method of an AssistedInject."
    723               + "\n  Offending instance is parameter [2] with key"
    724               + " [com.google.inject.Provider<java.lang.String>] on method ["
    725               + JavaxProviderBasedColoredCarFactory.class.getName()
    726               + ".createCar()]");
    727       assertContains(
    728           expected.getMessage(),
    729           ") A Provider may not be a type in a factory method of an AssistedInject."
    730               + "\n  Offending instance is parameter [1] with key"
    731               + " [com.google.inject.Provider<"
    732               + Color.class.getName()
    733               + ">"
    734               + " annotated with @com.google.inject.assistedinject.Assisted(value="
    735               + Annotations.memberValueString("color")
    736               + ")]"
    737               + " on method ["
    738               + JavaxProviderBasedColoredCarFactory.class.getName()
    739               + ".createMustang()]");
    740       assertContains(
    741           expected.getMessage(),
    742           ") No implementation for com.google.inject.assistedinject."
    743               + "FactoryProvider2Test$JavaxProviderBasedColoredCarFactory was bound.");
    744     }
    745   }
    746 
    747   public void testFactoryUseBeforeInitialization() {
    748     ColoredCarFactory carFactory =
    749         FactoryProvider.newFactory(ColoredCarFactory.class, Subaru.class).get();
    750     try {
    751       carFactory.create(Color.RED);
    752       fail();
    753     } catch (IllegalStateException expected) {
    754       assertContains(
    755           expected.getMessage(),
    756           "Factories.create() factories cannot be used until they're initialized by Guice.");
    757     }
    758   }
    759 
    760   interface MustangFactory {
    761     Mustang create(Color color);
    762   }
    763 
    764   public void testFactoryBuildingConcreteTypes() {
    765     Injector injector =
    766         Guice.createInjector(
    767             new AbstractModule() {
    768               @Override
    769               protected void configure() {
    770                 bind(double.class).toInstance(5.0d);
    771                 // note there is no 'thatMakes()' call here:
    772                 bind(MustangFactory.class)
    773                     .toProvider(FactoryProvider.newFactory(MustangFactory.class, Mustang.class));
    774               }
    775             });
    776     MustangFactory factory = injector.getInstance(MustangFactory.class);
    777 
    778     Mustang mustang = factory.create(Color.RED);
    779     assertSame(Color.RED, mustang.color);
    780     assertEquals(5.0d, mustang.engineSize, 0.0);
    781   }
    782 
    783   static class Fleet {
    784     @Inject Mustang mustang;
    785     @Inject Camaro camaro;
    786   }
    787 
    788   interface FleetFactory {
    789     Fleet createFleet(Color color);
    790   }
    791 
    792   public void testInjectDeepIntoConstructedObjects() {
    793     Injector injector =
    794         Guice.createInjector(
    795             new AbstractModule() {
    796               @Override
    797               protected void configure() {
    798                 bind(double.class).toInstance(5.0d);
    799                 bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250);
    800                 bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984);
    801                 bind(FleetFactory.class)
    802                     .toProvider(FactoryProvider.newFactory(FleetFactory.class, Fleet.class));
    803               }
    804             });
    805 
    806     FleetFactory fleetFactory = injector.getInstance(FleetFactory.class);
    807     Fleet fleet = fleetFactory.createFleet(Color.RED);
    808 
    809     assertSame(Color.RED, fleet.mustang.color);
    810     assertEquals(5.0d, fleet.mustang.engineSize, 0.0);
    811     assertSame(Color.RED, fleet.camaro.color);
    812     assertEquals(250, fleet.camaro.horsePower);
    813     assertEquals(1984, fleet.camaro.modelYear);
    814   }
    815 
    816   interface TwoToneCarFactory {
    817     Car create(@Assisted("paint") Color paint, @Assisted("fabric") Color fabric);
    818   }
    819 
    820   static class Maxima implements Car {
    821     @Inject
    822     @Assisted("paint")
    823     Color paint;
    824 
    825     @Inject
    826     @Assisted("fabric")
    827     Color fabric;
    828   }
    829 
    830   public void testDistinctKeys() {
    831     Injector injector =
    832         Guice.createInjector(
    833             new AbstractModule() {
    834               @Override
    835               protected void configure() {
    836                 bind(TwoToneCarFactory.class)
    837                     .toProvider(FactoryProvider.newFactory(TwoToneCarFactory.class, Maxima.class));
    838               }
    839             });
    840 
    841     TwoToneCarFactory factory = injector.getInstance(TwoToneCarFactory.class);
    842     Maxima maxima = (Maxima) factory.create(Color.BLACK, Color.GRAY);
    843     assertSame(Color.BLACK, maxima.paint);
    844     assertSame(Color.GRAY, maxima.fabric);
    845   }
    846 
    847   interface DoubleToneCarFactory {
    848     Car create(@Assisted("paint") Color paint, @Assisted("paint") Color morePaint);
    849   }
    850 
    851   public void testDuplicateKeys() {
    852     try {
    853       Guice.createInjector(
    854           new AbstractModule() {
    855             @Override
    856             protected void configure() {
    857               bind(DoubleToneCarFactory.class)
    858                   .toProvider(FactoryProvider.newFactory(DoubleToneCarFactory.class, Maxima.class));
    859             }
    860           });
    861       fail();
    862     } catch (CreationException expected) {
    863       assertContains(
    864           expected.getMessage(),
    865           "A binding to "
    866               + Color.class.getName()
    867               + " annotated with @"
    868               + Assisted.class.getName()
    869               + "(value="
    870               + Annotations.memberValueString("paint")
    871               + ") was already configured at");
    872     }
    873   }
    874 
    875   /*if[AOP]*/
    876   public void testMethodInterceptorsOnAssistedTypes() {
    877     final AtomicInteger invocationCount = new AtomicInteger();
    878     final org.aopalliance.intercept.MethodInterceptor interceptor =
    879         new org.aopalliance.intercept.MethodInterceptor() {
    880           @Override
    881           public Object invoke(org.aopalliance.intercept.MethodInvocation methodInvocation)
    882               throws Throwable {
    883             invocationCount.incrementAndGet();
    884             return methodInvocation.proceed();
    885           }
    886         };
    887 
    888     Injector injector =
    889         Guice.createInjector(
    890             new AbstractModule() {
    891               @Override
    892               protected void configure() {
    893                 bindInterceptor(Matchers.any(), Matchers.any(), interceptor);
    894                 bind(Double.class).toInstance(5.0d);
    895                 bind(ColoredCarFactory.class)
    896                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
    897               }
    898             });
    899 
    900     ColoredCarFactory factory = injector.getInstance(ColoredCarFactory.class);
    901     Mustang mustang = (Mustang) factory.create(Color.GREEN);
    902     assertEquals(0, invocationCount.get());
    903     mustang.drive();
    904     assertEquals(1, invocationCount.get());
    905   }
    906   /*end[AOP]*/
    907 
    908   /**
    909    * Our factories aren't reusable across injectors. Although this behaviour isn't something we
    910    * like, I have a test case to make sure the error message is pretty.
    911    */
    912   public void testFactoryReuseErrorMessageIsPretty() {
    913     final Provider<ColoredCarFactory> factoryProvider =
    914         FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class);
    915 
    916     Guice.createInjector(
    917         new AbstractModule() {
    918           @Override
    919           protected void configure() {
    920             bind(Double.class).toInstance(5.0d);
    921             bind(ColoredCarFactory.class).toProvider(factoryProvider);
    922           }
    923         });
    924 
    925     try {
    926       Guice.createInjector(
    927           new AbstractModule() {
    928             @Override
    929             protected void configure() {
    930               bind(Double.class).toInstance(5.0d);
    931               bind(ColoredCarFactory.class).toProvider(factoryProvider);
    932             }
    933           });
    934       fail();
    935     } catch (CreationException expected) {
    936       assertContains(
    937           expected.getMessage(), "Factories.create() factories may only be used in one Injector!");
    938     }
    939   }
    940 
    941   public void testNonAssistedFactoryMethodParameter() {
    942     try {
    943       FactoryProvider.newFactory(NamedParameterFactory.class, Mustang.class);
    944       fail();
    945     } catch (ConfigurationException expected) {
    946       assertContains(
    947           expected.getMessage(),
    948           "Only @Assisted is allowed for factory parameters, but found @" + Named.class.getName());
    949     }
    950   }
    951 
    952   interface NamedParameterFactory {
    953     Car create(@Named("seats") int seats, double engineSize);
    954   }
    955 
    956   public void testDefaultAssistedAnnotation() throws NoSuchFieldException {
    957     Assisted plainAssisted =
    958         Subaru.class.getDeclaredField("colorProvider").getAnnotation(Assisted.class);
    959     assertEqualsBothWays(FactoryProvider2.DEFAULT_ANNOTATION, plainAssisted);
    960     assertEquals(FactoryProvider2.DEFAULT_ANNOTATION.toString(), plainAssisted.toString());
    961   }
    962 
    963   interface GenericColoredCarFactory<T extends Car> {
    964     T create(Color color);
    965   }
    966 
    967   public void testGenericAssistedFactory() {
    968     final TypeLiteral<GenericColoredCarFactory<Mustang>> mustangTypeLiteral =
    969         new TypeLiteral<GenericColoredCarFactory<Mustang>>() {};
    970     final TypeLiteral<GenericColoredCarFactory<Camaro>> camaroTypeLiteral =
    971         new TypeLiteral<GenericColoredCarFactory<Camaro>>() {};
    972 
    973     Injector injector =
    974         Guice.createInjector(
    975             new AbstractModule() {
    976               @Override
    977               protected void configure() {
    978                 bind(Double.class).toInstance(5.0d);
    979                 bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250);
    980                 bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984);
    981                 bind(mustangTypeLiteral)
    982                     .toProvider(
    983                         FactoryProvider.newFactory(
    984                             mustangTypeLiteral, TypeLiteral.get(Mustang.class)));
    985                 bind(camaroTypeLiteral)
    986                     .toProvider(
    987                         FactoryProvider.newFactory(
    988                             camaroTypeLiteral, TypeLiteral.get(Camaro.class)));
    989               }
    990             });
    991 
    992     GenericColoredCarFactory<Mustang> mustangFactory =
    993         injector.getInstance(Key.get(mustangTypeLiteral));
    994     GenericColoredCarFactory<Camaro> camaroFactory =
    995         injector.getInstance(Key.get(camaroTypeLiteral));
    996 
    997     Mustang blueMustang = mustangFactory.create(Color.BLUE);
    998     assertEquals(Color.BLUE, blueMustang.color);
    999     assertEquals(5.0d, blueMustang.engineSize, 0.0);
   1000 
   1001     Camaro redCamaro = camaroFactory.create(Color.RED);
   1002     assertEquals(Color.RED, redCamaro.color);
   1003     assertEquals(1984, redCamaro.modelYear);
   1004     assertEquals(250, redCamaro.horsePower);
   1005   }
   1006 
   1007   @SuppressWarnings("unused")
   1008   public interface Insurance<T extends Car> {}
   1009 
   1010   public static class MustangInsurance implements Insurance<Mustang> {
   1011     private final double premium;
   1012     private final double limit;
   1013 
   1014     @SuppressWarnings("unused")
   1015     private Mustang car;
   1016 
   1017     @Inject
   1018     public MustangInsurance(
   1019         @Named("lowLimit") double limit, @Assisted Mustang car, @Assisted double premium) {
   1020       this.premium = premium;
   1021       this.limit = limit;
   1022       this.car = car;
   1023     }
   1024 
   1025     public void sell() {}
   1026   }
   1027 
   1028   public static class CamaroInsurance implements Insurance<Camaro> {
   1029     private final double premium;
   1030     private final double limit;
   1031 
   1032     @SuppressWarnings("unused")
   1033     private Camaro car;
   1034 
   1035     @Inject
   1036     public CamaroInsurance(
   1037         @Named("highLimit") double limit, @Assisted Camaro car, @Assisted double premium) {
   1038       this.premium = premium;
   1039       this.limit = limit;
   1040       this.car = car;
   1041     }
   1042 
   1043     public void sell() {}
   1044   }
   1045 
   1046   public interface MustangInsuranceFactory {
   1047     public Insurance<Mustang> create(Mustang car, double premium);
   1048   }
   1049 
   1050   public interface CamaroInsuranceFactory {
   1051     public Insurance<Camaro> create(Camaro car, double premium);
   1052   }
   1053 
   1054   public void testAssistedFactoryForConcreteType() {
   1055 
   1056     Injector injector =
   1057         Guice.createInjector(
   1058             new AbstractModule() {
   1059               @Override
   1060               protected void configure() {
   1061                 bind(Double.class).annotatedWith(Names.named("lowLimit")).toInstance(50000.0d);
   1062                 bind(Double.class).annotatedWith(Names.named("highLimit")).toInstance(100000.0d);
   1063                 bind(MustangInsuranceFactory.class)
   1064                     .toProvider(
   1065                         FactoryProvider.newFactory(
   1066                             MustangInsuranceFactory.class, MustangInsurance.class));
   1067                 bind(CamaroInsuranceFactory.class)
   1068                     .toProvider(
   1069                         FactoryProvider.newFactory(
   1070                             CamaroInsuranceFactory.class, CamaroInsurance.class));
   1071               }
   1072             });
   1073 
   1074     MustangInsuranceFactory mustangInsuranceFactory =
   1075         injector.getInstance(MustangInsuranceFactory.class);
   1076     CamaroInsuranceFactory camaroInsuranceFactory =
   1077         injector.getInstance(CamaroInsuranceFactory.class);
   1078 
   1079     Mustang mustang = new Mustang(5000d, Color.BLACK);
   1080     MustangInsurance mustangPolicy =
   1081         (MustangInsurance) mustangInsuranceFactory.create(mustang, 800.0d);
   1082     assertEquals(800.0d, mustangPolicy.premium, 0.0);
   1083     assertEquals(50000.0d, mustangPolicy.limit, 0.0);
   1084 
   1085     Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
   1086     CamaroInsurance camaroPolicy = (CamaroInsurance) camaroInsuranceFactory.create(camaro, 800.0d);
   1087     assertEquals(800.0d, camaroPolicy.premium, 0.0);
   1088     assertEquals(100000.0d, camaroPolicy.limit, 0.0);
   1089   }
   1090 
   1091   public interface InsuranceFactory<T extends Car> {
   1092     public Insurance<T> create(T car, double premium);
   1093   }
   1094 
   1095   public void testAssistedFactoryForParameterizedType() {
   1096     final TypeLiteral<InsuranceFactory<Mustang>> mustangInsuranceFactoryType =
   1097         new TypeLiteral<InsuranceFactory<Mustang>>() {};
   1098     final TypeLiteral<InsuranceFactory<Camaro>> camaroInsuranceFactoryType =
   1099         new TypeLiteral<InsuranceFactory<Camaro>>() {};
   1100 
   1101     Injector injector =
   1102         Guice.createInjector(
   1103             new AbstractModule() {
   1104               @Override
   1105               protected void configure() {
   1106                 bind(Double.class).annotatedWith(Names.named("lowLimit")).toInstance(50000.0d);
   1107                 bind(Double.class).annotatedWith(Names.named("highLimit")).toInstance(100000.0d);
   1108                 bind(mustangInsuranceFactoryType)
   1109                     .toProvider(
   1110                         FactoryProvider.newFactory(
   1111                             mustangInsuranceFactoryType, TypeLiteral.get(MustangInsurance.class)));
   1112                 bind(camaroInsuranceFactoryType)
   1113                     .toProvider(
   1114                         FactoryProvider.newFactory(
   1115                             camaroInsuranceFactoryType, TypeLiteral.get(CamaroInsurance.class)));
   1116               }
   1117             });
   1118 
   1119     InsuranceFactory<Mustang> mustangInsuranceFactory =
   1120         injector.getInstance(Key.get(mustangInsuranceFactoryType));
   1121     InsuranceFactory<Camaro> camaroInsuranceFactory =
   1122         injector.getInstance(Key.get(camaroInsuranceFactoryType));
   1123 
   1124     Mustang mustang = new Mustang(5000d, Color.BLACK);
   1125     MustangInsurance mustangPolicy =
   1126         (MustangInsurance) mustangInsuranceFactory.create(mustang, 800.0d);
   1127     assertEquals(800.0d, mustangPolicy.premium, 0.0);
   1128     assertEquals(50000.0d, mustangPolicy.limit, 0.0);
   1129 
   1130     Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
   1131     CamaroInsurance camaroPolicy = (CamaroInsurance) camaroInsuranceFactory.create(camaro, 800.0d);
   1132     assertEquals(800.0d, camaroPolicy.premium, 0.0);
   1133     assertEquals(100000.0d, camaroPolicy.limit, 0.0);
   1134   }
   1135 
   1136   public static class AutoInsurance<T extends Car> implements Insurance<T> {
   1137     private final double premium;
   1138     private final double limit;
   1139     private final T car;
   1140 
   1141     @Inject
   1142     public AutoInsurance(double limit, @Assisted T car, @Assisted double premium) {
   1143       this.limit = limit;
   1144       this.car = car;
   1145       this.premium = premium;
   1146     }
   1147 
   1148     public void sell() {}
   1149   }
   1150 
   1151   public void testAssistedFactoryForTypeVariableParameters() {
   1152     final TypeLiteral<InsuranceFactory<Camaro>> camaroInsuranceFactoryType =
   1153         new TypeLiteral<InsuranceFactory<Camaro>>() {};
   1154 
   1155     Injector injector =
   1156         Guice.createInjector(
   1157             new AbstractModule() {
   1158               @Override
   1159               protected void configure() {
   1160                 bind(Double.class).toInstance(50000.0d);
   1161                 bind(camaroInsuranceFactoryType)
   1162                     .toProvider(
   1163                         FactoryProvider.newFactory(
   1164                             camaroInsuranceFactoryType,
   1165                             new TypeLiteral<AutoInsurance<Camaro>>() {}));
   1166               }
   1167             });
   1168 
   1169     InsuranceFactory<Camaro> camaroInsuranceFactory =
   1170         injector.getInstance(Key.get(camaroInsuranceFactoryType));
   1171 
   1172     Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
   1173     AutoInsurance<?> camaroPolicy =
   1174         (AutoInsurance<?>) camaroInsuranceFactory.create(camaro, 800.0d);
   1175     assertEquals(800.0d, camaroPolicy.premium, 0.0);
   1176     assertEquals(50000.0d, camaroPolicy.limit, 0.0);
   1177     assertEquals(camaro, camaroPolicy.car);
   1178   }
   1179 
   1180   public void testInjectingAndUsingInjector() {
   1181     Injector injector =
   1182         Guice.createInjector(
   1183             new AbstractModule() {
   1184               @Override
   1185               protected void configure() {
   1186                 bind(ColoredCarFactory.class)
   1187                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Segway.class));
   1188               }
   1189             });
   1190 
   1191     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
   1192     Segway green = (Segway) carFactory.create(Color.GREEN);
   1193     assertSame(Color.GREEN, green.getColor());
   1194     assertSame(Color.GREEN, green.getColor());
   1195 
   1196     Segway pink = (Segway) carFactory.create(Color.PINK);
   1197     assertSame(Color.PINK, pink.getColor());
   1198     assertSame(Color.PINK, pink.getColor());
   1199     assertSame(Color.GREEN, green.getColor());
   1200   }
   1201 
   1202   public void testDuplicateAssistedFactoryBinding() {
   1203     Injector injector =
   1204         Guice.createInjector(
   1205             new AbstractModule() {
   1206               @Override
   1207               protected void configure() {
   1208                 bind(Double.class).toInstance(5.0d);
   1209                 bind(ColoredCarFactory.class)
   1210                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
   1211                 bind(ColoredCarFactory.class)
   1212                     .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
   1213               }
   1214             });
   1215     ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
   1216 
   1217     Mustang blueMustang = (Mustang) carFactory.create(Color.BLUE);
   1218     assertEquals(Color.BLUE, blueMustang.color);
   1219     assertEquals(5.0d, blueMustang.engineSize, 0.0);
   1220 
   1221     Mustang redMustang = (Mustang) carFactory.create(Color.RED);
   1222     assertEquals(Color.RED, redMustang.color);
   1223     assertEquals(5.0d, redMustang.engineSize, 0.0);
   1224   }
   1225 
   1226   public interface Equals {
   1227 
   1228     enum ComparisonMethod {
   1229       SHALLOW,
   1230       DEEP;
   1231     }
   1232 
   1233     interface Factory {
   1234       Equals equals(Equals.ComparisonMethod comparisonMethod);
   1235     }
   1236 
   1237     public static class Impl implements Equals {
   1238       private final double sigma;
   1239       private final ComparisonMethod comparisonMethod;
   1240 
   1241       @AssistedInject
   1242       public Impl(double sigma, @Assisted ComparisonMethod comparisonMethod) {
   1243         this.sigma = sigma;
   1244         this.comparisonMethod = comparisonMethod;
   1245       }
   1246     }
   1247   }
   1248 
   1249   public void testFactoryMethodCalledEquals() {
   1250     Injector injector =
   1251         Guice.createInjector(
   1252             new AbstractModule() {
   1253               @Override
   1254               protected void configure() {
   1255                 bind(Double.class).toInstance(0.01d);
   1256                 bind(Equals.Factory.class)
   1257                     .toProvider(
   1258                         FactoryProvider.newFactory(Equals.Factory.class, Equals.Impl.class));
   1259               }
   1260             });
   1261     Equals.Factory equalsFactory = injector.getInstance(Equals.Factory.class);
   1262     Equals.Impl shallowEquals = (Impl) equalsFactory.equals(ComparisonMethod.SHALLOW);
   1263     assertEquals(ComparisonMethod.SHALLOW, shallowEquals.comparisonMethod);
   1264     assertEquals(0.01d, shallowEquals.sigma, 0.0);
   1265   }
   1266 
   1267   static class Segway implements Car {
   1268     @Inject Injector injector;
   1269 
   1270     Color getColor() {
   1271       return injector.getInstance(Key.get(Color.class, FactoryProvider2.DEFAULT_ANNOTATION));
   1272     }
   1273   }
   1274 
   1275   public void testReturnValueMatchesParamValue() {
   1276     Injector injector =
   1277         Guice.createInjector(
   1278             new AbstractModule() {
   1279               @Override
   1280               public void configure() {
   1281                 install(new FactoryModuleBuilder().build(Delegater.Factory.class));
   1282               }
   1283             });
   1284     Delegater delegate = new Delegater();
   1285     Delegater user = injector.getInstance(Delegater.Factory.class).create(delegate);
   1286     assertSame(delegate, user.delegate);
   1287   }
   1288 
   1289   static class Delegater {
   1290     interface Factory {
   1291       Delegater create(Delegater delegate);
   1292     }
   1293 
   1294     private final Delegater delegate;
   1295 
   1296     @Inject
   1297     Delegater(@Assisted Delegater delegater) {
   1298       this.delegate = delegater;
   1299     }
   1300 
   1301     Delegater() {
   1302       this.delegate = null;
   1303     }
   1304   }
   1305 
   1306   public abstract static class AbstractAssisted {
   1307     interface Factory<O extends AbstractAssisted, I extends CharSequence> {
   1308       O create(I string);
   1309     }
   1310   }
   1311 
   1312   static class ConcreteAssisted extends AbstractAssisted {
   1313     @Inject
   1314     ConcreteAssisted(@SuppressWarnings("unused") @Assisted String string) {}
   1315   }
   1316 
   1317   static class ConcreteAssistedWithOverride extends AbstractAssisted {
   1318     @AssistedInject
   1319     ConcreteAssistedWithOverride(@SuppressWarnings("unused") @Assisted String string) {}
   1320 
   1321     @AssistedInject
   1322     ConcreteAssistedWithOverride(@SuppressWarnings("unused") @Assisted StringBuilder sb) {}
   1323 
   1324     interface Factory extends AbstractAssisted.Factory<ConcreteAssistedWithOverride, String> {
   1325       @Override
   1326       ConcreteAssistedWithOverride create(String string);
   1327     }
   1328 
   1329     interface Factory2 extends AbstractAssisted.Factory<ConcreteAssistedWithOverride, String> {
   1330       @Override
   1331       ConcreteAssistedWithOverride create(String string);
   1332 
   1333       ConcreteAssistedWithOverride create(StringBuilder sb);
   1334     }
   1335   }
   1336 
   1337   static class ConcreteAssistedWithoutOverride extends AbstractAssisted {
   1338     @Inject
   1339     ConcreteAssistedWithoutOverride(@SuppressWarnings("unused") @Assisted String string) {}
   1340 
   1341     interface Factory extends AbstractAssisted.Factory<ConcreteAssistedWithoutOverride, String> {}
   1342   }
   1343 
   1344   public static class Public extends AbstractAssisted {
   1345     @AssistedInject
   1346     Public(@SuppressWarnings("unused") @Assisted String string) {}
   1347 
   1348     @AssistedInject
   1349     Public(@SuppressWarnings("unused") @Assisted StringBuilder sb) {}
   1350 
   1351     public interface Factory extends AbstractAssisted.Factory<Public, String> {
   1352       @Override
   1353       Public create(String string);
   1354 
   1355       Public create(StringBuilder sb);
   1356     }
   1357   }
   1358 
   1359   // See https://github.com/google/guice/issues/904
   1360   public void testGeneratedDefaultMethodsForwardCorrectly() {
   1361     final Key<AbstractAssisted.Factory<ConcreteAssisted, String>> concreteKey =
   1362         new Key<AbstractAssisted.Factory<ConcreteAssisted, String>>() {};
   1363     Injector injector =
   1364         Guice.createInjector(
   1365             new AbstractModule() {
   1366               @Override
   1367               protected void configure() {
   1368                 install(
   1369                     new FactoryModuleBuilder().build(ConcreteAssistedWithOverride.Factory.class));
   1370                 install(
   1371                     new FactoryModuleBuilder().build(ConcreteAssistedWithOverride.Factory2.class));
   1372                 install(
   1373                     new FactoryModuleBuilder()
   1374                         .build(ConcreteAssistedWithoutOverride.Factory.class));
   1375                 install(new FactoryModuleBuilder().build(Public.Factory.class));
   1376                 install(new FactoryModuleBuilder().build(concreteKey));
   1377               }
   1378             });
   1379 
   1380     ConcreteAssistedWithOverride.Factory factory1 =
   1381         injector.getInstance(ConcreteAssistedWithOverride.Factory.class);
   1382     factory1.create("foo");
   1383     AbstractAssisted.Factory<ConcreteAssistedWithOverride, String> factory1Abstract = factory1;
   1384     factory1Abstract.create("foo");
   1385 
   1386     ConcreteAssistedWithOverride.Factory2 factory2 =
   1387         injector.getInstance(ConcreteAssistedWithOverride.Factory2.class);
   1388     factory2.create("foo");
   1389     factory2.create(new StringBuilder("foo"));
   1390     AbstractAssisted.Factory<ConcreteAssistedWithOverride, String> factory2Abstract = factory2;
   1391     factory2Abstract.create("foo");
   1392 
   1393     ConcreteAssistedWithoutOverride.Factory factory3 =
   1394         injector.getInstance(ConcreteAssistedWithoutOverride.Factory.class);
   1395     factory3.create("foo");
   1396     AbstractAssisted.Factory<ConcreteAssistedWithoutOverride, String> factory3Abstract = factory3;
   1397     factory3Abstract.create("foo");
   1398 
   1399     Public.Factory factory4 = injector.getInstance(Public.Factory.class);
   1400     factory4.create("foo");
   1401     factory4.create(new StringBuilder("foo"));
   1402     AbstractAssisted.Factory<Public, String> factory4Abstract = factory4;
   1403     factory4Abstract.create("foo");
   1404 
   1405     AbstractAssisted.Factory<ConcreteAssisted, String> factory5 = injector.getInstance(concreteKey);
   1406     factory5.create("foo");
   1407   }
   1408 }
   1409