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.internal; 18 19 import static com.google.inject.Asserts.assertContains; 20 import static com.google.inject.internal.RealMultibinder.collectionOfJavaxProvidersOf; 21 import static com.google.inject.internal.SpiUtils.VisitType.BOTH; 22 import static com.google.inject.internal.SpiUtils.VisitType.MODULE; 23 import static com.google.inject.internal.SpiUtils.assertSetVisitor; 24 import static com.google.inject.internal.SpiUtils.instance; 25 import static com.google.inject.internal.SpiUtils.providerInstance; 26 import static com.google.inject.name.Names.named; 27 import static java.lang.annotation.RetentionPolicy.RUNTIME; 28 29 import com.google.common.base.Optional; 30 import com.google.common.base.Predicates; 31 import com.google.common.collect.FluentIterable; 32 import com.google.common.collect.ImmutableList; 33 import com.google.common.collect.ImmutableMap; 34 import com.google.common.collect.ImmutableSet; 35 import com.google.common.collect.Iterables; 36 import com.google.common.collect.Lists; 37 import com.google.common.collect.Sets; 38 import com.google.inject.AbstractModule; 39 import com.google.inject.Binding; 40 import com.google.inject.BindingAnnotation; 41 import com.google.inject.CreationException; 42 import com.google.inject.Guice; 43 import com.google.inject.Inject; 44 import com.google.inject.Injector; 45 import com.google.inject.Key; 46 import com.google.inject.Module; 47 import com.google.inject.Provider; 48 import com.google.inject.Provides; 49 import com.google.inject.ProvisionException; 50 import com.google.inject.Scopes; 51 import com.google.inject.Stage; 52 import com.google.inject.TypeLiteral; 53 import com.google.inject.multibindings.MapBinder; 54 import com.google.inject.multibindings.Multibinder; 55 import com.google.inject.multibindings.OptionalBinder; 56 import com.google.inject.name.Named; 57 import com.google.inject.name.Names; 58 import com.google.inject.spi.Dependency; 59 import com.google.inject.spi.Element; 60 import com.google.inject.spi.Elements; 61 import com.google.inject.spi.HasDependencies; 62 import com.google.inject.spi.InstanceBinding; 63 import com.google.inject.spi.LinkedKeyBinding; 64 import com.google.inject.util.Modules; 65 import com.google.inject.util.Providers; 66 import com.google.inject.util.Types; 67 import java.io.ByteArrayInputStream; 68 import java.io.ByteArrayOutputStream; 69 import java.io.IOException; 70 import java.io.ObjectInputStream; 71 import java.io.ObjectOutputStream; 72 import java.lang.annotation.Annotation; 73 import java.lang.annotation.ElementType; 74 import java.lang.annotation.Retention; 75 import java.lang.annotation.RetentionPolicy; 76 import java.lang.annotation.Target; 77 import java.lang.reflect.Method; 78 import java.util.Collection; 79 import java.util.Collections; 80 import java.util.HashSet; 81 import java.util.List; 82 import java.util.Map; 83 import java.util.Map.Entry; 84 import java.util.Set; 85 import junit.framework.TestCase; 86 87 /** @author jessewilson@google.com (Jesse Wilson) */ 88 public class MultibinderTest extends TestCase { 89 90 final TypeLiteral<Optional<String>> optionalOfString = new TypeLiteral<Optional<String>>() {}; 91 final TypeLiteral<Map<String, String>> mapOfStringString = 92 new TypeLiteral<Map<String, String>>() {}; 93 final TypeLiteral<Set<String>> setOfString = new TypeLiteral<Set<String>>() {}; 94 final TypeLiteral<Set<Integer>> setOfInteger = new TypeLiteral<Set<Integer>>() {}; 95 final TypeLiteral<String> stringType = TypeLiteral.get(String.class); 96 final TypeLiteral<Integer> intType = TypeLiteral.get(Integer.class); 97 final TypeLiteral<List<String>> listOfStrings = new TypeLiteral<List<String>>() {}; 98 final TypeLiteral<Set<List<String>>> setOfListOfStrings = new TypeLiteral<Set<List<String>>>() {}; 99 final TypeLiteral<Collection<Provider<String>>> collectionOfProvidersOfStrings = 100 new TypeLiteral<Collection<Provider<String>>>() {}; 101 testMultibinderAggregatesMultipleModules()102 public void testMultibinderAggregatesMultipleModules() { 103 Module abc = 104 new AbstractModule() { 105 @Override 106 protected void configure() { 107 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 108 multibinder.addBinding().toInstance("A"); 109 multibinder.addBinding().toInstance("B"); 110 multibinder.addBinding().toInstance("C"); 111 } 112 }; 113 Module de = 114 new AbstractModule() { 115 @Override 116 protected void configure() { 117 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 118 multibinder.addBinding().toInstance("D"); 119 multibinder.addBinding().toInstance("E"); 120 } 121 }; 122 123 Injector injector = Guice.createInjector(abc, de); 124 Key<Set<String>> setKey = Key.get(setOfString); 125 Set<String> abcde = injector.getInstance(setKey); 126 Set<String> results = setOf("A", "B", "C", "D", "E"); 127 128 assertEquals(results, abcde); 129 assertSetVisitor( 130 setKey, 131 stringType, 132 setOf(abc, de), 133 BOTH, 134 false, 135 0, 136 instance("A"), 137 instance("B"), 138 instance("C"), 139 instance("D"), 140 instance("E")); 141 } 142 testMultibinderAggregationForAnnotationInstance()143 public void testMultibinderAggregationForAnnotationInstance() { 144 Module module = 145 new AbstractModule() { 146 @Override 147 protected void configure() { 148 Multibinder<String> multibinder = 149 Multibinder.newSetBinder(binder(), String.class, Names.named("abc")); 150 multibinder.addBinding().toInstance("A"); 151 multibinder.addBinding().toInstance("B"); 152 153 multibinder = Multibinder.newSetBinder(binder(), String.class, Names.named("abc")); 154 multibinder.addBinding().toInstance("C"); 155 } 156 }; 157 Injector injector = Guice.createInjector(module); 158 159 Key<Set<String>> setKey = Key.get(setOfString, Names.named("abc")); 160 Set<String> abc = injector.getInstance(setKey); 161 Set<String> results = setOf("A", "B", "C"); 162 assertEquals(results, abc); 163 assertSetVisitor( 164 setKey, 165 stringType, 166 setOf(module), 167 BOTH, 168 false, 169 0, 170 instance("A"), 171 instance("B"), 172 instance("C")); 173 } 174 testMultibinderAggregationForAnnotationType()175 public void testMultibinderAggregationForAnnotationType() { 176 Module module = 177 new AbstractModule() { 178 @Override 179 protected void configure() { 180 Multibinder<String> multibinder = 181 Multibinder.newSetBinder(binder(), String.class, Abc.class); 182 multibinder.addBinding().toInstance("A"); 183 multibinder.addBinding().toInstance("B"); 184 185 multibinder = Multibinder.newSetBinder(binder(), String.class, Abc.class); 186 multibinder.addBinding().toInstance("C"); 187 } 188 }; 189 Injector injector = Guice.createInjector(module); 190 191 Key<Set<String>> setKey = Key.get(setOfString, Abc.class); 192 Set<String> abcde = injector.getInstance(setKey); 193 Set<String> results = setOf("A", "B", "C"); 194 assertEquals(results, abcde); 195 assertSetVisitor( 196 setKey, 197 stringType, 198 setOf(module), 199 BOTH, 200 false, 201 0, 202 instance("A"), 203 instance("B"), 204 instance("C")); 205 } 206 testMultibinderWithMultipleAnnotationValueSets()207 public void testMultibinderWithMultipleAnnotationValueSets() { 208 Module module = 209 new AbstractModule() { 210 @Override 211 protected void configure() { 212 Multibinder<String> abcMultibinder = 213 Multibinder.newSetBinder(binder(), String.class, named("abc")); 214 abcMultibinder.addBinding().toInstance("A"); 215 abcMultibinder.addBinding().toInstance("B"); 216 abcMultibinder.addBinding().toInstance("C"); 217 218 Multibinder<String> deMultibinder = 219 Multibinder.newSetBinder(binder(), String.class, named("de")); 220 deMultibinder.addBinding().toInstance("D"); 221 deMultibinder.addBinding().toInstance("E"); 222 } 223 }; 224 Injector injector = Guice.createInjector(module); 225 226 Key<Set<String>> abcSetKey = Key.get(setOfString, named("abc")); 227 Set<String> abc = injector.getInstance(abcSetKey); 228 Key<Set<String>> deSetKey = Key.get(setOfString, named("de")); 229 Set<String> de = injector.getInstance(deSetKey); 230 Set<String> abcResults = setOf("A", "B", "C"); 231 assertEquals(abcResults, abc); 232 Set<String> deResults = setOf("D", "E"); 233 assertEquals(deResults, de); 234 assertSetVisitor( 235 abcSetKey, 236 stringType, 237 setOf(module), 238 BOTH, 239 false, 240 1, 241 instance("A"), 242 instance("B"), 243 instance("C")); 244 assertSetVisitor( 245 deSetKey, stringType, setOf(module), BOTH, false, 1, instance("D"), instance("E")); 246 } 247 testMultibinderWithMultipleAnnotationTypeSets()248 public void testMultibinderWithMultipleAnnotationTypeSets() { 249 Module module = 250 new AbstractModule() { 251 @Override 252 protected void configure() { 253 Multibinder<String> abcMultibinder = 254 Multibinder.newSetBinder(binder(), String.class, Abc.class); 255 abcMultibinder.addBinding().toInstance("A"); 256 abcMultibinder.addBinding().toInstance("B"); 257 abcMultibinder.addBinding().toInstance("C"); 258 259 Multibinder<String> deMultibinder = 260 Multibinder.newSetBinder(binder(), String.class, De.class); 261 deMultibinder.addBinding().toInstance("D"); 262 deMultibinder.addBinding().toInstance("E"); 263 } 264 }; 265 Injector injector = Guice.createInjector(module); 266 267 Key<Set<String>> abcSetKey = Key.get(setOfString, Abc.class); 268 Set<String> abc = injector.getInstance(abcSetKey); 269 Key<Set<String>> deSetKey = Key.get(setOfString, De.class); 270 Set<String> de = injector.getInstance(deSetKey); 271 Set<String> abcResults = setOf("A", "B", "C"); 272 assertEquals(abcResults, abc); 273 Set<String> deResults = setOf("D", "E"); 274 assertEquals(deResults, de); 275 assertSetVisitor( 276 abcSetKey, 277 stringType, 278 setOf(module), 279 BOTH, 280 false, 281 1, 282 instance("A"), 283 instance("B"), 284 instance("C")); 285 assertSetVisitor( 286 deSetKey, stringType, setOf(module), BOTH, false, 1, instance("D"), instance("E")); 287 } 288 testMultibinderWithMultipleSetTypes()289 public void testMultibinderWithMultipleSetTypes() { 290 Module module = 291 new AbstractModule() { 292 @Override 293 protected void configure() { 294 Multibinder.newSetBinder(binder(), String.class).addBinding().toInstance("A"); 295 Multibinder.newSetBinder(binder(), Integer.class).addBinding().toInstance(1); 296 } 297 }; 298 Injector injector = Guice.createInjector(module); 299 300 assertEquals(setOf("A"), injector.getInstance(Key.get(setOfString))); 301 assertEquals(setOf(1), injector.getInstance(Key.get(setOfInteger))); 302 assertSetVisitor( 303 Key.get(setOfString), stringType, setOf(module), BOTH, false, 1, instance("A")); 304 assertSetVisitor(Key.get(setOfInteger), intType, setOf(module), BOTH, false, 1, instance(1)); 305 } 306 testMultibinderWithEmptySet()307 public void testMultibinderWithEmptySet() { 308 Module module = 309 new AbstractModule() { 310 @Override 311 protected void configure() { 312 Multibinder.newSetBinder(binder(), String.class); 313 } 314 }; 315 Injector injector = Guice.createInjector(module); 316 317 Set<String> set = injector.getInstance(Key.get(setOfString)); 318 assertEquals(Collections.emptySet(), set); 319 assertSetVisitor(Key.get(setOfString), stringType, setOf(module), BOTH, false, 0); 320 } 321 testMultibinderSetIsUnmodifiable()322 public void testMultibinderSetIsUnmodifiable() { 323 Injector injector = 324 Guice.createInjector( 325 new AbstractModule() { 326 @Override 327 protected void configure() { 328 Multibinder.newSetBinder(binder(), String.class).addBinding().toInstance("A"); 329 } 330 }); 331 332 Set<String> set = injector.getInstance(Key.get(setOfString)); 333 try { 334 set.clear(); 335 fail(); 336 } catch (UnsupportedOperationException expected) { 337 } 338 } 339 testMultibinderSetIsSerializable()340 public void testMultibinderSetIsSerializable() throws IOException, ClassNotFoundException { 341 Injector injector = 342 Guice.createInjector( 343 new AbstractModule() { 344 @Override 345 protected void configure() { 346 Multibinder.newSetBinder(binder(), String.class).addBinding().toInstance("A"); 347 } 348 }); 349 350 Set<String> set = injector.getInstance(Key.get(setOfString)); 351 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 352 ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream); 353 try { 354 objectOutputStream.writeObject(set); 355 } finally { 356 objectOutputStream.close(); 357 } 358 ObjectInputStream objectInputStream = 359 new ObjectInputStream(new ByteArrayInputStream(byteStream.toByteArray())); 360 try { 361 Object setCopy = objectInputStream.readObject(); 362 assertEquals(set, setCopy); 363 } finally { 364 objectInputStream.close(); 365 } 366 } 367 testMultibinderSetIsLazy()368 public void testMultibinderSetIsLazy() { 369 Module module = 370 new AbstractModule() { 371 @Override 372 protected void configure() { 373 Multibinder.newSetBinder(binder(), Integer.class) 374 .addBinding() 375 .toProvider( 376 new Provider<Integer>() { 377 int nextValue = 1; 378 379 @Override 380 public Integer get() { 381 return nextValue++; 382 } 383 }); 384 } 385 }; 386 Injector injector = Guice.createInjector(module); 387 388 assertEquals(setOf(1), injector.getInstance(Key.get(setOfInteger))); 389 assertEquals(setOf(2), injector.getInstance(Key.get(setOfInteger))); 390 assertEquals(setOf(3), injector.getInstance(Key.get(setOfInteger))); 391 assertSetVisitor( 392 Key.get(setOfInteger), intType, setOf(module), BOTH, false, 0, providerInstance(1)); 393 } 394 testMultibinderSetForbidsDuplicateElements()395 public void testMultibinderSetForbidsDuplicateElements() { 396 Module module1 = 397 new AbstractModule() { 398 @Override 399 protected void configure() { 400 final Multibinder<String> multibinder = 401 Multibinder.newSetBinder(binder(), String.class); 402 multibinder.addBinding().toProvider(Providers.of("A")); 403 } 404 }; 405 Module module2 = 406 new AbstractModule() { 407 @Override 408 protected void configure() { 409 final Multibinder<String> multibinder = 410 Multibinder.newSetBinder(binder(), String.class); 411 multibinder.addBinding().toInstance("A"); 412 } 413 }; 414 Injector injector = Guice.createInjector(module1, module2); 415 416 try { 417 injector.getInstance(Key.get(setOfString)); 418 fail(); 419 } catch (ProvisionException expected) { 420 assertContains( 421 expected.getMessage(), 422 "1) Set injection failed due to duplicated element \"A\"", 423 "Bound at " + module1.getClass().getName(), 424 "Bound at " + module2.getClass().getName()); 425 } 426 427 // But we can still visit the module! 428 assertSetVisitor( 429 Key.get(setOfString), 430 stringType, 431 setOf(module1, module2), 432 MODULE, 433 false, 434 0, 435 instance("A"), 436 instance("A")); 437 } 438 testMultibinderSetShowsBothElementsIfToStringDifferent()439 public void testMultibinderSetShowsBothElementsIfToStringDifferent() { 440 // A simple example of a type whose toString returns more information than its equals method 441 // considers. 442 class ValueType { 443 int a; 444 int b; 445 446 ValueType(int a, int b) { 447 this.a = a; 448 this.b = b; 449 } 450 451 @Override 452 public boolean equals(Object obj) { 453 return (obj instanceof ValueType) && (((ValueType) obj).a == a); 454 } 455 456 @Override 457 public int hashCode() { 458 return a; 459 } 460 461 @Override 462 public String toString() { 463 return String.format("ValueType(%d,%d)", a, b); 464 } 465 } 466 467 Module module1 = 468 new AbstractModule() { 469 @Override 470 protected void configure() { 471 final Multibinder<ValueType> multibinder = 472 Multibinder.newSetBinder(binder(), ValueType.class); 473 multibinder.addBinding().toProvider(Providers.of(new ValueType(1, 2))); 474 } 475 }; 476 Module module2 = 477 new AbstractModule() { 478 @Override 479 protected void configure() { 480 final Multibinder<ValueType> multibinder = 481 Multibinder.newSetBinder(binder(), ValueType.class); 482 multibinder.addBinding().toInstance(new ValueType(1, 3)); 483 } 484 }; 485 Injector injector = Guice.createInjector(module1, module2); 486 487 TypeLiteral<ValueType> valueType = TypeLiteral.get(ValueType.class); 488 TypeLiteral<Set<ValueType>> setOfValueType = new TypeLiteral<Set<ValueType>>() {}; 489 try { 490 injector.getInstance(Key.get(setOfValueType)); 491 fail(); 492 } catch (ProvisionException expected) { 493 assertContains( 494 expected.getMessage(), 495 "1) Set injection failed due to multiple elements comparing equal:", 496 "\"ValueType(1,2)\"", 497 "bound at " + module1.getClass().getName(), 498 "\"ValueType(1,3)\"", 499 "bound at " + module2.getClass().getName()); 500 } 501 502 // But we can still visit the module! 503 assertSetVisitor( 504 Key.get(setOfValueType), 505 valueType, 506 setOf(module1, module2), 507 MODULE, 508 false, 509 0, 510 instance(new ValueType(1, 2)), 511 instance(new ValueType(1, 3))); 512 } 513 testMultibinderSetPermitDuplicateElements()514 public void testMultibinderSetPermitDuplicateElements() { 515 Module ab = 516 new AbstractModule() { 517 @Override 518 protected void configure() { 519 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 520 multibinder.addBinding().toInstance("A"); 521 multibinder.addBinding().toInstance("B"); 522 } 523 }; 524 Module bc = 525 new AbstractModule() { 526 @Override 527 protected void configure() { 528 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 529 multibinder.permitDuplicates(); 530 multibinder.addBinding().toInstance("B"); 531 multibinder.addBinding().toInstance("C"); 532 } 533 }; 534 Injector injector = Guice.createInjector(ab, bc); 535 536 assertEquals(setOf("A", "B", "C"), injector.getInstance(Key.get(setOfString))); 537 assertSetVisitor( 538 Key.get(setOfString), 539 stringType, 540 setOf(ab, bc), 541 BOTH, 542 true, 543 0, 544 instance("A"), 545 instance("B"), 546 instance("C")); 547 } 548 testMultibinderSetPermitDuplicateElementsFromOtherModule()549 public void testMultibinderSetPermitDuplicateElementsFromOtherModule() { 550 // This module duplicates a binding for "B", which would normally be an error. 551 // Because module cd is also installed and the Multibinder<String> 552 // in cd sets permitDuplicates, there should be no error. 553 Module ab = 554 new AbstractModule() { 555 @Override 556 protected void configure() { 557 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 558 multibinder.addBinding().toInstance("A"); 559 multibinder.addBinding().toInstance("B"); 560 multibinder.addBinding().toProvider(Providers.of("B")); 561 } 562 }; 563 Module cd = 564 new AbstractModule() { 565 @Override 566 protected void configure() { 567 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 568 multibinder.permitDuplicates(); 569 multibinder.addBinding().toInstance("C"); 570 multibinder.addBinding().toInstance("D"); 571 } 572 }; 573 Injector injector = Guice.createInjector(ab, cd); 574 575 assertEquals(setOf("A", "B", "C", "D"), injector.getInstance(Key.get(setOfString))); 576 assertSetVisitor( 577 Key.get(setOfString), 578 stringType, 579 setOf(ab, cd), 580 BOTH, 581 true, 582 0, 583 instance("A"), 584 instance("B"), 585 providerInstance("B"), 586 instance("C"), 587 instance("D")); 588 } 589 testMultibinderSetPermitDuplicateCallsToPermitDuplicates()590 public void testMultibinderSetPermitDuplicateCallsToPermitDuplicates() { 591 Module ab = 592 new AbstractModule() { 593 @Override 594 protected void configure() { 595 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 596 multibinder.permitDuplicates(); 597 multibinder.addBinding().toInstance("A"); 598 multibinder.addBinding().toInstance("B"); 599 } 600 }; 601 Module bc = 602 new AbstractModule() { 603 @Override 604 protected void configure() { 605 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 606 multibinder.permitDuplicates(); 607 multibinder.addBinding().toInstance("B"); 608 multibinder.addBinding().toInstance("C"); 609 } 610 }; 611 Injector injector = Guice.createInjector(ab, bc); 612 613 assertEquals(setOf("A", "B", "C"), injector.getInstance(Key.get(setOfString))); 614 assertSetVisitor( 615 Key.get(setOfString), 616 stringType, 617 setOf(ab, bc), 618 BOTH, 619 true, 620 0, 621 instance("A"), 622 instance("B"), 623 instance("C")); 624 } 625 testMultibinderSetForbidsNullElements()626 public void testMultibinderSetForbidsNullElements() { 627 Module m = 628 new AbstractModule() { 629 @Override 630 protected void configure() { 631 Multibinder.newSetBinder(binder(), String.class) 632 .addBinding() 633 .toProvider(Providers.<String>of(null)); 634 } 635 }; 636 Injector injector = Guice.createInjector(m); 637 638 try { 639 injector.getInstance(Key.get(setOfString)); 640 fail(); 641 } catch (ProvisionException expected) { 642 assertContains( 643 expected.getMessage(), 644 "1) Set injection failed due to null element bound at: " 645 + m.getClass().getName() 646 + ".configure("); 647 } 648 } 649 testSourceLinesInMultibindings()650 public void testSourceLinesInMultibindings() { 651 try { 652 Guice.createInjector( 653 new AbstractModule() { 654 @Override 655 protected void configure() { 656 Multibinder.newSetBinder(binder(), Integer.class).addBinding(); 657 } 658 }); 659 fail(); 660 } catch (CreationException expected) { 661 assertContains( 662 expected.getMessage(), 663 true, 664 "No implementation for java.lang.Integer", 665 "at " + getClass().getName()); 666 } 667 } 668 669 /** 670 * We just want to make sure that multibinder's binding depends on each of its values. We don't 671 * really care about the underlying structure of those bindings, which are implementation details. 672 */ testMultibinderDependencies()673 public void testMultibinderDependencies() { 674 Injector injector = 675 Guice.createInjector( 676 new AbstractModule() { 677 @Override 678 protected void configure() { 679 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 680 multibinder.addBinding().toInstance("A"); 681 multibinder.addBinding().to(Key.get(String.class, Names.named("b"))); 682 683 bindConstant().annotatedWith(Names.named("b")).to("B"); 684 } 685 }); 686 687 Binding<Set<String>> binding = injector.getBinding(new Key<Set<String>>() {}); 688 HasDependencies withDependencies = (HasDependencies) binding; 689 Set<String> elements = Sets.newHashSet(); 690 for (Dependency<?> dependency : withDependencies.getDependencies()) { 691 elements.add((String) injector.getInstance(dependency.getKey())); 692 } 693 assertEquals(ImmutableSet.of("A", "B"), elements); 694 } 695 696 /** 697 * We just want to make sure that multibinder's binding depends on each of its values. We don't 698 * really care about the underlying structure of those bindings, which are implementation details. 699 */ testMultibinderDependenciesInToolStage()700 public void testMultibinderDependenciesInToolStage() { 701 Injector injector = 702 Guice.createInjector( 703 Stage.TOOL, 704 new AbstractModule() { 705 @Override 706 protected void configure() { 707 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 708 multibinder.addBinding().toInstance("A"); 709 multibinder.addBinding().to(Key.get(String.class, Names.named("b"))); 710 711 bindConstant().annotatedWith(Names.named("b")).to("B"); 712 } 713 }); 714 715 Binding<Set<String>> binding = injector.getBinding(new Key<Set<String>>() {}); 716 HasDependencies withDependencies = (HasDependencies) binding; 717 InstanceBinding<?> instanceBinding = null; 718 LinkedKeyBinding<?> linkedBinding = null; 719 // The non-tool stage test can test this by calling injector.getInstance to ensure 720 // the right values are returned -- in tool stage we can't do that. It's also a 721 // little difficult to validate the dependencies & bindings, because they're 722 // bindings created internally within Multibinder. 723 // To workaround this, we just validate that the dependencies lookup to a single 724 // InstanceBinding whose value is "A" and another LinkedBinding whose target is 725 // the Key of @Named("b") String=B 726 for (Dependency<?> dependency : withDependencies.getDependencies()) { 727 Binding<?> b = injector.getBinding(dependency.getKey()); 728 if (b instanceof InstanceBinding) { 729 if (instanceBinding != null) { 730 fail( 731 "Already have an instance binding of: " 732 + instanceBinding 733 + ", and now want to add: " 734 + b); 735 } else { 736 instanceBinding = (InstanceBinding) b; 737 } 738 } else if (b instanceof LinkedKeyBinding) { 739 if (linkedBinding != null) { 740 fail( 741 "Already have a linked binding of: " + linkedBinding + ", and now want to add: " + b); 742 } else { 743 linkedBinding = (LinkedKeyBinding) b; 744 } 745 } else { 746 fail("Unexpected dependency of: " + dependency); 747 } 748 } 749 750 assertNotNull(instanceBinding); 751 assertNotNull(linkedBinding); 752 753 assertEquals("A", instanceBinding.getInstance()); 754 assertEquals(Key.get(String.class, Names.named("b")), linkedBinding.getLinkedKey()); 755 } 756 757 /** 758 * Our implementation maintains order, but doesn't guarantee it in the API spec. TODO: specify the 759 * iteration order? 760 */ testBindOrderEqualsIterationOrder()761 public void testBindOrderEqualsIterationOrder() { 762 Injector injector = 763 Guice.createInjector( 764 new AbstractModule() { 765 @Override 766 protected void configure() { 767 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 768 multibinder.addBinding().toInstance("leonardo"); 769 multibinder.addBinding().toInstance("donatello"); 770 install( 771 new AbstractModule() { 772 @Override 773 protected void configure() { 774 Multibinder.newSetBinder(binder(), String.class) 775 .addBinding() 776 .toInstance("michaelangelo"); 777 } 778 }); 779 } 780 }, 781 new AbstractModule() { 782 @Override 783 protected void configure() { 784 Multibinder.newSetBinder(binder(), String.class).addBinding().toInstance("raphael"); 785 } 786 }); 787 788 List<String> inOrder = ImmutableList.copyOf(injector.getInstance(Key.get(setOfString))); 789 assertEquals(ImmutableList.of("leonardo", "donatello", "michaelangelo", "raphael"), inOrder); 790 } 791 792 @Retention(RUNTIME) 793 @BindingAnnotation 794 @interface Abc {} 795 796 @Retention(RUNTIME) 797 @BindingAnnotation 798 @interface De {} 799 setOf(T... elements)800 private <T> Set<T> setOf(T... elements) { 801 Set<T> result = Sets.newHashSet(); 802 Collections.addAll(result, elements); 803 return result; 804 } 805 806 /** With overrides, we should get the union of all multibindings. */ testModuleOverrideAndMultibindings()807 public void testModuleOverrideAndMultibindings() { 808 Module ab = 809 new AbstractModule() { 810 @Override 811 protected void configure() { 812 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 813 multibinder.addBinding().toInstance("A"); 814 multibinder.addBinding().toInstance("B"); 815 } 816 }; 817 Module cd = 818 new AbstractModule() { 819 @Override 820 protected void configure() { 821 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 822 multibinder.addBinding().toInstance("C"); 823 multibinder.addBinding().toInstance("D"); 824 } 825 }; 826 Module ef = 827 new AbstractModule() { 828 @Override 829 protected void configure() { 830 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 831 multibinder.addBinding().toInstance("E"); 832 multibinder.addBinding().toInstance("F"); 833 } 834 }; 835 836 Module abcd = Modules.override(ab).with(cd); 837 Injector injector = Guice.createInjector(abcd, ef); 838 assertEquals( 839 ImmutableSet.of("A", "B", "C", "D", "E", "F"), injector.getInstance(Key.get(setOfString))); 840 841 assertSetVisitor( 842 Key.get(setOfString), 843 stringType, 844 setOf(abcd, ef), 845 BOTH, 846 false, 847 0, 848 instance("A"), 849 instance("B"), 850 instance("C"), 851 instance("D"), 852 instance("E"), 853 instance("F")); 854 } 855 856 /** With overrides, we should get the union of all multibindings. */ testModuleOverrideAndMultibindingsWithPermitDuplicates()857 public void testModuleOverrideAndMultibindingsWithPermitDuplicates() { 858 Module abc = 859 new AbstractModule() { 860 @Override 861 protected void configure() { 862 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 863 multibinder.addBinding().toInstance("A"); 864 multibinder.addBinding().toInstance("B"); 865 multibinder.addBinding().toInstance("C"); 866 multibinder.permitDuplicates(); 867 } 868 }; 869 Module cd = 870 new AbstractModule() { 871 @Override 872 protected void configure() { 873 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 874 multibinder.addBinding().toInstance("C"); 875 multibinder.addBinding().toInstance("D"); 876 multibinder.permitDuplicates(); 877 } 878 }; 879 Module ef = 880 new AbstractModule() { 881 @Override 882 protected void configure() { 883 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 884 multibinder.addBinding().toInstance("E"); 885 multibinder.addBinding().toInstance("F"); 886 multibinder.permitDuplicates(); 887 } 888 }; 889 890 Module abcd = Modules.override(abc).with(cd); 891 Injector injector = Guice.createInjector(abcd, ef); 892 assertEquals( 893 ImmutableSet.of("A", "B", "C", "D", "E", "F"), injector.getInstance(Key.get(setOfString))); 894 895 assertSetVisitor( 896 Key.get(setOfString), 897 stringType, 898 setOf(abcd, ef), 899 BOTH, 900 true, 901 0, 902 instance("A"), 903 instance("B"), 904 instance("C"), 905 instance("D"), 906 instance("E"), 907 instance("F")); 908 } 909 910 /** Doubly-installed modules should not conflict, even when one is overridden. */ testModuleOverrideRepeatedInstallsAndMultibindings_toInstance()911 public void testModuleOverrideRepeatedInstallsAndMultibindings_toInstance() { 912 Module ab = 913 new AbstractModule() { 914 @Override 915 protected void configure() { 916 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 917 multibinder.addBinding().toInstance("A"); 918 multibinder.addBinding().toInstance("B"); 919 } 920 }; 921 922 // Guice guarantees this assertion, as the same module cannot be installed twice. 923 assertEquals( 924 ImmutableSet.of("A", "B"), Guice.createInjector(ab, ab).getInstance(Key.get(setOfString))); 925 926 // Guice will only guarantee this assertion if Multibinder ensures the bindings match. 927 Injector injector = Guice.createInjector(ab, Modules.override(ab).with(ab)); 928 assertEquals(ImmutableSet.of("A", "B"), injector.getInstance(Key.get(setOfString))); 929 } 930 testModuleOverrideRepeatedInstallsAndMultibindings_toKey()931 public void testModuleOverrideRepeatedInstallsAndMultibindings_toKey() { 932 Module ab = 933 new AbstractModule() { 934 @Override 935 protected void configure() { 936 Key<String> aKey = Key.get(String.class, Names.named("A_string")); 937 Key<String> bKey = Key.get(String.class, Names.named("B_string")); 938 bind(aKey).toInstance("A"); 939 bind(bKey).toInstance("B"); 940 941 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 942 multibinder.addBinding().to(aKey); 943 multibinder.addBinding().to(bKey); 944 } 945 }; 946 947 // Guice guarantees this assertion, as the same module cannot be installed twice. 948 assertEquals( 949 ImmutableSet.of("A", "B"), Guice.createInjector(ab, ab).getInstance(Key.get(setOfString))); 950 951 // Guice will only guarantee this assertion if Multibinder ensures the bindings match. 952 Injector injector = Guice.createInjector(ab, Modules.override(ab).with(ab)); 953 assertEquals(ImmutableSet.of("A", "B"), injector.getInstance(Key.get(setOfString))); 954 } 955 testModuleOverrideRepeatedInstallsAndMultibindings_toProviderInstance()956 public void testModuleOverrideRepeatedInstallsAndMultibindings_toProviderInstance() { 957 Module ab = 958 new AbstractModule() { 959 @Override 960 protected void configure() { 961 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 962 multibinder.addBinding().toProvider(Providers.of("A")); 963 multibinder.addBinding().toProvider(Providers.of("B")); 964 } 965 }; 966 967 // Guice guarantees this assertion, as the same module cannot be installed twice. 968 assertEquals( 969 ImmutableSet.of("A", "B"), Guice.createInjector(ab, ab).getInstance(Key.get(setOfString))); 970 971 // Guice will only guarantee this assertion if Multibinder ensures the bindings match. 972 Injector injector = Guice.createInjector(ab, Modules.override(ab).with(ab)); 973 assertEquals(ImmutableSet.of("A", "B"), injector.getInstance(Key.get(setOfString))); 974 } 975 976 private static class AStringProvider implements Provider<String> { 977 @Override get()978 public String get() { 979 return "A"; 980 } 981 } 982 983 private static class BStringProvider implements Provider<String> { 984 @Override get()985 public String get() { 986 return "B"; 987 } 988 } 989 testModuleOverrideRepeatedInstallsAndMultibindings_toProviderKey()990 public void testModuleOverrideRepeatedInstallsAndMultibindings_toProviderKey() { 991 Module ab = 992 new AbstractModule() { 993 @Override 994 protected void configure() { 995 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); 996 multibinder.addBinding().toProvider(Key.get(AStringProvider.class)); 997 multibinder.addBinding().toProvider(Key.get(BStringProvider.class)); 998 } 999 }; 1000 1001 // Guice guarantees this assertion, as the same module cannot be installed twice. 1002 assertEquals( 1003 ImmutableSet.of("A", "B"), Guice.createInjector(ab, ab).getInstance(Key.get(setOfString))); 1004 1005 // Guice will only guarantee this assertion if Multibinder ensures the bindings match. 1006 Injector injector = Guice.createInjector(ab, Modules.override(ab).with(ab)); 1007 assertEquals(ImmutableSet.of("A", "B"), injector.getInstance(Key.get(setOfString))); 1008 } 1009 1010 private static class StringGrabber { 1011 private final String string; 1012 1013 @SuppressWarnings("unused") // Found by reflection StringGrabber(@amed"A_string") String string)1014 public StringGrabber(@Named("A_string") String string) { 1015 this.string = string; 1016 } 1017 1018 @SuppressWarnings("unused") // Found by reflection StringGrabber(@amed"B_string") String string, int unused)1019 public StringGrabber(@Named("B_string") String string, int unused) { 1020 this.string = string; 1021 } 1022 1023 @Override hashCode()1024 public int hashCode() { 1025 return string.hashCode(); 1026 } 1027 1028 @Override equals(Object obj)1029 public boolean equals(Object obj) { 1030 return (obj instanceof StringGrabber) && ((StringGrabber) obj).string.equals(string); 1031 } 1032 1033 @Override toString()1034 public String toString() { 1035 return "StringGrabber(" + string + ")"; 1036 } 1037 values(Iterable<StringGrabber> grabbers)1038 static Set<String> values(Iterable<StringGrabber> grabbers) { 1039 Set<String> result = new HashSet<>(); 1040 for (StringGrabber grabber : grabbers) { 1041 result.add(grabber.string); 1042 } 1043 return result; 1044 } 1045 } 1046 testModuleOverrideRepeatedInstallsAndMultibindings_toConstructor()1047 public void testModuleOverrideRepeatedInstallsAndMultibindings_toConstructor() { 1048 TypeLiteral<Set<StringGrabber>> setOfStringGrabber = new TypeLiteral<Set<StringGrabber>>() {}; 1049 Module ab = 1050 new AbstractModule() { 1051 @Override 1052 protected void configure() { 1053 Key<String> aKey = Key.get(String.class, Names.named("A_string")); 1054 Key<String> bKey = Key.get(String.class, Names.named("B_string")); 1055 bind(aKey).toInstance("A"); 1056 bind(bKey).toInstance("B"); 1057 bind(Integer.class).toInstance(0); // used to disambiguate constructors 1058 1059 Multibinder<StringGrabber> multibinder = 1060 Multibinder.newSetBinder(binder(), StringGrabber.class); 1061 try { 1062 multibinder 1063 .addBinding() 1064 .toConstructor(StringGrabber.class.getConstructor(String.class)); 1065 multibinder 1066 .addBinding() 1067 .toConstructor(StringGrabber.class.getConstructor(String.class, int.class)); 1068 } catch (NoSuchMethodException e) { 1069 fail("No such method: " + e.getMessage()); 1070 } 1071 } 1072 }; 1073 1074 // Guice guarantees this assertion, as the same module cannot be installed twice. 1075 assertEquals( 1076 ImmutableSet.of("A", "B"), 1077 StringGrabber.values( 1078 Guice.createInjector(ab, ab).getInstance(Key.get(setOfStringGrabber)))); 1079 1080 // Guice will only guarantee this assertion if Multibinder ensures the bindings match. 1081 Injector injector = Guice.createInjector(ab, Modules.override(ab).with(ab)); 1082 assertEquals( 1083 ImmutableSet.of("A", "B"), 1084 StringGrabber.values(injector.getInstance(Key.get(setOfStringGrabber)))); 1085 } 1086 1087 /** 1088 * Unscoped bindings should not conflict, whether they were bound with no explicit scope, or 1089 * explicitly bound in {@link Scopes#NO_SCOPE}. 1090 */ testDuplicateUnscopedBindings()1091 public void testDuplicateUnscopedBindings() { 1092 Module singleBinding = 1093 new AbstractModule() { 1094 @Override 1095 protected void configure() { 1096 bind(Integer.class).to(Key.get(Integer.class, named("A"))); 1097 bind(Integer.class).to(Key.get(Integer.class, named("A"))).in(Scopes.NO_SCOPE); 1098 } 1099 1100 @Provides 1101 @Named("A") 1102 int provideInteger() { 1103 return 5; 1104 } 1105 }; 1106 Module multibinding = 1107 new AbstractModule() { 1108 @Override 1109 protected void configure() { 1110 Multibinder<Integer> multibinder = Multibinder.newSetBinder(binder(), Integer.class); 1111 multibinder.addBinding().to(Key.get(Integer.class, named("A"))); 1112 multibinder.addBinding().to(Key.get(Integer.class, named("A"))).in(Scopes.NO_SCOPE); 1113 } 1114 }; 1115 1116 assertEquals(5, (int) Guice.createInjector(singleBinding).getInstance(Integer.class)); 1117 assertEquals( 1118 ImmutableSet.of(5), 1119 Guice.createInjector(singleBinding, multibinding).getInstance(Key.get(setOfInteger))); 1120 } 1121 1122 /** Ensure key hash codes are fixed at injection time, not binding time. */ testKeyHashCodesFixedAtInjectionTime()1123 public void testKeyHashCodesFixedAtInjectionTime() { 1124 Module ab = 1125 new AbstractModule() { 1126 @Override 1127 protected void configure() { 1128 Multibinder<List<String>> multibinder = 1129 Multibinder.newSetBinder(binder(), listOfStrings); 1130 List<String> list = Lists.newArrayList(); 1131 multibinder.addBinding().toInstance(list); 1132 list.add("A"); 1133 list.add("B"); 1134 } 1135 }; 1136 1137 Injector injector = Guice.createInjector(ab); 1138 for (Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) { 1139 Key<?> bindingKey = entry.getKey(); 1140 Key<?> clonedKey; 1141 if (bindingKey.getAnnotation() != null) { 1142 clonedKey = Key.get(bindingKey.getTypeLiteral(), bindingKey.getAnnotation()); 1143 } else if (bindingKey.getAnnotationType() != null) { 1144 clonedKey = Key.get(bindingKey.getTypeLiteral(), bindingKey.getAnnotationType()); 1145 } else { 1146 clonedKey = Key.get(bindingKey.getTypeLiteral()); 1147 } 1148 assertEquals(bindingKey, clonedKey); 1149 assertEquals( 1150 "Incorrect hashcode for " + bindingKey + " -> " + entry.getValue(), 1151 bindingKey.hashCode(), 1152 clonedKey.hashCode()); 1153 } 1154 } 1155 1156 /** Ensure bindings do not rehash their keys once returned from {@link Elements#getElements}. */ testBindingKeysFixedOnReturnFromGetElements()1157 public void testBindingKeysFixedOnReturnFromGetElements() { 1158 final List<String> list = Lists.newArrayList(); 1159 Module ab = 1160 new AbstractModule() { 1161 @Override 1162 protected void configure() { 1163 Multibinder<List<String>> multibinder = 1164 Multibinder.newSetBinder(binder(), listOfStrings); 1165 multibinder.addBinding().toInstance(list); 1166 list.add("A"); 1167 list.add("B"); 1168 } 1169 }; 1170 1171 InstanceBinding<?> binding = 1172 Iterables.getOnlyElement(Iterables.filter(Elements.getElements(ab), InstanceBinding.class)); 1173 Key<?> keyBefore = binding.getKey(); 1174 assertEquals(listOfStrings, keyBefore.getTypeLiteral()); 1175 1176 list.add("C"); 1177 Key<?> keyAfter = binding.getKey(); 1178 assertSame(keyBefore, keyAfter); 1179 } 1180 1181 /* 1182 * Verify through gratuitous mutation that key hashCode snapshots and whatnot happens at the right 1183 * times, by binding two lists that are different at injector creation, but compare equal when the 1184 * module is configured *and* when the set is instantiated. 1185 */ testConcurrentMutation_bindingsDiffentAtInjectorCreation()1186 public void testConcurrentMutation_bindingsDiffentAtInjectorCreation() { 1187 // We initially bind two equal lists 1188 final List<String> list1 = Lists.newArrayList(); 1189 final List<String> list2 = Lists.newArrayList(); 1190 Module module = 1191 new AbstractModule() { 1192 @Override 1193 protected void configure() { 1194 Multibinder<List<String>> multibinder = 1195 Multibinder.newSetBinder(binder(), listOfStrings); 1196 multibinder.addBinding().toInstance(list1); 1197 multibinder.addBinding().toInstance(list2); 1198 } 1199 }; 1200 List<Element> elements = Elements.getElements(module); 1201 1202 // Now we change the lists so they no longer match, and create the injector. 1203 list1.add("A"); 1204 list2.add("B"); 1205 Injector injector = Guice.createInjector(Elements.getModule(elements)); 1206 1207 // Now we change the lists so they compare equal again, and create the set. 1208 list1.add(1, "B"); 1209 list2.add(0, "A"); 1210 try { 1211 injector.getInstance(Key.get(setOfListOfStrings)); 1212 fail(); 1213 } catch (ProvisionException e) { 1214 assertEquals(1, e.getErrorMessages().size()); 1215 assertContains( 1216 Iterables.getOnlyElement(e.getErrorMessages()).getMessage().toString(), 1217 "Set injection failed due to duplicated element \"[A, B]\""); 1218 } 1219 1220 // Finally, we change the lists again so they are once more different, and ensure the set 1221 // contains both. 1222 list1.remove("A"); 1223 list2.remove("B"); 1224 Set<List<String>> set = injector.getInstance(Key.get(setOfListOfStrings)); 1225 assertEquals(ImmutableSet.of(ImmutableList.of("A"), ImmutableList.of("B")), set); 1226 } 1227 1228 /* 1229 * Verify through gratuitous mutation that key hashCode snapshots and whatnot happen at the right 1230 * times, by binding two lists that compare equal at injector creation, but are different when the 1231 * module is configured *and* when the set is instantiated. 1232 */ testConcurrentMutation_bindingsSameAtInjectorCreation()1233 public void testConcurrentMutation_bindingsSameAtInjectorCreation() { 1234 // We initially bind two distinct lists 1235 final List<String> list1 = Lists.newArrayList("A"); 1236 final List<String> list2 = Lists.newArrayList("B"); 1237 Module module = 1238 new AbstractModule() { 1239 @Override 1240 protected void configure() { 1241 Multibinder<List<String>> multibinder = 1242 Multibinder.newSetBinder(binder(), listOfStrings); 1243 multibinder.addBinding().toInstance(list1); 1244 multibinder.addBinding().toInstance(list2); 1245 } 1246 }; 1247 List<Element> elements = Elements.getElements(module); 1248 1249 // Now we change the lists so they compare equal, and create the injector. 1250 list1.add(1, "B"); 1251 list2.add(0, "A"); 1252 Injector injector = Guice.createInjector(Elements.getModule(elements)); 1253 1254 // Now we change the lists again so they are once more different, and create the set. 1255 list1.remove("A"); 1256 list2.remove("B"); 1257 Set<List<String>> set = injector.getInstance(Key.get(setOfListOfStrings)); 1258 1259 // The set will contain just one of the two lists. 1260 // (In fact, it will be the first one we bound, but we don't promise that, so we won't test it.) 1261 assertTrue( 1262 ImmutableSet.of(ImmutableList.of("A")).equals(set) 1263 || ImmutableSet.of(ImmutableList.of("B")).equals(set)); 1264 } 1265 1266 @BindingAnnotation 1267 @Retention(RetentionPolicy.RUNTIME) 1268 @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) 1269 private static @interface Marker {} 1270 1271 @Marker testMultibinderMatching()1272 public void testMultibinderMatching() throws Exception { 1273 Method m = MultibinderTest.class.getDeclaredMethod("testMultibinderMatching"); 1274 assertNotNull(m); 1275 final Annotation marker = m.getAnnotation(Marker.class); 1276 Injector injector = 1277 Guice.createInjector( 1278 new AbstractModule() { 1279 @Override 1280 public void configure() { 1281 Multibinder<Integer> mb1 = 1282 Multibinder.newSetBinder(binder(), Integer.class, Marker.class); 1283 Multibinder<Integer> mb2 = 1284 Multibinder.newSetBinder(binder(), Integer.class, marker); 1285 mb1.addBinding().toInstance(1); 1286 mb2.addBinding().toInstance(2); 1287 1288 // This assures us that the two binders are equivalent, so we expect the instance added to 1289 // each to have been added to one set. 1290 assertEquals(mb1, mb2); 1291 } 1292 }); 1293 TypeLiteral<Set<Integer>> t = new TypeLiteral<Set<Integer>>() {}; 1294 Set<Integer> s1 = injector.getInstance(Key.get(t, Marker.class)); 1295 Set<Integer> s2 = injector.getInstance(Key.get(t, marker)); 1296 1297 // This assures us that the two sets are in fact equal. They may not be same set (as in Java 1298 // object identical), but we shouldn't expect that, since probably Guice creates the set each 1299 // time in case the elements are dependent on scope. 1300 assertEquals(s1, s2); 1301 1302 // This ensures that MultiBinder is internally using the correct set name -- 1303 // making sure that instances of marker annotations have the same set name as 1304 // MarkerAnnotation.class. 1305 Set<Integer> expected = new HashSet<>(); 1306 expected.add(1); 1307 expected.add(2); 1308 assertEquals(expected, s1); 1309 } 1310 1311 // See issue 670 testSetAndMapValueAreDistinct()1312 public void testSetAndMapValueAreDistinct() { 1313 Injector injector = 1314 Guice.createInjector( 1315 new AbstractModule() { 1316 @Override 1317 protected void configure() { 1318 Multibinder.newSetBinder(binder(), String.class).addBinding().toInstance("A"); 1319 1320 MapBinder.newMapBinder(binder(), String.class, String.class) 1321 .addBinding("B") 1322 .toInstance("b"); 1323 1324 OptionalBinder.newOptionalBinder(binder(), String.class) 1325 .setDefault() 1326 .toInstance("C"); 1327 OptionalBinder.newOptionalBinder(binder(), String.class) 1328 .setBinding() 1329 .toInstance("D"); 1330 } 1331 }); 1332 1333 assertEquals(ImmutableSet.of("A"), injector.getInstance(Key.get(setOfString))); 1334 assertEquals(ImmutableMap.of("B", "b"), injector.getInstance(Key.get(mapOfStringString))); 1335 assertEquals(Optional.of("D"), injector.getInstance(Key.get(optionalOfString))); 1336 } 1337 1338 // See issue 670 testSetAndMapValueAreDistinctInSpi()1339 public void testSetAndMapValueAreDistinctInSpi() { 1340 Injector injector = 1341 Guice.createInjector( 1342 new AbstractModule() { 1343 @Override 1344 protected void configure() { 1345 Multibinder.newSetBinder(binder(), String.class).addBinding().toInstance("A"); 1346 1347 MapBinder.newMapBinder(binder(), String.class, String.class) 1348 .addBinding("B") 1349 .toInstance("b"); 1350 1351 OptionalBinder.newOptionalBinder(binder(), String.class) 1352 .setDefault() 1353 .toInstance("C"); 1354 } 1355 }); 1356 Collector collector = new Collector(); 1357 Binding<Map<String, String>> mapbinding = injector.getBinding(Key.get(mapOfStringString)); 1358 mapbinding.acceptTargetVisitor(collector); 1359 assertNotNull(collector.mapbinding); 1360 1361 Binding<Set<String>> setbinding = injector.getBinding(Key.get(setOfString)); 1362 setbinding.acceptTargetVisitor(collector); 1363 assertNotNull(collector.setbinding); 1364 1365 Binding<Optional<String>> optionalbinding = injector.getBinding(Key.get(optionalOfString)); 1366 optionalbinding.acceptTargetVisitor(collector); 1367 assertNotNull(collector.optionalbinding); 1368 1369 // There should only be three instance bindings for string types 1370 // (but because of the OptionalBinder, there's 2 ProviderInstanceBindings also). 1371 // We also know the InstanceBindings will be in the order: A, b, C because that's 1372 // how we bound them, and binding order is preserved. 1373 List<Binding<String>> bindings = 1374 FluentIterable.from(injector.findBindingsByType(stringType)) 1375 .filter(Predicates.instanceOf(InstanceBinding.class)) 1376 .toList(); 1377 assertEquals(bindings.toString(), 3, bindings.size()); 1378 Binding<String> a = bindings.get(0); 1379 Binding<String> b = bindings.get(1); 1380 Binding<String> c = bindings.get(2); 1381 assertEquals("A", ((InstanceBinding<String>) a).getInstance()); 1382 assertEquals("b", ((InstanceBinding<String>) b).getInstance()); 1383 assertEquals("C", ((InstanceBinding<String>) c).getInstance()); 1384 1385 // Make sure the correct elements belong to their own sets. 1386 assertFalse(collector.mapbinding.containsElement(a)); 1387 assertTrue(collector.mapbinding.containsElement(b)); 1388 assertFalse(collector.mapbinding.containsElement(c)); 1389 1390 assertTrue(collector.setbinding.containsElement(a)); 1391 assertFalse(collector.setbinding.containsElement(b)); 1392 assertFalse(collector.setbinding.containsElement(c)); 1393 1394 assertFalse(collector.optionalbinding.containsElement(a)); 1395 assertFalse(collector.optionalbinding.containsElement(b)); 1396 assertTrue(collector.optionalbinding.containsElement(c)); 1397 } 1398 testMultibinderCanInjectCollectionOfProviders()1399 public void testMultibinderCanInjectCollectionOfProviders() { 1400 Module module = 1401 new AbstractModule() { 1402 @Override 1403 protected void configure() { 1404 final Multibinder<String> multibinder = 1405 Multibinder.newSetBinder(binder(), String.class); 1406 multibinder.addBinding().toProvider(Providers.of("A")); 1407 multibinder.addBinding().toProvider(Providers.of("B")); 1408 multibinder.addBinding().toInstance("C"); 1409 } 1410 }; 1411 Collection<String> expectedValues = ImmutableList.of("A", "B", "C"); 1412 1413 Injector injector = Guice.createInjector(module); 1414 1415 Collection<Provider<String>> providers = 1416 injector.getInstance(Key.get(collectionOfProvidersOfStrings)); 1417 assertEquals(expectedValues, collectValues(providers)); 1418 1419 Collection<javax.inject.Provider<String>> javaxProviders = 1420 injector.getInstance(Key.get(collectionOfJavaxProvidersOf(stringType))); 1421 assertEquals(expectedValues, collectValues(javaxProviders)); 1422 } 1423 testMultibinderCanInjectCollectionOfProvidersWithAnnotation()1424 public void testMultibinderCanInjectCollectionOfProvidersWithAnnotation() { 1425 final Annotation ann = Names.named("foo"); 1426 Module module = 1427 new AbstractModule() { 1428 @Override 1429 protected void configure() { 1430 final Multibinder<String> multibinder = 1431 Multibinder.newSetBinder(binder(), String.class, ann); 1432 multibinder.addBinding().toProvider(Providers.of("A")); 1433 multibinder.addBinding().toProvider(Providers.of("B")); 1434 multibinder.addBinding().toInstance("C"); 1435 } 1436 }; 1437 Collection<String> expectedValues = ImmutableList.of("A", "B", "C"); 1438 1439 Injector injector = Guice.createInjector(module); 1440 1441 Collection<Provider<String>> providers = 1442 injector.getInstance(Key.get(collectionOfProvidersOfStrings, ann)); 1443 Collection<String> values = collectValues(providers); 1444 assertEquals(expectedValues, values); 1445 1446 Collection<javax.inject.Provider<String>> javaxProviders = 1447 injector.getInstance(Key.get(collectionOfJavaxProvidersOf(stringType), ann)); 1448 assertEquals(expectedValues, collectValues(javaxProviders)); 1449 } 1450 testMultibindingProviderDependencies()1451 public void testMultibindingProviderDependencies() { 1452 final Annotation setAnn = Names.named("foo"); 1453 Injector injector = 1454 Guice.createInjector( 1455 new AbstractModule() { 1456 @Override 1457 protected void configure() { 1458 Multibinder<String> multibinder = 1459 Multibinder.newSetBinder(binder(), String.class, setAnn); 1460 multibinder.addBinding().toInstance("a"); 1461 multibinder.addBinding().toInstance("b"); 1462 } 1463 }); 1464 HasDependencies providerBinding = 1465 (HasDependencies) injector.getBinding(new Key<Collection<Provider<String>>>(setAnn) {}); 1466 HasDependencies setBinding = 1467 (HasDependencies) injector.getBinding(new Key<Set<String>>(setAnn) {}); 1468 // sanity check the size 1469 assertEquals(setBinding.getDependencies().toString(), 2, setBinding.getDependencies().size()); 1470 Set<Dependency<?>> expected = Sets.newHashSet(); 1471 for (Dependency<?> dep : setBinding.getDependencies()) { 1472 Key key = dep.getKey(); 1473 Dependency<?> providerDependency = 1474 Dependency.get(key.ofType(Types.providerOf(key.getTypeLiteral().getType()))); 1475 expected.add(providerDependency); 1476 } 1477 assertEquals(expected, providerBinding.getDependencies()); 1478 } 1479 testEmptyMultibinder()1480 public void testEmptyMultibinder() { 1481 Injector injector = 1482 Guice.createInjector( 1483 new AbstractModule() { 1484 @Override 1485 protected void configure() { 1486 Multibinder.newSetBinder(binder(), String.class); 1487 } 1488 }); 1489 assertEquals(ImmutableSet.of(), injector.getInstance(new Key<Set<String>>() {})); 1490 assertEquals( 1491 ImmutableList.of(), injector.getInstance(new Key<Collection<Provider<String>>>() {})); 1492 } 1493 1494 private static final class ObjectWithInjectionPoint { 1495 boolean setterHasBeenCalled; 1496 1497 @Inject setter(String dummy)1498 void setter(String dummy) { 1499 setterHasBeenCalled = true; 1500 } 1501 } 1502 1503 // This tests for a behavior where InstanceBindingImpl.getProvider() would return uninitialized 1504 // instances if called during injector creation (depending on the order of injection requests). testMultibinderDependsOnInstanceBindingWithInjectionPoints()1505 public void testMultibinderDependsOnInstanceBindingWithInjectionPoints() { 1506 Guice.createInjector( 1507 new AbstractModule() { 1508 private Provider<Set<ObjectWithInjectionPoint>> provider; 1509 1510 @Override 1511 protected void configure() { 1512 bind(Object.class).toInstance(this); // force setter() to be injected first 1513 bind(String.class).toInstance("foo"); 1514 this.provider = getProvider(new Key<Set<ObjectWithInjectionPoint>>() {}); 1515 Multibinder.newSetBinder(binder(), ObjectWithInjectionPoint.class) 1516 .addBinding() 1517 .toInstance(new ObjectWithInjectionPoint()); 1518 } 1519 1520 @Inject 1521 void setter(String s) { 1522 for (ObjectWithInjectionPoint item : provider.get()) { 1523 assertTrue(item.setterHasBeenCalled); 1524 } 1525 } 1526 }); 1527 } 1528 collectValues( Collection<? extends javax.inject.Provider<T>> providers)1529 private <T> Collection<T> collectValues( 1530 Collection<? extends javax.inject.Provider<T>> providers) { 1531 Collection<T> values = Lists.newArrayList(); 1532 for (javax.inject.Provider<T> provider : providers) { 1533 values.add(provider.get()); 1534 } 1535 return values; 1536 } 1537 } 1538