Home | History | Annotate | Download | only in util
      1 /**
      2  * Copyright (C) 2008 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.inject.util;
     18 
     19 import static com.google.inject.Asserts.asModuleChain;
     20 import static com.google.inject.Asserts.assertContains;
     21 import static com.google.inject.Guice.createInjector;
     22 import static com.google.inject.name.Names.named;
     23 import static java.lang.annotation.ElementType.METHOD;
     24 import static java.lang.annotation.ElementType.TYPE;
     25 import static java.lang.annotation.RetentionPolicy.RUNTIME;
     26 
     27 import com.google.common.base.Objects;
     28 import com.google.common.collect.ImmutableSet;
     29 import com.google.inject.AbstractModule;
     30 import com.google.inject.Binder;
     31 import com.google.inject.Binding;
     32 import com.google.inject.CreationException;
     33 import com.google.inject.Exposed;
     34 import com.google.inject.Guice;
     35 import com.google.inject.Injector;
     36 import com.google.inject.Key;
     37 import com.google.inject.Module;
     38 import com.google.inject.PrivateModule;
     39 import com.google.inject.Provider;
     40 import com.google.inject.Provides;
     41 import com.google.inject.Scope;
     42 import com.google.inject.ScopeAnnotation;
     43 import com.google.inject.Stage;
     44 import com.google.inject.name.Named;
     45 import com.google.inject.name.Names;
     46 import com.google.inject.spi.InjectionPoint;
     47 import com.google.inject.spi.ModuleAnnotatedMethodScanner;
     48 
     49 import junit.framework.TestCase;
     50 
     51 import java.lang.annotation.Annotation;
     52 import java.lang.annotation.Documented;
     53 import java.lang.annotation.Retention;
     54 import java.lang.annotation.Target;
     55 import java.util.Date;
     56 import java.util.Set;
     57 import java.util.concurrent.atomic.AtomicReference;
     58 
     59 /**
     60  * @author sberlin (at) gmail.com (Sam Berlin)
     61  */
     62 public class OverrideModuleTest extends TestCase {
     63 
     64   private static final Key<String> key2 = Key.get(String.class, named("2"));
     65   private static final Key<String> key3 = Key.get(String.class, named("3"));
     66 
     67   private static final Module EMPTY_MODULE = new Module() {
     68     public void configure(Binder binder) {}
     69   };
     70 
     71   public void testOverride() {
     72     Injector injector = createInjector(Modules.override(newModule("A")).with(newModule("B")));
     73     assertEquals("B", injector.getInstance(String.class));
     74   }
     75 
     76   public void testOverrideMultiple() {
     77     Module module = Modules.override(newModule("A"), newModule(1), newModule(0.5f))
     78         .with(newModule("B"), newModule(2), newModule(1.5d));
     79     Injector injector = createInjector(module);
     80     assertEquals("B", injector.getInstance(String.class));
     81     assertEquals(2, injector.getInstance(Integer.class).intValue());
     82     assertEquals(0.5f, injector.getInstance(Float.class));
     83     assertEquals(1.5d, injector.getInstance(Double.class));
     84   }
     85 
     86   public void testOverrideUnmatchedTolerated() {
     87     Injector injector = createInjector(Modules.override(EMPTY_MODULE).with(newModule("B")));
     88     assertEquals("B", injector.getInstance(String.class));
     89   }
     90 
     91   public void testOverrideConstant() {
     92     Module original = new AbstractModule() {
     93       @Override protected void configure() {
     94         bindConstant().annotatedWith(named("Test")).to("A");
     95       }
     96     };
     97 
     98     Module replacements = new AbstractModule() {
     99       @Override protected void configure() {
    100         bindConstant().annotatedWith(named("Test")).to("B");
    101       }
    102     };
    103 
    104     Injector injector = createInjector(Modules.override(original).with(replacements));
    105     assertEquals("B", injector.getInstance(Key.get(String.class, named("Test"))));
    106   }
    107 
    108   public void testGetProviderInModule() {
    109     Module original = new AbstractModule() {
    110       @Override protected void configure() {
    111         bind(String.class).toInstance("A");
    112         bind(key2).toProvider(getProvider(String.class));
    113       }
    114     };
    115 
    116     Injector injector = createInjector(Modules.override(original).with(EMPTY_MODULE));
    117     assertEquals("A", injector.getInstance(String.class));
    118     assertEquals("A", injector.getInstance(key2));
    119   }
    120 
    121   public void testOverrideWhatGetProviderProvided() {
    122     Module original = new AbstractModule() {
    123       @Override protected void configure() {
    124         bind(String.class).toInstance("A");
    125         bind(key2).toProvider(getProvider(String.class));
    126       }
    127     };
    128 
    129     Module replacements = newModule("B");
    130 
    131     Injector injector = createInjector(Modules.override(original).with(replacements));
    132     assertEquals("B", injector.getInstance(String.class));
    133     assertEquals("B", injector.getInstance(key2));
    134   }
    135 
    136   public void testOverrideUsingOriginalsGetProvider() {
    137     Module original = new AbstractModule() {
    138       @Override protected void configure() {
    139         bind(String.class).toInstance("A");
    140         bind(key2).toInstance("B");
    141       }
    142     };
    143 
    144     Module replacements = new AbstractModule() {
    145       @Override protected void configure() {
    146         bind(String.class).toProvider(getProvider(key2));
    147       }
    148     };
    149 
    150     Injector injector = createInjector(Modules.override(original).with(replacements));
    151     assertEquals("B", injector.getInstance(String.class));
    152     assertEquals("B", injector.getInstance(key2));
    153   }
    154 
    155   public void testOverrideOfOverride() {
    156     Module original = new AbstractModule() {
    157       @Override protected void configure() {
    158         bind(String.class).toInstance("A1");
    159         bind(key2).toInstance("A2");
    160         bind(key3).toInstance("A3");
    161       }
    162     };
    163 
    164     Module replacements1 = new AbstractModule() {
    165       @Override protected void configure() {
    166         bind(String.class).toInstance("B1");
    167         bind(key2).toInstance("B2");
    168       }
    169     };
    170 
    171     Module overrides = Modules.override(original).with(replacements1);
    172 
    173     Module replacements2 = new AbstractModule() {
    174       @Override protected void configure() {
    175         bind(String.class).toInstance("C1");
    176         bind(key3).toInstance("C3");
    177       }
    178     };
    179 
    180     Injector injector = createInjector(Modules.override(overrides).with(replacements2));
    181     assertEquals("C1", injector.getInstance(String.class));
    182     assertEquals("B2", injector.getInstance(key2));
    183     assertEquals("C3", injector.getInstance(key3));
    184   }
    185 
    186   static class OuterReplacementsModule extends AbstractModule {
    187     @Override protected void configure() {
    188       install(new InnerReplacementsModule());
    189     }
    190   }
    191   static class InnerReplacementsModule extends AbstractModule {
    192     @Override protected void configure() {
    193       bind(String.class).toInstance("B");
    194       bind(String.class).toInstance("C");
    195     }
    196   }
    197   public void testOverridesTwiceFails() {
    198     Module original = newModule("A");
    199     Module replacements = new OuterReplacementsModule();
    200     Module module = Modules.override(original).with(replacements);
    201     try {
    202       createInjector(module);
    203       fail();
    204     } catch (CreationException expected) {
    205       assertContains(expected.getMessage(),
    206           "A binding to java.lang.String was already configured at "
    207               + InnerReplacementsModule.class.getName(),
    208           asModuleChain(Modules.OverrideModule.class,
    209               OuterReplacementsModule.class, InnerReplacementsModule.class),
    210           "at " + InnerReplacementsModule.class.getName(),
    211           asModuleChain(Modules.OverrideModule.class,
    212               OuterReplacementsModule.class, InnerReplacementsModule.class));
    213     }
    214   }
    215 
    216   public void testOverridesDoesntFixTwiceBoundInOriginal() {
    217     Module original = new AbstractModule() {
    218       @Override protected void configure() {
    219         bind(String.class).toInstance("A");
    220         bind(String.class).toInstance("B");
    221       }
    222     };
    223 
    224     Module replacements = new AbstractModule() {
    225       @Override protected void configure() {
    226         bind(String.class).toInstance("C");
    227       }
    228     };
    229 
    230     Module module = Modules.override(original).with(replacements);
    231     try {
    232       createInjector(module);
    233       fail();
    234     } catch (CreationException expected) {
    235       // The replacement comes first because we replace A with C,
    236       // then we encounter B and freak out.
    237       assertContains(expected.getMessage(),
    238           "1) A binding to java.lang.String was already configured at "
    239               + replacements.getClass().getName(),
    240           asModuleChain(Modules.OverrideModule.class, replacements.getClass()),
    241           "at " + original.getClass().getName(),
    242           asModuleChain(Modules.OverrideModule.class, original.getClass()));
    243     }
    244   }
    245 
    246   public void testStandardScopeAnnotation() {
    247     final SingleUseScope scope = new SingleUseScope();
    248 
    249     Module module = new AbstractModule() {
    250       @Override protected void configure() {
    251         bindScope(TestScopeAnnotation.class, scope);
    252         bind(String.class).in(TestScopeAnnotation.class);
    253       }
    254     };
    255     assertFalse(scope.used);
    256 
    257     Guice.createInjector(module);
    258     assertTrue(scope.used);
    259   }
    260 
    261   public void testOverrideUntargettedBinding() {
    262     Module original = new AbstractModule() {
    263       @Override protected void configure() {
    264         bind(Date.class);
    265       }
    266     };
    267 
    268     Module replacements = new AbstractModule() {
    269       @Override protected void configure() {
    270         bind(Date.class).toInstance(new Date(0));
    271       }
    272     };
    273 
    274     Injector injector = createInjector(Modules.override(original).with(replacements));
    275     assertEquals(0, injector.getInstance(Date.class).getTime());
    276   }
    277 
    278   public void testOverrideScopeAnnotation() {
    279     final Scope scope = new Scope() {
    280       public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
    281         throw new AssertionError("Should not be called");
    282       }
    283     };
    284 
    285     final SingleUseScope replacementScope = new SingleUseScope();
    286 
    287     Module original = new AbstractModule() {
    288       @Override protected void configure() {
    289         bindScope(TestScopeAnnotation.class, scope);
    290         bind(Date.class).in(TestScopeAnnotation.class);
    291       }
    292     };
    293 
    294     Module replacements = new AbstractModule() {
    295       @Override protected void configure() {
    296         bindScope(TestScopeAnnotation.class, replacementScope);
    297       }
    298     };
    299 
    300     Injector injector = createInjector(Modules.override(original).with(replacements));
    301     injector.getInstance(Date.class);
    302     assertTrue(replacementScope.used);
    303   }
    304 
    305   public void testFailsIfOverridenScopeInstanceHasBeenUsed() {
    306     final Scope scope = new Scope() {
    307       public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
    308         return unscoped;
    309       }
    310 
    311       @Override public String toString() {
    312         return "ORIGINAL SCOPE";
    313       }
    314     };
    315 
    316     final Module original = new AbstractModule() {
    317       @Override protected void configure() {
    318         bindScope(TestScopeAnnotation.class, scope);
    319         bind(Date.class).in(scope);
    320         bind(String.class).in(scope);
    321       }
    322     };
    323     Module originalWrapper = new AbstractModule() {
    324       @Override protected void configure() {
    325         install(original);
    326       }
    327     };
    328 
    329     Module replacements = new AbstractModule() {
    330       @Override protected void configure() {
    331         bindScope(TestScopeAnnotation.class, new SingleUseScope());
    332       }
    333     };
    334 
    335     try {
    336       createInjector(Modules.override(originalWrapper).with(replacements));
    337       fail("Exception expected");
    338     } catch (CreationException e) {
    339       assertContains(e.getMessage(),
    340           "1) The scope for @TestScopeAnnotation is bound directly and cannot be overridden.",
    341           "original binding at " + original.getClass().getName() + ".configure(",
    342           asModuleChain(originalWrapper.getClass(), original.getClass()),
    343           "bound directly at " + original.getClass().getName() + ".configure(",
    344           asModuleChain(originalWrapper.getClass(), original.getClass()),
    345           "bound directly at " + original.getClass().getName() + ".configure(",
    346           asModuleChain(originalWrapper.getClass(), original.getClass()),
    347           "at ", replacements.getClass().getName() + ".configure(",
    348           asModuleChain(Modules.OverrideModule.class, replacements.getClass()));
    349     }
    350   }
    351 
    352   public void testOverrideIsLazy() {
    353     final AtomicReference<String> value = new AtomicReference<String>("A");
    354     Module overridden = Modules.override(new AbstractModule() {
    355       @Override protected void configure() {
    356         bind(String.class).annotatedWith(named("original")).toInstance(value.get());
    357       }
    358     }).with(new AbstractModule() {
    359       @Override protected void configure() {
    360         bind(String.class).annotatedWith(named("override")).toInstance(value.get());
    361       }
    362     });
    363 
    364     // the value.get() call should be deferred until Guice.createInjector
    365     value.set("B");
    366     Injector injector = Guice.createInjector(overridden);
    367     assertEquals("B", injector.getInstance(Key.get(String.class, named("original"))));
    368     assertEquals("B", injector.getInstance(Key.get(String.class, named("override"))));
    369   }
    370 
    371   public void testOverridePrivateModuleOverPrivateModule() {
    372     Module exposes5and6 = new AbstractModule() {
    373       @Override protected void configure() {
    374         install(new PrivateModule() {
    375           @Override protected void configure() {
    376             bind(Integer.class).toInstance(5);
    377             expose(Integer.class);
    378 
    379             bind(Character.class).toInstance('E');
    380           }
    381         });
    382 
    383         install(new PrivateModule() {
    384           @Override protected void configure() {
    385             bind(Long.class).toInstance(6L);
    386             expose(Long.class);
    387 
    388             bind(Character.class).toInstance('F');
    389           }
    390         });
    391       }
    392     };
    393 
    394     AbstractModule exposes15 = new AbstractModule() {
    395       @Override protected void configure() {
    396         install(new PrivateModule() {
    397           @Override protected void configure() {
    398             bind(Integer.class).toInstance(15);
    399             expose(Integer.class);
    400 
    401             bind(Character.class).toInstance('G');
    402           }
    403         });
    404 
    405         install(new PrivateModule() {
    406           @Override protected void configure() {
    407             bind(Character.class).toInstance('H');
    408           }
    409         });
    410       }
    411     };
    412 
    413     // override forwards
    414     Injector injector = Guice.createInjector(Modules.override(exposes5and6).with(exposes15));
    415     assertEquals(15, injector.getInstance(Integer.class).intValue());
    416     assertEquals(6L, injector.getInstance(Long.class).longValue());
    417 
    418     // and in reverse order
    419     Injector reverse = Guice.createInjector(Modules.override(exposes15).with(exposes5and6));
    420     assertEquals(5, reverse.getInstance(Integer.class).intValue());
    421     assertEquals(6L, reverse.getInstance(Long.class).longValue());
    422   }
    423 
    424   public void testOverrideModuleAndPrivateModule() {
    425     Module exposes5 = new PrivateModule() {
    426       @Override protected void configure() {
    427         bind(Integer.class).toInstance(5);
    428         expose(Integer.class);
    429       }
    430     };
    431 
    432     Module binds15 = new AbstractModule() {
    433       @Override protected void configure() {
    434         bind(Integer.class).toInstance(15);
    435       }
    436     };
    437 
    438     Injector injector = Guice.createInjector(Modules.override(exposes5).with(binds15));
    439     assertEquals(15, injector.getInstance(Integer.class).intValue());
    440 
    441     Injector reverse = Guice.createInjector(Modules.override(binds15).with(exposes5));
    442     assertEquals(5, reverse.getInstance(Integer.class).intValue());
    443   }
    444 
    445   public void testOverrideDeepExpose() {
    446     final AtomicReference<Provider<Character>> charAProvider
    447         = new AtomicReference<Provider<Character>>();
    448 
    449     Module exposes5 = new PrivateModule() {
    450       @Override protected void configure() {
    451         install(new PrivateModule() {
    452           @Override protected void configure() {
    453             bind(Integer.class).toInstance(5);
    454             expose(Integer.class);
    455             charAProvider.set(getProvider(Character.class));
    456             bind(Character.class).toInstance('A');
    457           }
    458         });
    459         expose(Integer.class);
    460       }
    461     };
    462 
    463     Injector injector = Guice.createInjector(Modules.override(exposes5).with(EMPTY_MODULE));
    464     assertEquals(5, injector.getInstance(Integer.class).intValue());
    465     assertEquals('A', charAProvider.getAndSet(null).get().charValue());
    466 
    467     injector = Guice.createInjector(Modules.override(EMPTY_MODULE).with(exposes5));
    468     assertEquals(5, injector.getInstance(Integer.class).intValue());
    469     assertEquals('A', charAProvider.getAndSet(null).get().charValue());
    470 
    471     final AtomicReference<Provider<Character>> charBProvider
    472         = new AtomicReference<Provider<Character>>();
    473 
    474     Module binds15 = new AbstractModule() {
    475       @Override protected void configure() {
    476         bind(Integer.class).toInstance(15);
    477 
    478         install(new PrivateModule() {
    479           @Override protected void configure() {
    480             charBProvider.set(getProvider(Character.class));
    481             bind(Character.class).toInstance('B');
    482           }
    483         });
    484       }
    485     };
    486 
    487     injector = Guice.createInjector(Modules.override(binds15).with(exposes5));
    488     assertEquals(5, injector.getInstance(Integer.class).intValue());
    489     assertEquals('A', charAProvider.getAndSet(null).get().charValue());
    490     assertEquals('B', charBProvider.getAndSet(null).get().charValue());
    491 
    492     injector = Guice.createInjector(Modules.override(exposes5).with(binds15));
    493     assertEquals(15, injector.getInstance(Integer.class).intValue());
    494     assertEquals('A', charAProvider.getAndSet(null).get().charValue());
    495     assertEquals('B', charBProvider.getAndSet(null).get().charValue());
    496   }
    497 
    498   @Retention(RUNTIME)
    499   @Target(TYPE)
    500   @ScopeAnnotation
    501   private static @interface TestScopeAnnotation {}
    502 
    503   private static class SingleUseScope implements Scope {
    504     boolean used = false;
    505     public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
    506       assertFalse(used);
    507       used = true;
    508       return unscoped;
    509     }
    510   }
    511 
    512   static class NewModule<T> extends AbstractModule {
    513     private final T bound;
    514     NewModule(T bound) {
    515       this.bound = bound;
    516     }
    517     @Override protected void configure() {
    518       @SuppressWarnings("unchecked")
    519       Class<T> type = (Class<T>)bound.getClass();
    520       bind(type).toInstance(bound);
    521     }
    522   }
    523 
    524   private static <T> Module newModule(final T bound) {
    525     return new NewModule<T>(bound);
    526   }
    527 
    528   private static final String RESULT = "RESULT";
    529   private static final String PRIVATE_INPUT = "PRIVATE_INPUT";
    530   private static final String OVERRIDDEN_INPUT = "FOO";
    531   private static final String OVERRIDDEN_RESULT = "Size: 3";
    532   private static final Key<String> RESULT_KEY = Key.get(String.class, named(RESULT));
    533   private static final Key<String> INPUT_KEY = Key.get(String.class, named(PRIVATE_INPUT));
    534 
    535   public void testExposedBindingOverride() throws Exception {
    536     Injector inj = Guice.createInjector(
    537         Modules.override(new ExampleModule()).with(
    538             new AbstractModule() {
    539               @Override protected void configure() {
    540                 bind(RESULT_KEY).toInstance(OVERRIDDEN_RESULT);
    541               }
    542             }));
    543     assertEquals(inj.getInstance(RESULT_KEY), OVERRIDDEN_RESULT);
    544   }
    545 
    546   public void testPrivateBindingOverride() throws Exception {
    547     Injector inj = Guice.createInjector(
    548         Modules.override(new ExampleModule()).with(
    549             new AbstractModule() {
    550               @Override protected void configure() {
    551                 bind(INPUT_KEY).toInstance(OVERRIDDEN_INPUT);
    552               }
    553             }));
    554     assertEquals(inj.getInstance(RESULT_KEY), OVERRIDDEN_RESULT);
    555   }
    556 
    557   public static class ExampleModule extends PrivateModule {
    558     @Provides @Exposed @Named(RESULT)
    559     public String provideResult(@Named(PRIVATE_INPUT) String input) {
    560       return "Size: " + input.length();
    561     }
    562 
    563     @Provides @Named(PRIVATE_INPUT)
    564     public String provideInput() {
    565       return "Hello World";
    566     }
    567 
    568     @Override protected void configure() {
    569     }
    570   }
    571 
    572   public void testEqualsNotCalledByDefaultOnInstance() {
    573     final HashEqualsTester a = new HashEqualsTester();
    574     a.throwOnEquals = true;
    575     Guice.createInjector(Modules.override(new AbstractModule() {
    576       @Override
    577       protected void configure() {
    578        bind(String.class);
    579        bind(HashEqualsTester.class).toInstance(a);
    580       }
    581     }).with());
    582   }
    583 
    584   public void testEqualsNotCalledByDefaultOnProvider() {
    585     final HashEqualsTester a = new HashEqualsTester();
    586     a.throwOnEquals = true;
    587     Guice.createInjector(Modules.override(new AbstractModule() {
    588       @Override
    589       protected void configure() {
    590        bind(String.class);
    591        bind(Object.class).toProvider(a);
    592       }
    593     }).with());
    594   }
    595 
    596   public void testHashcodeNeverCalledOnInstance() {
    597     final HashEqualsTester a = new HashEqualsTester();
    598     a.throwOnHashcode = true;
    599     a.equality = "test";
    600 
    601     final HashEqualsTester b = new HashEqualsTester();
    602     b.throwOnHashcode = true;
    603     b.equality = "test";
    604     Guice.createInjector(Modules.override(new AbstractModule() {
    605       @Override
    606       protected void configure() {
    607        bind(String.class);
    608        bind(HashEqualsTester.class).toInstance(a);
    609        bind(HashEqualsTester.class).toInstance(b);
    610       }
    611     }).with());
    612   }
    613 
    614   public void testHashcodeNeverCalledOnProviderInstance() {
    615     final HashEqualsTester a = new HashEqualsTester();
    616     a.throwOnHashcode = true;
    617     a.equality = "test";
    618 
    619     final HashEqualsTester b = new HashEqualsTester();
    620     b.throwOnHashcode = true;
    621     b.equality = "test";
    622     Guice.createInjector(Modules.override(new AbstractModule() {
    623       @Override
    624       protected void configure() {
    625        bind(String.class);
    626        bind(Object.class).toProvider(a);
    627        bind(Object.class).toProvider(b);
    628       }
    629     }).with());
    630   }
    631 
    632   private static class HashEqualsTester implements Provider<Object> {
    633     private String equality;
    634     private boolean throwOnEquals;
    635     private boolean throwOnHashcode;
    636 
    637     @Override
    638     public boolean equals(Object obj) {
    639       if (throwOnEquals) {
    640         throw new RuntimeException();
    641       } else if (obj instanceof HashEqualsTester) {
    642         HashEqualsTester o = (HashEqualsTester)obj;
    643         if(o.throwOnEquals) {
    644           throw new RuntimeException();
    645         }
    646         if(equality == null && o.equality == null) {
    647           return this == o;
    648         } else {
    649           return Objects.equal(equality, o.equality);
    650         }
    651       } else {
    652         return false;
    653       }
    654     }
    655 
    656     @Override
    657     public int hashCode() {
    658       if(throwOnHashcode) {
    659         throw new RuntimeException();
    660       } else {
    661         return super.hashCode();
    662       }
    663     }
    664 
    665     public Object get() {
    666       return new Object();
    667     }
    668   }
    669 
    670   public void testCorrectStage() {
    671     final Stage stage = Stage.PRODUCTION;
    672     Module module = Modules.override(new AbstractModule() {
    673       @Override
    674       protected void configure() {
    675         if (currentStage() != Stage.PRODUCTION) {
    676           addError("Wronge stage in overridden module:" + currentStage());
    677         }
    678       }
    679     }).with(new AbstractModule() {
    680       @Override
    681       protected void configure() {
    682         if (currentStage() != Stage.PRODUCTION) {
    683           addError("Wronge stage in overriding module:" + currentStage());
    684         }
    685       }
    686     });
    687     Guice.createInjector(stage, module);
    688   }
    689 
    690   public void testOverridesApplyOriginalScanners() {
    691     Injector injector =
    692         Guice.createInjector(Modules.override(NamedMunger.module()).with(new AbstractModule() {
    693       @Override protected void configure() {}
    694       @TestProvides @Named("test") String provideString() { return "foo"; }
    695     }));
    696 
    697     assertNull(injector.getExistingBinding(Key.get(String.class, named("test"))));
    698     Binding<String> binding = injector.getBinding(Key.get(String.class, named("test-munged")));
    699     assertEquals("foo", binding.getProvider().get());
    700   }
    701 
    702   @Documented @Target(METHOD) @Retention(RUNTIME)
    703   private @interface TestProvides {}
    704 
    705   private static class NamedMunger extends ModuleAnnotatedMethodScanner {
    706     static Module module() {
    707       return new AbstractModule() {
    708         @Override protected void configure() {
    709           binder().scanModulesForAnnotatedMethods(new NamedMunger());
    710         }
    711       };
    712     }
    713 
    714     @Override
    715     public String toString() {
    716       return "NamedMunger";
    717     }
    718 
    719     @Override
    720     public Set<? extends Class<? extends Annotation>> annotationClasses() {
    721       return ImmutableSet.of(TestProvides.class);
    722     }
    723 
    724     @Override
    725     public <T> Key<T> prepareMethod(Binder binder, Annotation annotation, Key<T> key,
    726         InjectionPoint injectionPoint) {
    727       return Key.get(key.getTypeLiteral(),
    728           Names.named(((Named) key.getAnnotation()).value() + "-munged"));
    729     }
    730   }
    731 }
    732