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.spi; 18 19 import static com.google.common.collect.Iterables.getOnlyElement; 20 import static com.google.inject.Asserts.assertContains; 21 import static com.google.inject.Asserts.getDeclaringSourcePart; 22 import static com.google.inject.Asserts.isIncludeStackTraceComplete; 23 import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 25 import com.google.common.collect.ImmutableMap; 26 import com.google.common.collect.ImmutableSet; 27 import com.google.inject.AbstractModule; 28 import com.google.inject.Binding; 29 import com.google.inject.BindingAnnotation; 30 import com.google.inject.Inject; 31 import com.google.inject.Key; 32 import com.google.inject.MembersInjector; 33 import com.google.inject.Module; 34 import com.google.inject.PrivateBinder; 35 import com.google.inject.Provider; 36 import com.google.inject.Scope; 37 import com.google.inject.Scopes; 38 import com.google.inject.Singleton; 39 import com.google.inject.Stage; 40 import com.google.inject.TypeLiteral; 41 import com.google.inject.binder.AnnotatedBindingBuilder; 42 import com.google.inject.binder.AnnotatedConstantBindingBuilder; 43 import com.google.inject.binder.ConstantBindingBuilder; 44 import com.google.inject.binder.ScopedBindingBuilder; 45 import com.google.inject.matcher.Matcher; 46 import com.google.inject.matcher.Matchers; 47 import com.google.inject.name.Named; 48 import com.google.inject.name.Names; 49 import com.google.inject.util.Providers; 50 import java.lang.annotation.Annotation; 51 import java.lang.annotation.ElementType; 52 import java.lang.annotation.Retention; 53 import java.lang.annotation.Target; 54 import java.lang.reflect.Constructor; 55 import java.lang.reflect.Field; 56 import java.util.ArrayList; 57 import java.util.Arrays; 58 import java.util.Collection; 59 import java.util.HashMap; 60 import java.util.Iterator; 61 import java.util.List; 62 import java.util.Map; 63 import java.util.Set; 64 import java.util.TreeSet; 65 import java.util.concurrent.atomic.AtomicInteger; 66 import java.util.concurrent.atomic.AtomicReference; 67 import junit.framework.TestCase; 68 69 /** @author jessewilson (at) google.com (Jesse Wilson) */ 70 public class ElementsTest extends TestCase { 71 72 // Binder fidelity tests 73 74 public void testAddMessageErrorCommand() { 75 checkModule( 76 new AbstractModule() { 77 @Override 78 protected void configure() { 79 addError("Message %s %d %s", "A", 5, "C"); 80 } 81 }, 82 new FailingElementVisitor() { 83 @Override 84 public Void visit(Message command) { 85 assertEquals("Message A 5 C", command.getMessage()); 86 assertNull(command.getCause()); 87 assertContains( 88 command.getSources().toString(), 89 ElementsTest.class.getName(), 90 getDeclaringSourcePart(ElementsTest.class)); 91 assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class)); 92 return null; 93 } 94 }); 95 } 96 97 public void testAddThrowableErrorCommand() { 98 checkModule( 99 new AbstractModule() { 100 @Override 101 protected void configure() { 102 addError(new Exception("A")); 103 } 104 }, 105 new FailingElementVisitor() { 106 @Override 107 public Void visit(Message command) { 108 assertEquals("A", command.getCause().getMessage()); 109 assertEquals("An exception was caught and reported. Message: A", command.getMessage()); 110 assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class)); 111 return null; 112 } 113 }); 114 } 115 116 public void testErrorsAddedWhenExceptionsAreThrown() { 117 checkModule( 118 new AbstractModule() { 119 @Override 120 protected void configure() { 121 install( 122 new AbstractModule() { 123 @Override 124 protected void configure() { 125 throw new RuntimeException( 126 "Throwing RuntimeException in AbstractModule.configure()."); 127 } 128 }); 129 130 addError("Code after the exception still gets executed"); 131 } 132 }, 133 new FailingElementVisitor() { 134 @Override 135 public Void visit(Message command) { 136 assertEquals( 137 "Throwing RuntimeException in AbstractModule.configure().", 138 command.getCause().getMessage()); 139 return null; 140 } 141 }, 142 new FailingElementVisitor() { 143 @Override 144 public Void visit(Message command) { 145 assertEquals("Code after the exception still gets executed", command.getMessage()); 146 return null; 147 } 148 }); 149 } 150 151 private <T> T getInstance(Binding<T> binding) { 152 return binding.acceptTargetVisitor(Elements.<T>getInstanceVisitor()); 153 } 154 155 public void testBindConstantAnnotations() { 156 checkModule( 157 new AbstractModule() { 158 @Override 159 protected void configure() { 160 bindConstant().annotatedWith(SampleAnnotation.class).to("A"); 161 bindConstant().annotatedWith(Names.named("Bee")).to("B"); 162 } 163 }, 164 new FailingElementVisitor() { 165 @Override 166 public <T> Void visit(Binding<T> command) { 167 assertTrue(command instanceof InstanceBinding); 168 assertEquals(Key.get(String.class, SampleAnnotation.class), command.getKey()); 169 assertEquals("A", getInstance(command)); 170 return null; 171 } 172 }, 173 new FailingElementVisitor() { 174 @Override 175 public <T> Void visit(Binding<T> command) { 176 assertTrue(command instanceof InstanceBinding); 177 assertEquals(Key.get(String.class, Names.named("Bee")), command.getKey()); 178 assertEquals("B", getInstance(command)); 179 return null; 180 } 181 }); 182 } 183 184 public void testBindConstantTypes() { 185 checkModule( 186 new AbstractModule() { 187 @Override 188 protected void configure() { 189 bindConstant().annotatedWith(Names.named("String")).to("A"); 190 bindConstant().annotatedWith(Names.named("int")).to(2); 191 bindConstant().annotatedWith(Names.named("long")).to(3L); 192 bindConstant().annotatedWith(Names.named("boolean")).to(false); 193 bindConstant().annotatedWith(Names.named("double")).to(5.0d); 194 bindConstant().annotatedWith(Names.named("float")).to(6.0f); 195 bindConstant().annotatedWith(Names.named("short")).to((short) 7); 196 bindConstant().annotatedWith(Names.named("char")).to('h'); 197 bindConstant().annotatedWith(Names.named("byte")).to((byte) 8); 198 bindConstant().annotatedWith(Names.named("Class")).to(Iterator.class); 199 bindConstant().annotatedWith(Names.named("Enum")).to(CoinSide.TAILS); 200 } 201 }, 202 new FailingElementVisitor() { 203 @Override 204 public <T> Void visit(Binding<T> command) { 205 assertTrue(command instanceof InstanceBinding); 206 assertEquals(Key.get(String.class, Names.named("String")), command.getKey()); 207 assertEquals("A", getInstance(command)); 208 return null; 209 } 210 }, 211 new FailingElementVisitor() { 212 @Override 213 public <T> Void visit(Binding<T> command) { 214 assertTrue(command instanceof InstanceBinding); 215 assertEquals(Key.get(Integer.class, Names.named("int")), command.getKey()); 216 assertEquals(2, getInstance(command)); 217 return null; 218 } 219 }, 220 new FailingElementVisitor() { 221 @Override 222 public <T> Void visit(Binding<T> command) { 223 assertTrue(command instanceof InstanceBinding); 224 assertEquals(Key.get(Long.class, Names.named("long")), command.getKey()); 225 assertEquals(3L, getInstance(command)); 226 return null; 227 } 228 }, 229 new FailingElementVisitor() { 230 @Override 231 public <T> Void visit(Binding<T> command) { 232 assertTrue(command instanceof InstanceBinding); 233 assertEquals(Key.get(Boolean.class, Names.named("boolean")), command.getKey()); 234 assertEquals(false, getInstance(command)); 235 return null; 236 } 237 }, 238 new FailingElementVisitor() { 239 @Override 240 public <T> Void visit(Binding<T> command) { 241 assertTrue(command instanceof InstanceBinding); 242 assertEquals(Key.get(Double.class, Names.named("double")), command.getKey()); 243 assertEquals(5.0d, getInstance(command)); 244 return null; 245 } 246 }, 247 new FailingElementVisitor() { 248 @Override 249 public <T> Void visit(Binding<T> command) { 250 assertTrue(command instanceof InstanceBinding); 251 assertEquals(Key.get(Float.class, Names.named("float")), command.getKey()); 252 assertEquals(6.0f, getInstance(command)); 253 return null; 254 } 255 }, 256 new FailingElementVisitor() { 257 @Override 258 public <T> Void visit(Binding<T> command) { 259 assertTrue(command instanceof InstanceBinding); 260 assertEquals(Key.get(Short.class, Names.named("short")), command.getKey()); 261 assertEquals((short) 7, getInstance(command)); 262 return null; 263 } 264 }, 265 new FailingElementVisitor() { 266 @Override 267 public <T> Void visit(Binding<T> command) { 268 assertTrue(command instanceof InstanceBinding); 269 assertEquals(Key.get(Character.class, Names.named("char")), command.getKey()); 270 assertEquals('h', getInstance(command)); 271 return null; 272 } 273 }, 274 new FailingElementVisitor() { 275 @Override 276 public <T> Void visit(Binding<T> command) { 277 assertTrue(command instanceof InstanceBinding); 278 assertEquals(Key.get(Byte.class, Names.named("byte")), command.getKey()); 279 assertEquals((byte) 8, getInstance(command)); 280 return null; 281 } 282 }, 283 new FailingElementVisitor() { 284 @Override 285 public <T> Void visit(Binding<T> command) { 286 assertTrue(command instanceof InstanceBinding); 287 assertEquals(Key.get(Class.class, Names.named("Class")), command.getKey()); 288 assertEquals(Iterator.class, getInstance(command)); 289 return null; 290 } 291 }, 292 new FailingElementVisitor() { 293 @Override 294 public <T> Void visit(Binding<T> command) { 295 assertTrue(command instanceof InstanceBinding); 296 assertEquals(Key.get(CoinSide.class, Names.named("Enum")), command.getKey()); 297 assertEquals(CoinSide.TAILS, getInstance(command)); 298 return null; 299 } 300 }); 301 } 302 303 public void testBindKeysNoAnnotations() { 304 FailingElementVisitor keyChecker = 305 new FailingElementVisitor() { 306 @Override 307 public <T> Void visit(Binding<T> command) { 308 assertEquals(Key.get(String.class), command.getKey()); 309 return null; 310 } 311 }; 312 313 checkModule( 314 new AbstractModule() { 315 @Override 316 protected void configure() { 317 bind(String.class).toInstance("A"); 318 bind(new TypeLiteral<String>() {}).toInstance("B"); 319 bind(Key.get(String.class)).toInstance("C"); 320 } 321 }, 322 keyChecker, 323 keyChecker, 324 keyChecker); 325 } 326 327 public void testBindKeysWithAnnotationType() { 328 FailingElementVisitor annotationChecker = 329 new FailingElementVisitor() { 330 @Override 331 public <T> Void visit(Binding<T> command) { 332 assertEquals(Key.get(String.class, SampleAnnotation.class), command.getKey()); 333 return null; 334 } 335 }; 336 337 checkModule( 338 new AbstractModule() { 339 @Override 340 protected void configure() { 341 bind(String.class).annotatedWith(SampleAnnotation.class).toInstance("A"); 342 bind(new TypeLiteral<String>() {}) 343 .annotatedWith(SampleAnnotation.class) 344 .toInstance("B"); 345 } 346 }, 347 annotationChecker, 348 annotationChecker); 349 } 350 351 public void testBindKeysWithAnnotationInstance() { 352 FailingElementVisitor annotationChecker = 353 new FailingElementVisitor() { 354 @Override 355 public <T> Void visit(Binding<T> command) { 356 assertEquals(Key.get(String.class, Names.named("a")), command.getKey()); 357 return null; 358 } 359 }; 360 361 checkModule( 362 new AbstractModule() { 363 @Override 364 protected void configure() { 365 bind(String.class).annotatedWith(Names.named("a")).toInstance("B"); 366 bind(new TypeLiteral<String>() {}).annotatedWith(Names.named("a")).toInstance("C"); 367 } 368 }, 369 annotationChecker, 370 annotationChecker); 371 } 372 373 public void testBindToProvider() { 374 final Provider<String> aProvider = 375 new Provider<String>() { 376 @Override 377 public String get() { 378 return "A"; 379 } 380 }; 381 382 final javax.inject.Provider<Integer> intJavaxProvider = 383 new javax.inject.Provider<Integer>() { 384 @Override 385 public Integer get() { 386 return 42; 387 } 388 }; 389 390 final javax.inject.Provider<Double> doubleJavaxProvider = 391 new javax.inject.Provider<Double>() { 392 @javax.inject.Inject String string; 393 394 @Override 395 public Double get() { 396 return 42.42; 397 } 398 }; 399 400 checkModule( 401 new AbstractModule() { 402 @Override 403 protected void configure() { 404 bind(String.class).toProvider(aProvider); 405 bind(Integer.class).toProvider(intJavaxProvider); 406 bind(Double.class).toProvider(doubleJavaxProvider); 407 bind(List.class).toProvider(ListProvider.class); 408 bind(Collection.class).toProvider(Key.get(ListProvider.class)); 409 bind(Iterable.class).toProvider(new TypeLiteral<TProvider<List>>() {}); 410 } 411 }, 412 new FailingElementVisitor() { 413 @Override 414 public <T> Void visit(Binding<T> command) { 415 assertTrue(command instanceof ProviderInstanceBinding); 416 assertEquals(Key.get(String.class), command.getKey()); 417 command.acceptTargetVisitor( 418 new FailingTargetVisitor<T>() { 419 @Override 420 public Void visit(ProviderInstanceBinding<? extends T> binding) { 421 assertSame(aProvider, binding.getUserSuppliedProvider()); 422 assertSame(aProvider, binding.getProviderInstance()); 423 return null; 424 } 425 }); 426 return null; 427 } 428 }, 429 new FailingElementVisitor() { 430 @Override 431 public <T> Void visit(Binding<T> command) { 432 assertTrue(command instanceof ProviderInstanceBinding); 433 assertEquals(Key.get(Integer.class), command.getKey()); 434 command.acceptTargetVisitor( 435 new FailingTargetVisitor<T>() { 436 @Override 437 public Void visit(ProviderInstanceBinding<? extends T> binding) { 438 assertSame(intJavaxProvider, binding.getUserSuppliedProvider()); 439 assertEquals(42, binding.getProviderInstance().get()); 440 // we don't wrap this w/ dependencies if there were none. 441 assertFalse(binding.getProviderInstance() instanceof HasDependencies); 442 return null; 443 } 444 }); 445 return null; 446 } 447 }, 448 new FailingElementVisitor() { 449 @Override 450 public <T> Void visit(Binding<T> command) { 451 assertTrue(command instanceof ProviderInstanceBinding); 452 assertEquals(Key.get(Double.class), command.getKey()); 453 command.acceptTargetVisitor( 454 new FailingTargetVisitor<T>() { 455 @Override 456 public Void visit(ProviderInstanceBinding<? extends T> binding) { 457 assertSame(doubleJavaxProvider, binding.getUserSuppliedProvider()); 458 assertEquals(42.42, binding.getProviderInstance().get()); 459 // we do wrap it with dependencies if there were some. 460 assertTrue(binding.getProviderInstance() instanceof HasDependencies); 461 Set<Dependency<?>> deps = 462 ((HasDependencies) binding.getProviderInstance()).getDependencies(); 463 assertEquals(1, deps.size()); 464 assertEquals( 465 String.class, 466 deps.iterator().next().getKey().getTypeLiteral().getRawType()); 467 return null; 468 } 469 }); 470 return null; 471 } 472 }, 473 new FailingElementVisitor() { 474 @Override 475 public <T> Void visit(Binding<T> command) { 476 assertTrue(command instanceof ProviderKeyBinding); 477 assertEquals(Key.get(List.class), command.getKey()); 478 command.acceptTargetVisitor( 479 new FailingTargetVisitor<T>() { 480 @Override 481 public Void visit(ProviderKeyBinding<? extends T> binding) { 482 assertEquals(Key.get(ListProvider.class), binding.getProviderKey()); 483 return null; 484 } 485 }); 486 return null; 487 } 488 }, 489 new FailingElementVisitor() { 490 @Override 491 public <T> Void visit(Binding<T> command) { 492 assertTrue(command instanceof ProviderKeyBinding); 493 assertEquals(Key.get(Collection.class), command.getKey()); 494 command.acceptTargetVisitor( 495 new FailingTargetVisitor<T>() { 496 @Override 497 public Void visit(ProviderKeyBinding<? extends T> binding) { 498 assertEquals(Key.get(ListProvider.class), binding.getProviderKey()); 499 return null; 500 } 501 }); 502 return null; 503 } 504 }, 505 new FailingElementVisitor() { 506 @Override 507 public <T> Void visit(Binding<T> command) { 508 assertTrue(command instanceof ProviderKeyBinding); 509 assertEquals(Key.get(Iterable.class), command.getKey()); 510 command.acceptTargetVisitor( 511 new FailingTargetVisitor<T>() { 512 @Override 513 public Void visit(ProviderKeyBinding<? extends T> binding) { 514 assertEquals(new Key<TProvider<List>>() {}, binding.getProviderKey()); 515 return null; 516 } 517 }); 518 return null; 519 } 520 }); 521 } 522 523 public void testBindToLinkedBinding() { 524 checkModule( 525 new AbstractModule() { 526 @Override 527 protected void configure() { 528 bind(List.class).to(ArrayList.class); 529 bind(Map.class).to(new TypeLiteral<HashMap<Integer, String>>() {}); 530 bind(Set.class).to(Key.get(TreeSet.class, SampleAnnotation.class)); 531 } 532 }, 533 new FailingElementVisitor() { 534 @Override 535 public <T> Void visit(Binding<T> command) { 536 assertTrue(command instanceof LinkedKeyBinding); 537 assertEquals(Key.get(List.class), command.getKey()); 538 command.acceptTargetVisitor( 539 new FailingTargetVisitor<T>() { 540 @Override 541 public Void visit(LinkedKeyBinding<? extends T> binding) { 542 assertEquals(Key.get(ArrayList.class), binding.getLinkedKey()); 543 return null; 544 } 545 }); 546 return null; 547 } 548 }, 549 new FailingElementVisitor() { 550 @Override 551 public <T> Void visit(Binding<T> command) { 552 assertTrue(command instanceof LinkedKeyBinding); 553 assertEquals(Key.get(Map.class), command.getKey()); 554 command.acceptTargetVisitor( 555 new FailingTargetVisitor<T>() { 556 @Override 557 public Void visit(LinkedKeyBinding<? extends T> binding) { 558 assertEquals( 559 Key.get(new TypeLiteral<HashMap<Integer, String>>() {}), 560 binding.getLinkedKey()); 561 return null; 562 } 563 }); 564 return null; 565 } 566 }, 567 new FailingElementVisitor() { 568 @Override 569 public <T> Void visit(Binding<T> command) { 570 assertTrue(command instanceof LinkedKeyBinding); 571 assertEquals(Key.get(Set.class), command.getKey()); 572 command.acceptTargetVisitor( 573 new FailingTargetVisitor<T>() { 574 @Override 575 public Void visit(LinkedKeyBinding<? extends T> binding) { 576 assertEquals( 577 Key.get(TreeSet.class, SampleAnnotation.class), binding.getLinkedKey()); 578 return null; 579 } 580 }); 581 return null; 582 } 583 }); 584 } 585 586 public void testBindToInstance() { 587 checkModule( 588 new AbstractModule() { 589 @Override 590 protected void configure() { 591 bind(String.class).toInstance("A"); 592 } 593 }, 594 new FailingElementVisitor() { 595 @Override 596 public <T> Void visit(Binding<T> command) { 597 assertTrue(command instanceof InstanceBinding); 598 assertEquals(Key.get(String.class), command.getKey()); 599 assertEquals("A", getInstance(command)); 600 return null; 601 } 602 }); 603 } 604 605 public void testBindInScopes() { 606 checkModule( 607 new AbstractModule() { 608 @Override 609 protected void configure() { 610 bind(String.class); 611 bind(List.class).to(ArrayList.class).in(Scopes.SINGLETON); 612 bind(Map.class).to(HashMap.class).in(Singleton.class); 613 bind(Set.class).to(TreeSet.class).asEagerSingleton(); 614 } 615 }, 616 new FailingElementVisitor() { 617 @Override 618 public <T> Void visit(Binding<T> command) { 619 assertEquals(Key.get(String.class), command.getKey()); 620 command.acceptScopingVisitor( 621 new FailingBindingScopingVisitor() { 622 @Override 623 public Void visitNoScoping() { 624 return null; 625 } 626 }); 627 return null; 628 } 629 }, 630 new FailingElementVisitor() { 631 @Override 632 public <T> Void visit(Binding<T> command) { 633 assertEquals(Key.get(List.class), command.getKey()); 634 command.acceptScopingVisitor( 635 new FailingBindingScopingVisitor() { 636 @Override 637 public Void visitScope(Scope scope) { 638 assertEquals(Scopes.SINGLETON, scope); 639 return null; 640 } 641 }); 642 return null; 643 } 644 }, 645 new FailingElementVisitor() { 646 @Override 647 public <T> Void visit(Binding<T> command) { 648 assertEquals(Key.get(Map.class), command.getKey()); 649 command.acceptScopingVisitor( 650 new FailingBindingScopingVisitor() { 651 @Override 652 public Void visitScopeAnnotation(Class<? extends Annotation> annotation) { 653 assertEquals(Singleton.class, annotation); 654 return null; 655 } 656 }); 657 return null; 658 } 659 }, 660 new FailingElementVisitor() { 661 @Override 662 public <T> Void visit(Binding<T> command) { 663 assertEquals(Key.get(Set.class), command.getKey()); 664 command.acceptScopingVisitor( 665 new FailingBindingScopingVisitor() { 666 @Override 667 public Void visitEagerSingleton() { 668 return null; 669 } 670 }); 671 return null; 672 } 673 }); 674 } 675 676 public void testBindToInstanceInScope() { 677 checkModule( 678 new AbstractModule() { 679 @Override 680 protected void configure() { 681 AnnotatedBindingBuilder<String> b = bind(String.class); 682 b.toInstance("A"); 683 b.in(Singleton.class); 684 } 685 }, 686 new FailingElementVisitor() { 687 @Override 688 public <T> Void visit(Binding<T> command) { 689 return null; 690 } 691 }, 692 new FailingElementVisitor() { 693 @Override 694 public Void visit(Message command) { 695 assertEquals( 696 "Setting the scope is not permitted when binding to a single instance.", 697 command.getMessage()); 698 assertNull(command.getCause()); 699 assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class)); 700 return null; 701 } 702 }); 703 } 704 705 public void testBindToInstanceScope() { 706 checkModule( 707 new AbstractModule() { 708 @Override 709 protected void configure() { 710 bind(String.class).toInstance("A"); 711 } 712 }, 713 new FailingElementVisitor() { 714 @Override 715 public <T> Void visit(Binding<T> binding) { 716 assertEquals(Key.get(String.class), binding.getKey()); 717 binding.acceptScopingVisitor( 718 new FailingBindingScopingVisitor() { 719 @Override 720 public Void visitEagerSingleton() { 721 return null; 722 } 723 }); 724 return null; 725 } 726 }); 727 } 728 729 /*if[AOP]*/ 730 public void testBindIntercepor() { 731 final Matcher<Class> classMatcher = Matchers.subclassesOf(List.class); 732 final Matcher<Object> methodMatcher = Matchers.any(); 733 final org.aopalliance.intercept.MethodInterceptor methodInterceptor = 734 new org.aopalliance.intercept.MethodInterceptor() { 735 @Override 736 public Object invoke(org.aopalliance.intercept.MethodInvocation methodInvocation) { 737 return null; 738 } 739 }; 740 741 checkModule( 742 new AbstractModule() { 743 @Override 744 protected void configure() { 745 bindInterceptor(classMatcher, methodMatcher, methodInterceptor); 746 } 747 }, 748 new FailingElementVisitor() { 749 @Override 750 public Void visit(InterceptorBinding command) { 751 assertSame(classMatcher, command.getClassMatcher()); 752 assertSame(methodMatcher, command.getMethodMatcher()); 753 assertEquals(Arrays.asList(methodInterceptor), command.getInterceptors()); 754 return null; 755 } 756 }); 757 } 758 /*end[AOP]*/ 759 760 public void testBindScope() { 761 checkModule( 762 new AbstractModule() { 763 @Override 764 protected void configure() { 765 bindScope(SampleAnnotation.class, Scopes.NO_SCOPE); 766 } 767 }, 768 new FailingElementVisitor() { 769 @Override 770 public Void visit(ScopeBinding command) { 771 assertSame(SampleAnnotation.class, command.getAnnotationType()); 772 assertSame(Scopes.NO_SCOPE, command.getScope()); 773 return null; 774 } 775 }); 776 } 777 778 public void testBindListener() { 779 final Matcher<Object> typeMatcher = Matchers.only(TypeLiteral.get(String.class)); 780 final TypeListener listener = 781 new TypeListener() { 782 @Override 783 public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) { 784 throw new UnsupportedOperationException(); 785 } 786 }; 787 788 checkModule( 789 new AbstractModule() { 790 @Override 791 protected void configure() { 792 bindListener(typeMatcher, listener); 793 } 794 }, 795 new FailingElementVisitor() { 796 @Override 797 public Void visit(TypeListenerBinding binding) { 798 assertSame(typeMatcher, binding.getTypeMatcher()); 799 assertSame(listener, binding.getListener()); 800 return null; 801 } 802 }); 803 } 804 805 public void testConvertToTypes() { 806 final TypeConverter typeConverter = 807 new TypeConverter() { 808 @Override 809 public Object convert(String value, TypeLiteral<?> toType) { 810 return value; 811 } 812 }; 813 814 checkModule( 815 new AbstractModule() { 816 @Override 817 protected void configure() { 818 convertToTypes(Matchers.any(), typeConverter); 819 } 820 }, 821 new FailingElementVisitor() { 822 @Override 823 public Void visit(TypeConverterBinding command) { 824 assertSame(typeConverter, command.getTypeConverter()); 825 assertSame(Matchers.any(), command.getTypeMatcher()); 826 return null; 827 } 828 }); 829 } 830 831 public void testGetProvider() { 832 checkModule( 833 new AbstractModule() { 834 @Override 835 protected void configure() { 836 Provider<String> keyGetProvider = 837 getProvider(Key.get(String.class, SampleAnnotation.class)); 838 try { 839 keyGetProvider.get(); 840 fail("Expected IllegalStateException"); 841 } catch (IllegalStateException e) { 842 assertEquals( 843 "This Provider cannot be used until the Injector has been created.", 844 e.getMessage()); 845 } 846 847 Provider<String> typeGetProvider = getProvider(String.class); 848 try { 849 typeGetProvider.get(); 850 fail("Expected IllegalStateException"); 851 } catch (IllegalStateException e) { 852 assertEquals( 853 "This Provider cannot be used until the Injector has been created.", 854 e.getMessage()); 855 } 856 } 857 }, 858 new FailingElementVisitor() { 859 @Override 860 public <T> Void visit(ProviderLookup<T> command) { 861 assertEquals(Key.get(String.class, SampleAnnotation.class), command.getKey()); 862 assertNull(command.getDelegate()); 863 return null; 864 } 865 }, 866 new FailingElementVisitor() { 867 @Override 868 public <T> Void visit(ProviderLookup<T> command) { 869 assertEquals(Key.get(String.class), command.getKey()); 870 assertNull(command.getDelegate()); 871 return null; 872 } 873 }); 874 } 875 876 public void testElementInitialization() { 877 final AtomicReference<Provider<String>> providerFromBinder = 878 new AtomicReference<Provider<String>>(); 879 final AtomicReference<MembersInjector<String>> membersInjectorFromBinder = 880 new AtomicReference<MembersInjector<String>>(); 881 882 final AtomicReference<String> lastInjected = new AtomicReference<>(); 883 final MembersInjector<String> stringInjector = 884 new MembersInjector<String>() { 885 @Override 886 public void injectMembers(String instance) { 887 lastInjected.set(instance); 888 } 889 }; 890 891 checkModule( 892 new AbstractModule() { 893 @Override 894 protected void configure() { 895 providerFromBinder.set(getProvider(String.class)); 896 membersInjectorFromBinder.set(getMembersInjector(String.class)); 897 } 898 }, 899 new FailingElementVisitor() { 900 @Override 901 public <T> Void visit(ProviderLookup<T> providerLookup) { 902 @SuppressWarnings("unchecked") // we know that T is a String here 903 ProviderLookup<String> stringLookup = (ProviderLookup<String>) providerLookup; 904 stringLookup.initializeDelegate(Providers.of("out")); 905 906 assertEquals("out", providerFromBinder.get().get()); 907 return null; 908 } 909 }, 910 new FailingElementVisitor() { 911 @Override 912 public <T> Void visit(MembersInjectorLookup<T> lookup) { 913 @SuppressWarnings("unchecked") // we know that T is a String here 914 MembersInjectorLookup<String> stringLookup = (MembersInjectorLookup<String>) lookup; 915 stringLookup.initializeDelegate(stringInjector); 916 917 membersInjectorFromBinder.get().injectMembers("in"); 918 assertEquals("in", lastInjected.get()); 919 return null; 920 } 921 }); 922 } 923 924 public void testGetMembersInjector() { 925 checkModule( 926 new AbstractModule() { 927 @Override 928 protected void configure() { 929 MembersInjector<A<String>> typeMembersInjector = 930 getMembersInjector(new TypeLiteral<A<String>>() {}); 931 try { 932 typeMembersInjector.injectMembers(new A<String>()); 933 fail("Expected IllegalStateException"); 934 } catch (IllegalStateException e) { 935 assertEquals( 936 "This MembersInjector cannot be used until the Injector has been created.", 937 e.getMessage()); 938 } 939 940 MembersInjector<String> classMembersInjector = getMembersInjector(String.class); 941 try { 942 classMembersInjector.injectMembers("hello"); 943 fail("Expected IllegalStateException"); 944 } catch (IllegalStateException e) { 945 assertEquals( 946 "This MembersInjector cannot be used until the Injector has been created.", 947 e.getMessage()); 948 } 949 } 950 }, 951 new FailingElementVisitor() { 952 @Override 953 public <T> Void visit(MembersInjectorLookup<T> command) { 954 assertEquals(new TypeLiteral<A<String>>() {}, command.getType()); 955 assertNull(command.getDelegate()); 956 return null; 957 } 958 }, 959 new FailingElementVisitor() { 960 @Override 961 public <T> Void visit(MembersInjectorLookup<T> command) { 962 assertEquals(TypeLiteral.get(String.class), command.getType()); 963 assertNull(command.getDelegate()); 964 return null; 965 } 966 }); 967 } 968 969 public void testRequestInjection() { 970 final Object firstObject = new Object(); 971 final Object secondObject = new Object(); 972 973 checkModule( 974 new AbstractModule() { 975 @Override 976 protected void configure() { 977 requestInjection(firstObject); 978 requestInjection(secondObject); 979 } 980 }, 981 new FailingElementVisitor() { 982 @Override 983 public Void visit(InjectionRequest<?> command) { 984 assertEquals(firstObject, command.getInstance()); 985 return null; 986 } 987 }, 988 new FailingElementVisitor() { 989 @Override 990 public Void visit(InjectionRequest<?> command) { 991 assertEquals(secondObject, command.getInstance()); 992 return null; 993 } 994 }); 995 } 996 997 public void testRequestStaticInjection() { 998 checkModule( 999 new AbstractModule() { 1000 @Override 1001 protected void configure() { 1002 requestStaticInjection(ArrayList.class); 1003 } 1004 }, 1005 new FailingElementVisitor() { 1006 @Override 1007 public Void visit(StaticInjectionRequest command) { 1008 assertEquals(ArrayList.class, command.getType()); 1009 return null; 1010 } 1011 }); 1012 } 1013 1014 public void testNewPrivateBinder() { 1015 final Key<Collection> collection = Key.get(Collection.class, SampleAnnotation.class); 1016 final Key<ArrayList> arrayList = Key.get(ArrayList.class); 1017 final ImmutableSet<Key<?>> collections = ImmutableSet.<Key<?>>of(arrayList, collection); 1018 1019 final Key<?> a = Key.get(String.class, Names.named("a")); 1020 final Key<?> b = Key.get(String.class, Names.named("b")); 1021 final ImmutableSet<Key<?>> ab = ImmutableSet.of(a, b); 1022 1023 checkModule( 1024 new AbstractModule() { 1025 @Override 1026 protected void configure() { 1027 PrivateBinder one = binder().newPrivateBinder(); 1028 one.expose(ArrayList.class); 1029 one.expose(Collection.class).annotatedWith(SampleAnnotation.class); 1030 one.bind(List.class).to(ArrayList.class); 1031 1032 PrivateBinder two = 1033 binder().withSource("1 FooBar").newPrivateBinder().withSource("2 FooBar"); 1034 two.expose(String.class).annotatedWith(Names.named("a")); 1035 two.expose(b); 1036 two.bind(List.class).to(ArrayList.class); 1037 } 1038 }, 1039 new FailingElementVisitor() { 1040 @Override 1041 public Void visit(PrivateElements one) { 1042 assertEquals(collections, one.getExposedKeys()); 1043 checkElements( 1044 one.getElements(), 1045 new FailingElementVisitor() { 1046 @Override 1047 public <T> Void visit(Binding<T> binding) { 1048 assertEquals(Key.get(List.class), binding.getKey()); 1049 return null; 1050 } 1051 }); 1052 return null; 1053 } 1054 }, 1055 new ExternalFailureVisitor() { 1056 @Override 1057 public Void visit(PrivateElements two) { 1058 assertEquals(ab, two.getExposedKeys()); 1059 assertEquals("1 FooBar", two.getSource().toString()); 1060 checkElements( 1061 two.getElements(), 1062 new ExternalFailureVisitor() { 1063 @Override 1064 public <T> Void visit(Binding<T> binding) { 1065 assertEquals("2 FooBar", binding.getSource().toString()); 1066 assertEquals(Key.get(List.class), binding.getKey()); 1067 return null; 1068 } 1069 }); 1070 return null; 1071 } 1072 }); 1073 } 1074 1075 public void testBindWithMultipleAnnotationsAddsError() { 1076 checkModule( 1077 new AbstractModule() { 1078 @Override 1079 protected void configure() { 1080 AnnotatedBindingBuilder<String> abb = bind(String.class); 1081 abb.annotatedWith(SampleAnnotation.class); 1082 abb.annotatedWith(Names.named("A")); 1083 } 1084 }, 1085 new FailingElementVisitor() { 1086 @Override 1087 public <T> Void visit(Binding<T> command) { 1088 return null; 1089 } 1090 }, 1091 new FailingElementVisitor() { 1092 @Override 1093 public Void visit(Message command) { 1094 assertEquals( 1095 "More than one annotation is specified for this binding.", command.getMessage()); 1096 assertNull(command.getCause()); 1097 assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class)); 1098 return null; 1099 } 1100 }); 1101 } 1102 1103 public void testBindWithMultipleTargetsAddsError() { 1104 checkModule( 1105 new AbstractModule() { 1106 @Override 1107 protected void configure() { 1108 AnnotatedBindingBuilder<String> abb = bind(String.class); 1109 abb.toInstance("A"); 1110 abb.toInstance("B"); 1111 } 1112 }, 1113 new FailingElementVisitor() { 1114 @Override 1115 public <T> Void visit(Binding<T> command) { 1116 return null; 1117 } 1118 }, 1119 new FailingElementVisitor() { 1120 @Override 1121 public Void visit(Message command) { 1122 assertEquals("Implementation is set more than once.", command.getMessage()); 1123 assertNull(command.getCause()); 1124 assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class)); 1125 return null; 1126 } 1127 }); 1128 } 1129 1130 public void testBindWithMultipleScopesAddsError() { 1131 checkModule( 1132 new AbstractModule() { 1133 @Override 1134 protected void configure() { 1135 ScopedBindingBuilder sbb = bind(List.class).to(ArrayList.class); 1136 sbb.in(Scopes.NO_SCOPE); 1137 sbb.asEagerSingleton(); 1138 } 1139 }, 1140 new FailingElementVisitor() { 1141 @Override 1142 public <T> Void visit(Binding<T> command) { 1143 return null; 1144 } 1145 }, 1146 new FailingElementVisitor() { 1147 @Override 1148 public Void visit(Message command) { 1149 assertEquals("Scope is set more than once.", command.getMessage()); 1150 assertNull(command.getCause()); 1151 assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class)); 1152 return null; 1153 } 1154 }); 1155 } 1156 1157 public void testBindConstantWithMultipleAnnotationsAddsError() { 1158 checkModule( 1159 new AbstractModule() { 1160 @Override 1161 protected void configure() { 1162 AnnotatedConstantBindingBuilder cbb = bindConstant(); 1163 cbb.annotatedWith(SampleAnnotation.class).to("A"); 1164 cbb.annotatedWith(Names.named("A")); 1165 } 1166 }, 1167 new FailingElementVisitor() { 1168 @Override 1169 public <T> Void visit(Binding<T> command) { 1170 return null; 1171 } 1172 }, 1173 new FailingElementVisitor() { 1174 @Override 1175 public Void visit(Message command) { 1176 assertEquals( 1177 "More than one annotation is specified for this binding.", command.getMessage()); 1178 assertNull(command.getCause()); 1179 assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class)); 1180 return null; 1181 } 1182 }); 1183 } 1184 1185 public void testBindConstantWithMultipleTargetsAddsError() { 1186 checkModule( 1187 new AbstractModule() { 1188 @Override 1189 protected void configure() { 1190 ConstantBindingBuilder cbb = bindConstant().annotatedWith(SampleAnnotation.class); 1191 cbb.to("A"); 1192 cbb.to("B"); 1193 } 1194 }, 1195 new FailingElementVisitor() { 1196 @Override 1197 public <T> Void visit(Binding<T> command) { 1198 return null; 1199 } 1200 }, 1201 new FailingElementVisitor() { 1202 @Override 1203 public Void visit(Message message) { 1204 assertEquals("Constant value is set more than once.", message.getMessage()); 1205 assertNull(message.getCause()); 1206 assertContains(message.getSource(), getDeclaringSourcePart(ElementsTest.class)); 1207 return null; 1208 } 1209 }); 1210 } 1211 1212 public void testBindToConstructor() throws NoSuchMethodException, NoSuchFieldException { 1213 final Constructor<A> aConstructor = A.class.getDeclaredConstructor(); 1214 final Constructor<B> bConstructor = B.class.getDeclaredConstructor(Object.class); 1215 final Field field = B.class.getDeclaredField("stage"); 1216 1217 checkModule( 1218 new AbstractModule() { 1219 @Override 1220 protected void configure() { 1221 bind(A.class).toConstructor(aConstructor); 1222 bind(B.class) 1223 .toConstructor(bConstructor, new TypeLiteral<B<Integer>>() {}) 1224 .in(Singleton.class); 1225 } 1226 }, 1227 new FailingElementVisitor() { 1228 @Override 1229 public <T> Void visit(Binding<T> binding) { 1230 assertEquals(new Key<A>() {}, binding.getKey()); 1231 1232 return binding.acceptTargetVisitor( 1233 new FailingTargetVisitor<T>() { 1234 @Override 1235 public Void visit(ConstructorBinding<? extends T> constructorBinding) { 1236 InjectionPoint injectionPoint = constructorBinding.getConstructor(); 1237 assertEquals(aConstructor, injectionPoint.getMember()); 1238 assertEquals(new TypeLiteral<A>() {}, injectionPoint.getDeclaringType()); 1239 return null; 1240 } 1241 }); 1242 } 1243 }, 1244 new FailingElementVisitor() { 1245 @Override 1246 public <T> Void visit(Binding<T> binding) { 1247 assertEquals(new Key<B>() {}, binding.getKey()); 1248 binding.acceptScopingVisitor( 1249 new FailingBindingScopingVisitor() { 1250 @Override 1251 public Void visitScopeAnnotation(Class<? extends Annotation> annotation) { 1252 assertEquals(Singleton.class, annotation); 1253 return null; 1254 } 1255 }); 1256 1257 binding.acceptTargetVisitor( 1258 new FailingTargetVisitor<T>() { 1259 @Override 1260 public Void visit(ConstructorBinding<? extends T> constructorBinding) { 1261 assertEquals(bConstructor, constructorBinding.getConstructor().getMember()); 1262 assertEquals( 1263 Key.get(Integer.class), 1264 getOnlyElement(constructorBinding.getConstructor().getDependencies()) 1265 .getKey()); 1266 assertEquals( 1267 field, 1268 getOnlyElement(constructorBinding.getInjectableMembers()).getMember()); 1269 assertEquals(2, constructorBinding.getDependencies().size()); 1270 /*if[AOP]*/ 1271 assertEquals(ImmutableMap.of(), constructorBinding.getMethodInterceptors()); 1272 /*end[AOP]*/ 1273 return null; 1274 } 1275 }); 1276 return null; 1277 } 1278 }); 1279 } 1280 1281 public void testBindToMalformedConstructor() throws NoSuchMethodException, NoSuchFieldException { 1282 final Constructor<C> constructor = C.class.getDeclaredConstructor(Integer.class); 1283 1284 checkModule( 1285 new AbstractModule() { 1286 @Override 1287 protected void configure() { 1288 bind(C.class).toConstructor(constructor); 1289 } 1290 }, 1291 new FailingElementVisitor() { 1292 @Override 1293 public <T> Void visit(Binding<T> binding) { 1294 assertEquals(Key.get(C.class), binding.getKey()); 1295 assertTrue(binding instanceof UntargettedBinding); 1296 return null; 1297 } 1298 }, 1299 new ExternalFailureVisitor() { 1300 @Override 1301 public Void visit(Message message) { 1302 assertContains( 1303 message.getMessage(), 1304 C.class.getName() + ".a has more than one annotation ", 1305 Named.class.getName(), 1306 SampleAnnotation.class.getName()); 1307 return null; 1308 } 1309 }, 1310 new ExternalFailureVisitor() { 1311 @Override 1312 public Void visit(Message message) { 1313 assertContains( 1314 message.getMessage(), 1315 C.class.getName() + ".<init>() has more than one annotation ", 1316 Named.class.getName(), 1317 SampleAnnotation.class.getName()); 1318 return null; 1319 } 1320 }); 1321 } 1322 1323 // Business logic tests 1324 1325 public void testModulesAreInstalledAtMostOnce() { 1326 final AtomicInteger aConfigureCount = new AtomicInteger(0); 1327 final Module a = 1328 new AbstractModule() { 1329 @Override 1330 public void configure() { 1331 aConfigureCount.incrementAndGet(); 1332 } 1333 }; 1334 1335 Elements.getElements(a, a); 1336 assertEquals(1, aConfigureCount.get()); 1337 1338 aConfigureCount.set(0); 1339 Module b = 1340 new AbstractModule() { 1341 @Override 1342 protected void configure() { 1343 install(a); 1344 install(a); 1345 } 1346 }; 1347 1348 Elements.getElements(b); 1349 assertEquals(1, aConfigureCount.get()); 1350 } 1351 1352 /** Ensures the module performs the commands consistent with {@code visitors}. */ 1353 protected void checkModule(Module module, ElementVisitor<?>... visitors) { 1354 List<Element> elements = Elements.getElements(module); 1355 assertEquals(elements.size(), visitors.length); 1356 checkElements(elements, visitors); 1357 } 1358 1359 protected void checkElements(List<Element> elements, ElementVisitor<?>... visitors) { 1360 for (int i = 0; i < visitors.length; i++) { 1361 ElementVisitor<?> visitor = visitors[i]; 1362 Element element = elements.get(i); 1363 if (!(element instanceof Message)) { 1364 ElementSource source = (ElementSource) element.getSource(); 1365 assertFalse(source.getModuleClassNames().isEmpty()); 1366 if (isIncludeStackTraceComplete()) { 1367 assertTrue(source.getStackTrace().length > 0); 1368 } else { 1369 assertEquals(0, source.getStackTrace().length); 1370 } 1371 } 1372 if (!(visitor instanceof ExternalFailureVisitor)) { 1373 assertContains(element.getSource().toString(), getDeclaringSourcePart(ElementsTest.class)); 1374 } 1375 element.acceptVisitor(visitor); 1376 } 1377 } 1378 1379 private static class ListProvider implements Provider<List> { 1380 @Override 1381 public List get() { 1382 return new ArrayList(); 1383 } 1384 } 1385 1386 private static class TProvider<T> implements Provider<T> { 1387 @Override 1388 public T get() { 1389 return null; 1390 } 1391 } 1392 1393 /** 1394 * By extending this interface rather than FailingElementVisitor, the source of the error doesn't 1395 * need to contain the string {@code ElementsTest.java}. 1396 */ 1397 abstract static class ExternalFailureVisitor extends FailingElementVisitor {} 1398 1399 @Retention(RUNTIME) 1400 @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) 1401 @BindingAnnotation 1402 public @interface SampleAnnotation {} 1403 1404 public enum CoinSide { 1405 HEADS, 1406 TAILS 1407 } 1408 1409 static class A<T> { 1410 @Inject Stage stage; 1411 } 1412 1413 static class B<T> { 1414 @Inject Stage stage; 1415 1416 B(T t) {} 1417 } 1418 1419 static class C { 1420 @Inject 1421 @Named("foo") 1422 @SampleAnnotation 1423 String a; 1424 1425 C(@Named("bar") @SampleAnnotation Integer b) {} 1426 } 1427 } 1428