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