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