Home | History | Annotate | Download | only in spi
      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 (at) google.com (Bob Lee)
     68  */
     69 public class ProviderMethodsTest extends TestCase implements Module {
     70 
     71   @SuppressWarnings("unchecked")
     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 
     91   public void configure(Binder binder) {}
     92 
     93   interface Bob {
     94     String getName();
     95     Dagny getDaughter();
     96   }
     97 
     98   interface Dagny {
     99     int getAge();
    100   }
    101 
    102   @Provides
    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