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