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 
testAssistedFactory()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 
testAssistedFactoryWithAnnotations()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 {
create(Color color)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
Mustang(double engineSize, @Assisted Color color)116     public Mustang(double engineSize, @Assisted Color color) {
117       this.engineSize = engineSize;
118       this.color = color;
119     }
120 
drive()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
Camaro( @amed"horsePower") int horsePower, @Named("modelYear") int modelYear, @Assisted Color color)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 {
create(Color color, boolean convertable)141     Car create(Color color, boolean convertable);
142   }
143 
testFactoryUsesInjectedConstructor()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")
Corvette(Color color, boolean isConvertable)170     public Corvette(Color color, boolean isConvertable) {
171       throw new IllegalStateException("Not an @AssistedInject constructor");
172     }
173 
174     @Inject
Corvette(@ssisted Color color, Float maxMph, @Assisted boolean isConvertable)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 
testConstructorDoesntNeedAllFactoryMethodArguments()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
Beetle(@ssisted Color color)202     public Beetle(@Assisted Color color) {
203       this.color = color;
204     }
205   }
206 
testMethodsAndFieldsGetInjected()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
Porsche(@ssisted Color color, double price)236     public Porsche(@Assisted Color color, double price) {
237       this.color = color;
238       this.price = price;
239     }
240 
241     @Inject
setModel(int model)242     void setModel(int model) {
243       this.model = model;
244     }
245   }
246 
testProviderInjection()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
Firebird(Provider<String> modifiersProvider, @Assisted Color color)271     public Firebird(Provider<String> modifiersProvider, @Assisted Color color) {
272       this.modifiersProvider = modifiersProvider;
273       this.color = color;
274     }
275   }
276 
testAssistedProviderInjection()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
Flamingbird( Provider<String> modifiersProvider, @Assisted Provider<Color> colorProvider)307     public Flamingbird(
308         Provider<String> modifiersProvider, @Assisted Provider<Color> colorProvider) {
309       this.modifiersProvider = modifiersProvider;
310       this.colorProvider = colorProvider;
311     }
312   }
313 
testTypeTokenInjection()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
DeLorean( Set<String> extraFeatures, Set<Integer> featureActivationSpeeds, @Assisted Color color)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 
testTypeTokenProviderInjection()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
Z(Provider<Set<String>> manufacturersProvider, @Assisted Color color)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
Prius(@ssisted Color color)383     private Prius(@Assisted Color color) {
384       this.color = color;
385     }
386   }
387 
testAssistInjectionInNonPublicConstructor()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
ExplodingCar(@uppressWarnings"unused") @ssisted Color color)404     public ExplodingCar(@SuppressWarnings("unused") @Assisted Color color) {
405       throw new IllegalStateException("kaboom!");
406     }
407   }
408 
testExceptionDuringConstruction()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
DefectiveCar()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 {
createCar()440     Car createCar();
441   }
442 
443   public interface DefectiveCarFactory {
createCar()444     Car createCar() throws FireException;
445   }
446 
447   public interface CorrectDefectiveCarFactory {
createCar()448     Car createCar() throws FireException, ExplosionException;
449   }
450 
testConstructorExceptionsAreThrownByFactory()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 {
create(Collection<?> items)475       WildcardCollection create(Collection<?> items);
476     }
477 
478     @Inject
WildcardCollection(@uppressWarnings"unused") @ssisted Collection<?> items)479     public WildcardCollection(@SuppressWarnings("unused") @Assisted Collection<?> items) {}
480   }
481 
testWildcardGenerics()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
Fiat(SteeringWheel steeringWheel, @Assisted Color color)505     public Fiat(SteeringWheel steeringWheel, @Assisted Color color) {
506       this.steeringWheel = steeringWheel;
507       this.color = color;
508     }
509   }
510 
testFactoryWithImplicitBindings()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 
testFactoryFailsWithMissingBinding()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 
testFactoryFailsWithMissingBindingInToolStage()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 
testMethodsDeclaredInObject()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 
testInjectingProviderOfParameter()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 
testInjectingNullParameter()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 {
createCar(Provider<Color> colorProvider, Provider<String> stringProvider)632     Car createCar(Provider<Color> colorProvider, Provider<String> stringProvider);
633 
createMustang(@ssisted"color") Provider<Color> colorProvider)634     Mustang createMustang(@Assisted("color") Provider<Color> colorProvider);
635   }
636 
testAssistedProviderIsDisallowed()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 {
createCar( javax.inject.Provider<Color> colorProvider, javax.inject.Provider<String> stringProvider)690     Car createCar(
691         javax.inject.Provider<Color> colorProvider, javax.inject.Provider<String> stringProvider);
692 
createMustang(@ssisted"color") javax.inject.Provider<Color> colorProvider)693     Mustang createMustang(@Assisted("color") javax.inject.Provider<Color> colorProvider);
694   }
695 
testAssistedJavaxProviderIsDisallowed()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 
testFactoryUseBeforeInitialization()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 {
create(Color color)761     Mustang create(Color color);
762   }
763 
testFactoryBuildingConcreteTypes()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 {
createFleet(Color color)789     Fleet createFleet(Color color);
790   }
791 
testInjectDeepIntoConstructedObjects()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 {
create(@ssisted"paint") Color paint, @Assisted("fabric") Color fabric)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 
testDistinctKeys()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 {
create(@ssisted"paint") Color paint, @Assisted("paint") Color morePaint)848     Car create(@Assisted("paint") Color paint, @Assisted("paint") Color morePaint);
849   }
850 
testDuplicateKeys()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]*/
testMethodInterceptorsOnAssistedTypes()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    */
testFactoryReuseErrorMessageIsPretty()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 
testNonAssistedFactoryMethodParameter()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 {
create(@amed"seats") int seats, double engineSize)953     Car create(@Named("seats") int seats, double engineSize);
954   }
955 
testDefaultAssistedAnnotation()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> {
create(Color color)964     T create(Color color);
965   }
966 
testGenericAssistedFactory()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
MustangInsurance( @amed"lowLimit") double limit, @Assisted Mustang car, @Assisted double premium)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 
sell()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
CamaroInsurance( @amed"highLimit") double limit, @Assisted Camaro car, @Assisted double premium)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 
sell()1043     public void sell() {}
1044   }
1045 
1046   public interface MustangInsuranceFactory {
create(Mustang car, double premium)1047     public Insurance<Mustang> create(Mustang car, double premium);
1048   }
1049 
1050   public interface CamaroInsuranceFactory {
create(Camaro car, double premium)1051     public Insurance<Camaro> create(Camaro car, double premium);
1052   }
1053 
testAssistedFactoryForConcreteType()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> {
create(T car, double premium)1092     public Insurance<T> create(T car, double premium);
1093   }
1094 
testAssistedFactoryForParameterizedType()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
AutoInsurance(double limit, @Assisted T car, @Assisted double premium)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 
sell()1148     public void sell() {}
1149   }
1150 
testAssistedFactoryForTypeVariableParameters()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 
testInjectingAndUsingInjector()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 
testDuplicateAssistedFactoryBinding()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 {
equals(Equals.ComparisonMethod comparisonMethod)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
Impl(double sigma, @Assisted ComparisonMethod comparisonMethod)1242       public Impl(double sigma, @Assisted ComparisonMethod comparisonMethod) {
1243         this.sigma = sigma;
1244         this.comparisonMethod = comparisonMethod;
1245       }
1246     }
1247   }
1248 
testFactoryMethodCalledEquals()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 
getColor()1270     Color getColor() {
1271       return injector.getInstance(Key.get(Color.class, FactoryProvider2.DEFAULT_ANNOTATION));
1272     }
1273   }
1274 
testReturnValueMatchesParamValue()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 {
create(Delegater delegate)1291       Delegater create(Delegater delegate);
1292     }
1293 
1294     private final Delegater delegate;
1295 
1296     @Inject
Delegater(@ssisted Delegater delegater)1297     Delegater(@Assisted Delegater delegater) {
1298       this.delegate = delegater;
1299     }
1300 
Delegater()1301     Delegater() {
1302       this.delegate = null;
1303     }
1304   }
1305 
1306   public abstract static class AbstractAssisted {
1307     interface Factory<O extends AbstractAssisted, I extends CharSequence> {
create(I string)1308       O create(I string);
1309     }
1310   }
1311 
1312   static class ConcreteAssisted extends AbstractAssisted {
1313     @Inject
ConcreteAssisted(@uppressWarnings"unused") @ssisted String string)1314     ConcreteAssisted(@SuppressWarnings("unused") @Assisted String string) {}
1315   }
1316 
1317   static class ConcreteAssistedWithOverride extends AbstractAssisted {
1318     @AssistedInject
ConcreteAssistedWithOverride(@uppressWarnings"unused") @ssisted String string)1319     ConcreteAssistedWithOverride(@SuppressWarnings("unused") @Assisted String string) {}
1320 
1321     @AssistedInject
ConcreteAssistedWithOverride(@uppressWarnings"unused") @ssisted StringBuilder sb)1322     ConcreteAssistedWithOverride(@SuppressWarnings("unused") @Assisted StringBuilder sb) {}
1323 
1324     interface Factory extends AbstractAssisted.Factory<ConcreteAssistedWithOverride, String> {
1325       @Override
create(String string)1326       ConcreteAssistedWithOverride create(String string);
1327     }
1328 
1329     interface Factory2 extends AbstractAssisted.Factory<ConcreteAssistedWithOverride, String> {
1330       @Override
create(String string)1331       ConcreteAssistedWithOverride create(String string);
1332 
create(StringBuilder sb)1333       ConcreteAssistedWithOverride create(StringBuilder sb);
1334     }
1335   }
1336 
1337   static class ConcreteAssistedWithoutOverride extends AbstractAssisted {
1338     @Inject
ConcreteAssistedWithoutOverride(@uppressWarnings"unused") @ssisted String string)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
Public(@uppressWarnings"unused") @ssisted String string)1346     Public(@SuppressWarnings("unused") @Assisted String string) {}
1347 
1348     @AssistedInject
Public(@uppressWarnings"unused") @ssisted StringBuilder sb)1349     Public(@SuppressWarnings("unused") @Assisted StringBuilder sb) {}
1350 
1351     public interface Factory extends AbstractAssisted.Factory<Public, String> {
1352       @Override
create(String string)1353       Public create(String string);
1354 
create(StringBuilder sb)1355       Public create(StringBuilder sb);
1356     }
1357   }
1358 
1359   // See https://github.com/google/guice/issues/904
testGeneratedDefaultMethodsForwardCorrectly()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