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