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