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