• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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.spi;
18 
19 import static com.google.inject.Asserts.assertContains;
20 import static java.lang.annotation.RetentionPolicy.RUNTIME;
21 
22 import com.google.common.collect.ImmutableList;
23 import com.google.common.collect.ImmutableSet;
24 import com.google.common.collect.Iterables;
25 import com.google.common.collect.Lists;
26 import com.google.inject.AbstractModule;
27 import com.google.inject.Binder;
28 import com.google.inject.Binding;
29 import com.google.inject.BindingAnnotation;
30 import com.google.inject.CreationException;
31 import com.google.inject.Guice;
32 import com.google.inject.Inject;
33 import com.google.inject.Injector;
34 import com.google.inject.Key;
35 import com.google.inject.Module;
36 import com.google.inject.Provider;
37 import com.google.inject.Provides;
38 import com.google.inject.ProvisionException;
39 import com.google.inject.Singleton;
40 import com.google.inject.Stage;
41 import com.google.inject.TypeLiteral;
42 import com.google.inject.internal.Errors;
43 import com.google.inject.internal.InternalFlags;
44 import com.google.inject.internal.ProviderMethod;
45 import com.google.inject.internal.ProviderMethodsModule;
46 import com.google.inject.name.Named;
47 import com.google.inject.name.Names;
48 import com.google.inject.util.Providers;
49 import com.google.inject.util.Types;
50 import java.lang.annotation.ElementType;
51 import java.lang.annotation.Retention;
52 import java.lang.annotation.RetentionPolicy;
53 import java.lang.annotation.Target;
54 import java.lang.reflect.Method;
55 import java.util.ArrayList;
56 import java.util.Collection;
57 import java.util.List;
58 import java.util.Set;
59 import java.util.concurrent.atomic.AtomicReference;
60 import java.util.logging.Handler;
61 import java.util.logging.LogRecord;
62 import java.util.logging.Logger;
63 import junit.framework.TestCase;
64 
65 /** @author crazybob@google.com (Bob Lee) */
66 @SuppressWarnings("ProvidesMethodOutsideOfModule")
67 public class ProviderMethodsTest extends TestCase implements Module {
68 
69   @SuppressWarnings("unchecked")
testProviderMethods()70   public void testProviderMethods() {
71     Injector injector = Guice.createInjector(this);
72 
73     Bob bob = injector.getInstance(Bob.class);
74     assertEquals("A Bob", bob.getName());
75 
76     Bob clone = injector.getInstance(Bob.class);
77     assertEquals("A Bob", clone.getName());
78 
79     assertNotSame(bob, clone);
80     assertSame(bob.getDaughter(), clone.getDaughter());
81 
82     Key soleBobKey = Key.get(Bob.class, Sole.class);
83     assertSame(injector.getInstance(soleBobKey), injector.getInstance(soleBobKey));
84   }
85 
86   @Override
configure(Binder binder)87   public void configure(Binder binder) {}
88 
89   interface Bob {
getName()90     String getName();
91 
getDaughter()92     Dagny getDaughter();
93   }
94 
95   interface Dagny {
getAge()96     int getAge();
97   }
98 
99   @Provides
provideBob(final Dagny dagny)100   Bob provideBob(final Dagny dagny) {
101     return new Bob() {
102       @Override
103       public String getName() {
104         return "A Bob";
105       }
106 
107       @Override
108       public Dagny getDaughter() {
109         return dagny;
110       }
111     };
112   }
113 
114   @Provides
115   @Singleton
116   @Sole
117   Bob provideSoleBob(final Dagny dagny) {
118     return new Bob() {
119       @Override
120       public String getName() {
121         return "Only Bob";
122       }
123 
124       @Override
125       public Dagny getDaughter() {
126         return dagny;
127       }
128     };
129   }
130 
131   @Provides
132   @Singleton
133   Dagny provideDagny() {
134     return new Dagny() {
135       @Override
136       public int getAge() {
137         return 1;
138       }
139     };
140   }
141 
142   @Retention(RUNTIME)
143   @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
144   @BindingAnnotation
145   @interface Sole {}
146 
147   public void testCircularDependency() {
148     Injector injector =
149         Guice.createInjector(
150             new AbstractModule() {
151 
152               @Provides
153               Foo newFoo(final Bar bar) {
154                 return new Foo() {
155 
156                   @Override
157                   public Bar getBar() {
158                     return bar;
159                   }
160 
161                   @Override
162                   public int getI() {
163                     return 5;
164                   }
165                 };
166               }
167 
168               @Provides
169               Bar newBar(final Foo foo) {
170                 return new Bar() {
171 
172                   @Override
173                   public Foo getFoo() {
174                     return foo;
175                   }
176 
177                   @Override
178                   public int getI() {
179                     return 10;
180                   }
181                 };
182               }
183             });
184 
185     Foo foo = injector.getInstance(Foo.class);
186     assertEquals(5, foo.getI());
187     assertEquals(10, foo.getBar().getI());
188     assertEquals(5, foo.getBar().getFoo().getI());
189   }
190 
191   public interface Foo {
192     Bar getBar();
193 
194     int getI();
195   }
196 
197   public interface Bar {
198     Foo getFoo();
199 
200     int getI();
201   }
202 
203   public void testMultipleBindingAnnotations() {
204     try {
205       Guice.createInjector(
206           new AbstractModule() {
207 
208             @Provides
209             @Named("A")
210             @Blue
211             public String provideString() {
212               return "a";
213             }
214           });
215       fail();
216     } catch (CreationException expected) {
217       assertContains(
218           expected.getMessage(),
219           "more than one annotation annotated with @BindingAnnotation:",
220           "Named",
221           "Blue",
222           "at " + getClass().getName(),
223           ".provideString(ProviderMethodsTest.java:");
224     }
225   }
226 
227   @Retention(RUNTIME)
228   @BindingAnnotation
229   @interface Blue {}
230 
231   public void testGenericProviderMethods() {
232     Injector injector =
233         Guice.createInjector(new ProvideTs<String>("A", "B") {}, new ProvideTs<Integer>(1, 2) {});
234 
235     assertEquals("A", injector.getInstance(Key.get(String.class, Names.named("First"))));
236     assertEquals("B", injector.getInstance(Key.get(String.class, Names.named("Second"))));
237     assertEquals(
238         ImmutableSet.of("A", "B"), injector.getInstance(Key.get(Types.setOf(String.class))));
239 
240     assertEquals(1, injector.getInstance(Key.get(Integer.class, Names.named("First"))).intValue());
241     assertEquals(2, injector.getInstance(Key.get(Integer.class, Names.named("Second"))).intValue());
242     assertEquals(ImmutableSet.of(1, 2), injector.getInstance(Key.get(Types.setOf(Integer.class))));
243   }
244 
245   abstract class ProvideTs<T> extends AbstractModule {
246     final T first;
247     final T second;
248 
249     protected ProvideTs(T first, T second) {
250       this.first = first;
251       this.second = second;
252     }
253 
254     @Named("First")
255     @Provides
256     T provideFirst() {
257       return first;
258     }
259 
260     @Named("Second")
261     @Provides
262     T provideSecond() {
263       return second;
264     }
265 
266     @Provides
267     Set<T> provideBoth(@Named("First") T first, @Named("Second") T second) {
268       return ImmutableSet.of(first, second);
269     }
270   }
271 
272   public void testAutomaticProviderMethods() {
273     Injector injector =
274         Guice.createInjector(
275             (Module)
276                 new AbstractModule() {
277 
278                   private int next = 1;
279 
280                   @Provides
281                   @Named("count")
282                   public Integer provideCount() {
283                     return next++;
284                   }
285                 });
286 
287     assertEquals(1, injector.getInstance(Key.get(Integer.class, Names.named("count"))).intValue());
288     assertEquals(2, injector.getInstance(Key.get(Integer.class, Names.named("count"))).intValue());
289     assertEquals(3, injector.getInstance(Key.get(Integer.class, Names.named("count"))).intValue());
290   }
291 
292   /**
293    * If the user installs provider methods for the module manually, that shouldn't cause a double
294    * binding of the provider methods' types.
295    */
296   public void testAutomaticProviderMethodsDoNotCauseDoubleBinding() {
297     Module installsSelf =
298         new AbstractModule() {
299           @Override
300           protected void configure() {
301             install(this);
302             bind(Integer.class).toInstance(5);
303           }
304 
305           @Provides
306           public String provideString(Integer count) {
307             return "A" + count;
308           }
309         };
310 
311     Injector injector = Guice.createInjector(installsSelf);
312     assertEquals("A5", injector.getInstance(String.class));
313   }
314 
315   public void testWildcardProviderMethods() {
316     final List<String> strings = ImmutableList.of("A", "B", "C");
317     final List<Number> numbers = ImmutableList.<Number>of(1, 2, 3);
318 
319     Injector injector =
320         Guice.createInjector(
321             new AbstractModule() {
322               @Override
323               protected void configure() {
324                 @SuppressWarnings("unchecked")
325                 Key<List<? super Integer>> listOfSupertypesOfInteger =
326                     (Key<List<? super Integer>>)
327                         Key.get(Types.listOf(Types.supertypeOf(Integer.class)));
328                 bind(listOfSupertypesOfInteger).toInstance(numbers);
329               }
330 
331               @Provides
332               public List<? extends CharSequence> provideCharSequences() {
333                 return strings;
334               }
335 
336               @Provides
337               public Class<?> provideType() {
338                 return Float.class;
339               }
340             });
341 
342     assertSame(strings, injector.getInstance(HasWildcardInjection.class).charSequences);
343     assertSame(numbers, injector.getInstance(HasWildcardInjection.class).numbers);
344     assertSame(Float.class, injector.getInstance(HasWildcardInjection.class).type);
345   }
346 
347   static class HasWildcardInjection {
348     @Inject List<? extends CharSequence> charSequences;
349     @Inject List<? super Integer> numbers;
350     @Inject Class<?> type;
351   }
352 
353   public void testProviderMethodDependenciesAreExposed() throws Exception {
354     Module module =
355         new AbstractModule() {
356           @Override
357           protected void configure() {
358             bind(Integer.class).toInstance(50);
359             bindConstant().annotatedWith(Names.named("units")).to("Kg");
360           }
361 
362           @Provides
363           @Named("weight")
364           String provideWeight(Integer count, @Named("units") String units) {
365             return count + units;
366           }
367         };
368     Injector injector = Guice.createInjector(module);
369 
370     ProviderInstanceBinding<?> binding =
371         (ProviderInstanceBinding<?>)
372             injector.getBinding(Key.get(String.class, Names.named("weight")));
373     Method method =
374         module.getClass().getDeclaredMethod("provideWeight", Integer.class, String.class);
375     InjectionPoint point = new InjectionPoint(TypeLiteral.get(module.getClass()), method, false);
376     assertEquals(
377         ImmutableSet.<Dependency<?>>of(
378             new Dependency<Integer>(point, Key.get(Integer.class), false, 0),
379             new Dependency<String>(point, Key.get(String.class, Names.named("units")), false, 1)),
380         binding.getDependencies());
381   }
382 
383   public void testNonModuleProviderMethods() {
384     final Object methodsObject =
385         new Object() {
386           @Provides
387           @Named("foo")
388           String provideFoo() {
389             return "foo-value";
390           }
391         };
392 
393     Module module =
394         new AbstractModule() {
395           @Override
396           protected void configure() {
397             install(ProviderMethodsModule.forObject(methodsObject));
398           }
399         };
400 
401     Injector injector = Guice.createInjector(module);
402 
403     Key<String> key = Key.get(String.class, Names.named("foo"));
404     assertEquals("foo-value", injector.getInstance(key));
405 
406     // Test the provider method object itself. This makes sure getInstance works, since GIN uses it
407     List<Element> elements = Elements.getElements(module);
408     assertEquals(1, elements.size());
409 
410     Element element = elements.get(0);
411     assertTrue(
412         element + " instanceof ProviderInstanceBinding",
413         element instanceof ProviderInstanceBinding);
414 
415     ProviderInstanceBinding binding = (ProviderInstanceBinding) element;
416     javax.inject.Provider provider = binding.getUserSuppliedProvider();
417     assertTrue(provider instanceof ProviderMethod);
418     assertEquals(methodsObject, ((ProviderMethod) provider).getInstance());
419     assertSame(provider, binding.getProviderInstance());
420   }
421 
422   public void testVoidProviderMethods() {
423     try {
424       Guice.createInjector(
425           new AbstractModule() {
426 
427             @Provides
428             void provideFoo() {}
429           });
430       fail();
431     } catch (CreationException expected) {
432       assertContains(
433           expected.getMessage(),
434           "1) Provider methods must return a value. Do not return void.",
435           getClass().getName(),
436           ".provideFoo(ProviderMethodsTest.java:");
437     }
438   }
439 
440   public void testInjectsJustOneLogger() {
441     AtomicReference<Logger> loggerRef = new AtomicReference<>();
442     Injector injector = Guice.createInjector(new FooModule(loggerRef));
443 
444     assertNull(loggerRef.get());
445     injector.getInstance(Integer.class);
446     Logger lastLogger = loggerRef.getAndSet(null);
447     assertNotNull(lastLogger);
448     injector.getInstance(Integer.class);
449     assertSame(lastLogger, loggerRef.get());
450 
451     assertEquals(FooModule.class.getName(), lastLogger.getName());
452   }
453 
454   private static class FooModule extends AbstractModule {
455     private final AtomicReference<Logger> loggerRef;
456 
457     public FooModule(AtomicReference<Logger> loggerRef) {
458       this.loggerRef = loggerRef;
459     }
460 
461     @SuppressWarnings("unused")
462     @Provides
463     Integer foo(Logger logger) {
464       loggerRef.set(logger);
465       return 42;
466     }
467   }
468 
469   public void testSpi() throws Exception {
470     Module m1 =
471         new AbstractModule() {
472 
473           @Provides
474           @Named("foo")
475           String provideFoo(Integer dep) {
476             return "foo";
477           }
478         };
479     Module m2 =
480         new AbstractModule() {
481 
482           @Provides
483           Integer provideInt(@Named("foo") String dep) {
484             return 42;
485           }
486         };
487     Injector injector = Guice.createInjector(m1, m2);
488 
489     Binding<String> stringBinding = injector.getBinding(Key.get(String.class, Names.named("foo")));
490     ProvidesMethodBinding<String> stringMethod =
491         stringBinding.acceptTargetVisitor(new BindingCapturer<String>());
492     assertEquals(m1, stringMethod.getEnclosingInstance());
493     assertEquals(
494         m1.getClass().getDeclaredMethod("provideFoo", Integer.class), stringMethod.getMethod());
495     assertEquals(
496         ((HasDependencies) stringBinding).getDependencies(), stringMethod.getDependencies());
497     assertEquals(Key.get(String.class, Names.named("foo")), stringMethod.getKey());
498 
499     Binding<Integer> intBinding = injector.getBinding(Integer.class);
500     ProvidesMethodBinding<Integer> intMethod =
501         intBinding.acceptTargetVisitor(new BindingCapturer<Integer>());
502     assertEquals(m2, intMethod.getEnclosingInstance());
503     assertEquals(
504         m2.getClass().getDeclaredMethod("provideInt", String.class), intMethod.getMethod());
505     assertEquals(((HasDependencies) intBinding).getDependencies(), intMethod.getDependencies());
506     assertEquals(Key.get(Integer.class), intMethod.getKey());
507   }
508 
509   private static class BindingCapturer<T>
510       extends DefaultBindingTargetVisitor<T, ProvidesMethodBinding<T>>
511       implements ProvidesMethodTargetVisitor<T, ProvidesMethodBinding<T>> {
512 
513     @Override
514     @SuppressWarnings("unchecked")
515     public ProvidesMethodBinding<T> visit(
516         ProvidesMethodBinding<? extends T> providesMethodBinding) {
517       return (ProvidesMethodBinding<T>) providesMethodBinding;
518     }
519 
520     @Override
521     protected ProvidesMethodBinding<T> visitOther(Binding<? extends T> binding) {
522       throw new IllegalStateException("unexpected visit of: " + binding);
523     }
524   }
525 
526   public void testProvidesMethodVisibility() {
527     Injector injector = Guice.createInjector(new VisibilityModule());
528 
529     assertEquals(42, injector.getInstance(Integer.class).intValue());
530     assertEquals(42L, injector.getInstance(Long.class).longValue());
531     assertEquals(42D, injector.getInstance(Double.class).doubleValue(), 0.0);
532     assertEquals(42F, injector.getInstance(Float.class).floatValue(), 0.0f);
533   }
534 
535   private static class VisibilityModule extends AbstractModule {
536 
537     @SuppressWarnings("unused")
538     @Provides
539     Integer foo() {
540       return 42;
541     }
542 
543     @SuppressWarnings("unused")
544     @Provides
545     private Long bar() {
546       return 42L;
547     }
548 
549     @SuppressWarnings("unused")
550     @Provides
551     protected Double baz() {
552       return 42D;
553     }
554 
555     @SuppressWarnings("unused")
556     @Provides
557     public Float quux() {
558       return 42F;
559     }
560   }
561 
562   public void testProvidesMethodInheritenceHierarchy() {
563     try {
564       Guice.createInjector(new Sub1Module(), new Sub2Module());
565       fail("Expected injector creation failure");
566     } catch (CreationException expected) {
567       // both of our super class bindings cause errors
568       assertContains(
569           expected.getMessage(),
570           "A binding to java.lang.Long was already configured",
571           "A binding to java.lang.Integer was already configured");
572     }
573   }
574 
575   public void testProvidesMethodsDefinedInSuperClass() {
576     Injector injector = Guice.createInjector(new Sub1Module());
577     assertEquals(42, injector.getInstance(Integer.class).intValue());
578     assertEquals(42L, injector.getInstance(Long.class).longValue());
579     assertEquals(42D, injector.getInstance(Double.class).doubleValue(), 0.0);
580   }
581 
582   private static class BaseModule extends AbstractModule {
583 
584     @Provides
585     Integer foo() {
586       return 42;
587     }
588 
589     @Provides
590     Long bar() {
591       return 42L;
592     }
593   }
594 
595   private static class Sub1Module extends BaseModule {
596     @Provides
597     Double baz() {
598       return 42D;
599     }
600   }
601 
602   private static class Sub2Module extends BaseModule {
603     @Provides
604     Float quux() {
605       return 42F;
606     }
607   }
608 
609   /*if[AOP]*/
610   public void testShareFastClass() {
611     CallerInspecterModule module = new CallerInspecterModule();
612     Guice.createInjector(Stage.PRODUCTION, module);
613     assertEquals(module.fooCallerClass, module.barCallerClass);
614     assertTrue(module.fooCallerClass.contains("$$FastClassByGuice$$"));
615   }
616 
617   private static class CallerInspecterModule extends AbstractModule {
618     // start them off as unequal
619     String barCallerClass = "not_set_bar";
620     String fooCallerClass = "not_set_foo";
621 
622     @Provides
623     @Singleton
624     Integer foo() {
625       this.fooCallerClass = new Exception().getStackTrace()[1].getClassName();
626       return 42;
627     }
628 
629     @Provides
630     @Singleton
631     Long bar() {
632       this.barCallerClass = new Exception().getStackTrace()[1].getClassName();
633       return 42L;
634     }
635   }
636 
637   public void testShareFastClassWithSuperClass() {
638     CallerInspecterSubClassModule module = new CallerInspecterSubClassModule();
639     Guice.createInjector(Stage.PRODUCTION, module);
640     assertEquals(
641         "Expected provider methods in the same class to share fastclass classes",
642         module.fooCallerClass,
643         module.barCallerClass);
644     assertFalse(
645         "Did not expect provider methods in the subclasses to share fastclass classes "
646             + "with their parent classes",
647         module.bazCallerClass.equals(module.barCallerClass));
648   }
649 
650   private static class CallerInspecterSubClassModule extends CallerInspecterModule {
651     String bazCallerClass;
652 
653     @Override
654     protected void configure() {}
655 
656     @Provides
657     @Singleton
658     Double baz() {
659       this.bazCallerClass = new Exception().getStackTrace()[1].getClassName();
660       return 42D;
661     }
662   }
663   /*end[AOP]*/
664 
665   static class SuperClassModule extends AbstractModule {
666 
667     @Provides
668     Number providerMethod() {
669       return 1D;
670     }
671 
672     @Provides
673     @Named("rawlist")
674     List rawProvider(@Named("list") List<String> f) {
675       return f;
676     }
677 
678     @Provides
679     @Named("unrawlist")
680     List<String> rawParameterProvider(@Named("rawlist") List f) {
681       return f;
682     }
683 
684     @Provides
685     @Named("list")
686     List<String> annotatedGenericProviderMethod() {
687       return new ArrayList<String>();
688     }
689 
690     @Provides
691     @Named("collection")
692     Collection<String> annotatedGenericParameterProviderMethod(@Named("list") List<String> foo) {
693       return foo;
694     }
695 
696     @Provides
697     private String privateProviderMethod() {
698       return "hello";
699     }
700   }
701 
702   public void testOverrideProviderMethod_overrideHasProvides() {
703     class SubClassModule extends SuperClassModule {
704       @Override
705       @Provides
706       Number providerMethod() {
707         return 2D;
708       }
709     }
710     try {
711       Guice.createInjector(new SubClassModule());
712       fail();
713     } catch (CreationException e) {
714       assertContains(
715           e.getMessage(),
716           "Overriding @Provides methods is not allowed.",
717           "@Provides method: " + SuperClassModule.class.getName() + ".providerMethod()",
718           "overridden by: " + SubClassModule.class.getName() + ".providerMethod()");
719     }
720   }
721 
722   public void testOverrideProviderMethod_overrideHasProvides_withNewAnnotation() {
723     class SubClassModule extends SuperClassModule {
724       @Override
725       @Provides
726       @Named("foo")
727       Number providerMethod() {
728         return 2D;
729       }
730     }
731     try {
732       Guice.createInjector(new SubClassModule());
733       fail();
734     } catch (CreationException e) {
735       assertContains(
736           e.getMessage(),
737           "Overriding @Provides methods is not allowed.",
738           "@Provides method: " + SuperClassModule.class.getName() + ".providerMethod()",
739           "overridden by: " + SubClassModule.class.getName() + ".providerMethod()");
740     }
741   }
742 
743   public void testOverrideProviderMethod_overrideDoesntHaveProvides() {
744     class SubClassModule extends SuperClassModule {
745       @Override
746       Number providerMethod() {
747         return 2D;
748       }
749     }
750     try {
751       Guice.createInjector(new SubClassModule());
752       fail();
753     } catch (CreationException e) {
754       assertContains(
755           e.getMessage(),
756           "Overriding @Provides methods is not allowed.",
757           "@Provides method: " + SuperClassModule.class.getName() + ".providerMethod()",
758           "overridden by: " + SubClassModule.class.getName() + ".providerMethod()");
759     }
760   }
761 
762   public void testOverrideProviderMethod_overrideDoesntHaveProvides_withNewAnnotation() {
763     class SubClassModule extends SuperClassModule {
764       @Override
765       @Named("foo")
766       Number providerMethod() {
767         return 2D;
768       }
769     }
770     try {
771       Guice.createInjector(new SubClassModule());
772       fail();
773     } catch (CreationException e) {
774       assertContains(
775           e.getMessage(),
776           "Overriding @Provides methods is not allowed.",
777           "@Provides method: " + SuperClassModule.class.getName() + ".providerMethod()",
778           "overridden by: " + SubClassModule.class.getName() + ".providerMethod()");
779     }
780   }
781 
782   public void testOverrideProviderMethod_covariantOverrideDoesntHaveProvides() {
783     class SubClassModule extends SuperClassModule {
784       @Override
785       Double providerMethod() {
786         return 2D;
787       }
788     }
789     try {
790       Guice.createInjector(new SubClassModule());
791       fail();
792     } catch (CreationException e) {
793       assertContains(
794           e.getMessage(),
795           "Overriding @Provides methods is not allowed.",
796           "@Provides method: " + SuperClassModule.class.getName() + ".providerMethod()",
797           "overridden by: " + SubClassModule.class.getName() + ".providerMethod()");
798     }
799   }
800 
801   public void testOverrideProviderMethod_covariantOverrideHasProvides() {
802     class SubClassModule extends SuperClassModule {
803       @Override
804       @Provides
805       Double providerMethod() {
806         return 2D;
807       }
808     }
809     try {
810       Guice.createInjector(new SubClassModule());
811       fail();
812     } catch (CreationException e) {
813       assertContains(
814           e.getMessage(),
815           "Overriding @Provides methods is not allowed.",
816           "@Provides method: " + SuperClassModule.class.getName() + ".providerMethod()",
817           "overridden by: " + SubClassModule.class.getName() + ".providerMethod()");
818     }
819   }
820 
821   public void testOverrideProviderMethod_fakeOverridePrivateMethod() {
822     class SubClassModule extends SuperClassModule {
823       // not actually an override, just looks like it
824       String privateProviderMethod() {
825         return "sub";
826       }
827     }
828     assertEquals("hello", Guice.createInjector(new SubClassModule()).getInstance(String.class));
829   }
830 
831   public void testOverrideProviderMethod_subclassRawTypes_returnType() {
832     class SubClassModule extends SuperClassModule {
833       @Override
834       List annotatedGenericProviderMethod() {
835         return super.annotatedGenericProviderMethod();
836       }
837     }
838     try {
839       Guice.createInjector(new SubClassModule());
840       fail();
841     } catch (CreationException e) {
842       assertContains(
843           e.getMessage(),
844           "Overriding @Provides methods is not allowed.",
845           "@Provides method: "
846               + SuperClassModule.class.getName()
847               + ".annotatedGenericProviderMethod()",
848           "overridden by: " + SubClassModule.class.getName() + ".annotatedGenericProviderMethod()");
849     }
850   }
851 
852   public void testOverrideProviderMethod_subclassRawTypes_parameterType() {
853     class SubClassModule extends SuperClassModule {
854       @Override
855       Collection<String> annotatedGenericParameterProviderMethod(List foo) {
856         return super.annotatedGenericParameterProviderMethod(foo);
857       }
858     }
859     try {
860       Guice.createInjector(new SubClassModule());
861       fail();
862     } catch (CreationException e) {
863       assertContains(
864           e.getMessage(),
865           "Overriding @Provides methods is not allowed.",
866           "@Provides method: "
867               + SuperClassModule.class.getName()
868               + ".annotatedGenericParameterProviderMethod()",
869           "overridden by: "
870               + SubClassModule.class.getName()
871               + ".annotatedGenericParameterProviderMethod()");
872     }
873   }
874 
875   public void testOverrideProviderMethod_superclassRawTypes_returnType() {
876     class SubClassModule extends SuperClassModule {
877       // remove the rawtype from the override
878       @Override
879       List<String> rawProvider(List<String> f) {
880         return f;
881       }
882     }
883     try {
884       Guice.createInjector(new SubClassModule());
885       fail();
886     } catch (CreationException e) {
887       assertContains(
888           e.getMessage(),
889           "Overriding @Provides methods is not allowed.",
890           "@Provides method: " + SuperClassModule.class.getName() + ".rawProvider()",
891           "overridden by: " + SubClassModule.class.getName() + ".rawProvider()");
892     }
893   }
894 
895   abstract static class GenericSuperModule<T> extends AbstractModule {
896     @Provides
897     String provide(T thing) {
898       return thing.toString();
899     }
900   }
901 
902   // This is a tricky case where signatures don't match, but it is an override (facilitated via a
903   // bridge method)
904   public void testOverrideProviderMethod_erasureBasedOverrides() {
905     class SubClassModule extends GenericSuperModule<Integer> {
906       @Override
907       String provide(Integer thing) {
908         return thing.toString();
909       }
910 
911       @Override
912       protected void configure() {
913         bind(Integer.class).toInstance(3);
914       }
915     }
916     try {
917       Guice.createInjector(new SubClassModule());
918       fail();
919     } catch (CreationException e) {
920       assertContains(
921           e.getMessage(),
922           "Overriding @Provides methods is not allowed.",
923           "@Provides method: " + GenericSuperModule.class.getName() + ".provide()",
924           "overridden by: " + SubClassModule.class.getName() + ".provide()");
925     }
926   }
927 
928   static class RestrictedSuper extends AbstractModule {
929     @Provides
930     public String provideFoo() {
931       return "foo";
932     }
933 
934   }
935 
936   public static class ExposedSub extends RestrictedSuper {}
937 
938   public void testOverrideProviderMethod_increasedVisibility() {
939     // ensure we don't detect the synthetic provideFoo method in ExposedSub as an override (it is,
940     // but since it is synthetic it would be annoying to throw an error on it).
941     assertEquals("foo", Guice.createInjector(new ExposedSub()).getInstance(String.class));
942   }
943 
944   interface ProviderInterface<T> {
945     T getT();
946   }
947 
948   static class ModuleImpl extends AbstractModule implements ProviderInterface<String> {
949 
950     @Override
951     @Provides
952     public String getT() {
953       return "string";
954     }
955 
956     @Provides
957     public Object getObject() {
958       return new Object();
959     }
960     /* javac will synthesize a bridge method for getT with the types erased, equivalent to:
961      * @Provides public Object getT() { ... }
962      */
963   }
964 
965   public void testIgnoreSyntheticBridgeMethods() {
966     Guice.createInjector(new ModuleImpl());
967   }
968 
969   public void testScopedProviderMethodThrowsException() {
970     Injector injector =
971         Guice.createInjector(
972             new AbstractModule() {
973 
974               @Provides
975               @Singleton
976               int provideInt() {
977                 throw new RuntimeException("boom");
978               }
979             });
980     Provider<Integer> intProvider = injector.getProvider(Integer.class);
981     try {
982       intProvider.get();
983       fail();
984     } catch (ProvisionException pe) {
985       // by default assertContains asserts that the last item doesn't repeat... which is the main
986       // thing we are testing for
987       assertContains(pe.getMessage(), "java.lang.RuntimeException: boom", "provideInt");
988     }
989   }
990 
991   public void testNullability() throws Exception {
992     Module module =
993         new AbstractModule() {
994           @Override
995           protected void configure() {
996             bind(String.class).toProvider(Providers.<String>of(null));
997           }
998 
999           @SuppressWarnings("unused")
1000           @Provides
1001           Integer fail(String foo) {
1002             return 1;
1003           }
1004 
1005           @SuppressWarnings("unused")
1006           @Provides
1007           Long succeed(@Nullable String foo) {
1008             return 2L;
1009           }
1010         };
1011     Injector injector = Guice.createInjector(module);
1012     InjectionPoint fooPoint =
1013         InjectionPoint.forMethod(
1014             module.getClass().getDeclaredMethod("fail", String.class),
1015             TypeLiteral.get(module.getClass()));
1016     Dependency<?> fooDependency = Iterables.getOnlyElement(fooPoint.getDependencies());
1017 
1018     runNullableTest(injector, fooDependency, module);
1019 
1020     injector.getInstance(Long.class);
1021   }
1022 
1023   public void testModuleBindings() throws Exception {
1024     Module module =
1025         new AbstractModule() {
1026 
1027           @Provides
1028           Integer fail() {
1029             return 1;
1030           }
1031         };
1032     // sanity check that the injector works
1033     Injector injector = Guice.createInjector(module);
1034     assertEquals(1, injector.getInstance(Integer.class).intValue());
1035     ProviderInstanceBinding injectorBinding =
1036         (ProviderInstanceBinding) injector.getBinding(Integer.class);
1037     assertEquals(1, injectorBinding.getUserSuppliedProvider().get());
1038 
1039     ProviderInstanceBinding moduleBinding =
1040         (ProviderInstanceBinding) Iterables.getOnlyElement(Elements.getElements(module));
1041     try {
1042       moduleBinding.getUserSuppliedProvider().get();
1043       fail();
1044     } catch (IllegalStateException ise) {
1045       assertEquals(
1046           "This Provider cannot be used until the Injector has been created.", ise.getMessage());
1047     }
1048   }
1049 
1050   private void runNullableTest(Injector injector, Dependency<?> dependency, Module module) {
1051     switch (InternalFlags.getNullableProvidesOption()) {
1052       case ERROR:
1053         validateNullableFails(injector, module);
1054         break;
1055       case IGNORE:
1056         validateNullableIgnored(injector);
1057         break;
1058       case WARN:
1059         validateNullableWarns(injector, dependency);
1060         break;
1061     }
1062   }
1063 
1064   private void validateNullableFails(Injector injector, Module module) {
1065     try {
1066       injector.getInstance(Integer.class);
1067       fail();
1068     } catch (ProvisionException expected) {
1069       assertContains(
1070           expected.getMessage(),
1071           "1) null returned by binding at " + module.getClass().getName() + ".configure(",
1072           "but the 1st parameter of " + module.getClass().getName() + ".fail(",
1073           "is not @Nullable",
1074           "while locating java.lang.String",
1075           "for the 1st parameter of " + module.getClass().getName() + ".fail(",
1076           "while locating java.lang.Integer");
1077 
1078       assertEquals(1, expected.getErrorMessages().size());
1079     }
1080   }
1081 
1082   private void validateNullableIgnored(Injector injector) {
1083     injector.getInstance(Integer.class); // no exception
1084   }
1085 
1086   private void validateNullableWarns(Injector injector, Dependency<?> dependency) {
1087     final List<LogRecord> logRecords = Lists.newArrayList();
1088     final Handler fakeHandler =
1089         new Handler() {
1090           @Override
1091           public void publish(LogRecord logRecord) {
1092             logRecords.add(logRecord);
1093           }
1094 
1095           @Override
1096           public void flush() {}
1097 
1098           @Override
1099           public void close() throws SecurityException {}
1100         };
1101     Logger.getLogger(Guice.class.getName()).addHandler(fakeHandler);
1102     try {
1103       injector.getInstance(Integer.class); // no exception, but assert it does log.
1104       LogRecord record = Iterables.getOnlyElement(logRecords);
1105       assertEquals(
1106           "Guice injected null into {0} (a {1}), please mark it @Nullable."
1107               + " Use -Dguice_check_nullable_provides_params=ERROR to turn this into an"
1108               + " error.",
1109           record.getMessage());
1110       assertEquals(Errors.convert(dependency.getKey()), record.getParameters()[1]);
1111     } finally {
1112       Logger.getLogger(Guice.class.getName()).removeHandler(fakeHandler);
1113     }
1114   }
1115 
1116   @Retention(RetentionPolicy.RUNTIME)
1117   @interface Nullable {}
1118 }
1119