1/** 2 * Copyright (C) 2010 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 17package com.google.inject.multibindings; 18 19import static com.google.inject.multibindings.MapBinder.entryOfProviderOf; 20import static com.google.inject.multibindings.MapBinder.mapOf; 21import static com.google.inject.multibindings.MapBinder.mapOfJavaxProviderOf; 22import static com.google.inject.multibindings.MapBinder.mapOfProviderOf; 23import static com.google.inject.multibindings.MapBinder.mapOfSetOfProviderOf; 24import static com.google.inject.multibindings.Multibinder.collectionOfJavaxProvidersOf; 25import static com.google.inject.multibindings.Multibinder.collectionOfProvidersOf; 26import static com.google.inject.multibindings.Multibinder.setOf; 27import static com.google.inject.multibindings.OptionalBinder.javaOptionalOfJavaxProvider; 28import static com.google.inject.multibindings.OptionalBinder.javaOptionalOfProvider; 29import static com.google.inject.multibindings.OptionalBinder.optionalOfJavaxProvider; 30import static com.google.inject.multibindings.OptionalBinder.optionalOfProvider; 31import static com.google.inject.multibindings.SpiUtils.BindType.INSTANCE; 32import static com.google.inject.multibindings.SpiUtils.BindType.LINKED; 33import static com.google.inject.multibindings.SpiUtils.BindType.PROVIDER_INSTANCE; 34import static com.google.inject.multibindings.SpiUtils.BindType.PROVIDER_KEY; 35import static com.google.inject.multibindings.SpiUtils.VisitType.BOTH; 36import static com.google.inject.multibindings.SpiUtils.VisitType.INJECTOR; 37import static com.google.inject.multibindings.SpiUtils.VisitType.MODULE; 38import static junit.framework.Assert.assertEquals; 39import static junit.framework.Assert.assertFalse; 40import static junit.framework.Assert.assertNotNull; 41import static junit.framework.Assert.assertNull; 42import static junit.framework.Assert.assertTrue; 43import static junit.framework.Assert.fail; 44 45import com.google.common.base.Objects; 46import com.google.common.base.Optional; 47import com.google.common.collect.ImmutableMap; 48import com.google.common.collect.ImmutableSet; 49import com.google.common.collect.Lists; 50import com.google.common.collect.Maps; 51import com.google.common.collect.Multimap; 52import com.google.common.collect.MultimapBuilder; 53import com.google.common.collect.Sets; 54import com.google.inject.Binding; 55import com.google.inject.Guice; 56import com.google.inject.Injector; 57import com.google.inject.Key; 58import com.google.inject.Module; 59import com.google.inject.Provider; 60import com.google.inject.TypeLiteral; 61import com.google.inject.multibindings.Indexer.IndexedBinding; 62import com.google.inject.multibindings.MapBinder.RealMapBinder.ProviderMapEntry; 63import com.google.inject.multibindings.OptionalBinder.Source; 64import com.google.inject.spi.DefaultBindingTargetVisitor; 65import com.google.inject.spi.Element; 66import com.google.inject.spi.Elements; 67import com.google.inject.spi.InstanceBinding; 68import com.google.inject.spi.LinkedKeyBinding; 69import com.google.inject.spi.ProviderInstanceBinding; 70import com.google.inject.spi.ProviderKeyBinding; 71import com.google.inject.spi.ProviderLookup; 72 73import java.util.HashSet; 74import java.util.List; 75import java.util.Map; 76import java.util.Set; 77 78/** 79 * Utilities for testing the Multibinder & MapBinder extension SPI. 80 * 81 * @author sameb@google.com (Sam Berlin) 82 */ 83public class SpiUtils { 84 85 private static final boolean HAS_JAVA_OPTIONAL; 86 static { 87 Class<?> optional = null; 88 try { 89 optional = Class.forName("java.util.Optional"); 90 } catch (ClassNotFoundException ignored) {} 91 HAS_JAVA_OPTIONAL = optional != null; 92 } 93 94 /** The kind of test we should perform. A live Injector, a raw Elements (Module) test, or both. */ 95 enum VisitType { INJECTOR, MODULE, BOTH } 96 97 /** 98 * Asserts that MapBinderBinding visitors for work correctly. 99 * 100 * @param <T> The type of the binding 101 * @param mapKey The key the map belongs to. 102 * @param keyType the TypeLiteral of the key of the map 103 * @param valueType the TypeLiteral of the value of the map 104 * @param modules The modules that define the mapbindings 105 * @param visitType The kind of test we should perform. A live Injector, a raw Elements (Module) test, or both. 106 * @param allowDuplicates If duplicates are allowed. 107 * @param expectedMapBindings The number of other mapbinders we expect to see. 108 * @param results The kind of bindings contained in the mapbinder. 109 */ 110 static <T> void assertMapVisitor(Key<T> mapKey, TypeLiteral<?> keyType, TypeLiteral<?> valueType, 111 Iterable<? extends Module> modules, VisitType visitType, boolean allowDuplicates, 112 int expectedMapBindings, MapResult... results) { 113 if(visitType == null) { 114 fail("must test something"); 115 } 116 117 if (visitType == BOTH || visitType == INJECTOR) { 118 mapInjectorTest(mapKey, keyType, valueType, modules, allowDuplicates, expectedMapBindings, 119 results); 120 } 121 122 if (visitType == BOTH || visitType == MODULE) { 123 mapModuleTest(mapKey, keyType, valueType, modules, allowDuplicates, expectedMapBindings, 124 results); 125 } 126 } 127 128 @SuppressWarnings("unchecked") 129 private static <T> void mapInjectorTest(Key<T> mapKey, TypeLiteral<?> keyType, 130 TypeLiteral<?> valueType, Iterable<? extends Module> modules, boolean allowDuplicates, 131 int expectedMapBindings, MapResult... results) { 132 Injector injector = Guice.createInjector(modules); 133 Visitor<T> visitor = new Visitor<T>(); 134 Binding<T> mapBinding = injector.getBinding(mapKey); 135 MapBinderBinding<T> mapbinder = (MapBinderBinding<T>)mapBinding.acceptTargetVisitor(visitor); 136 assertNotNull(mapbinder); 137 assertEquals(keyType, mapbinder.getKeyTypeLiteral()); 138 assertEquals(valueType, mapbinder.getValueTypeLiteral()); 139 assertEquals(allowDuplicates, mapbinder.permitsDuplicates()); 140 List<Map.Entry<?, Binding<?>>> entries = Lists.newArrayList(mapbinder.getEntries()); 141 List<MapResult> mapResults = Lists.newArrayList(results); 142 assertEquals("wrong entries, expected: " + mapResults + ", but was: " + entries, 143 mapResults.size(), entries.size()); 144 145 for(MapResult result : mapResults) { 146 Map.Entry<?, Binding<?>> found = null; 147 for(Map.Entry<?, Binding<?>> entry : entries) { 148 Object key = entry.getKey(); 149 Binding<?> value = entry.getValue(); 150 if(key.equals(result.k) && matches(value, result.v)) { 151 found = entry; 152 break; 153 } 154 } 155 if(found == null) { 156 fail("Could not find entry: " + result + " in remaining entries: " + entries); 157 } else { 158 assertTrue("mapBinder doesn't contain: " + found.getValue(), 159 mapbinder.containsElement(found.getValue())); 160 entries.remove(found); 161 } 162 } 163 164 if(!entries.isEmpty()) { 165 fail("Found all entries of: " + mapResults + ", but more were left over: " + entries); 166 } 167 168 Key<?> mapOfJavaxProvider = mapKey.ofType(mapOfJavaxProviderOf(keyType, valueType)); 169 Key<?> mapOfProvider = mapKey.ofType(mapOfProviderOf(keyType, valueType)); 170 Key<?> mapOfSetOfProvider = mapKey.ofType(mapOfSetOfProviderOf(keyType, valueType)); 171 Key<?> mapOfSet = mapKey.ofType(mapOf(keyType, setOf(valueType))); 172 Key<?> setOfEntry = mapKey.ofType(setOf(entryOfProviderOf(keyType, valueType))); 173 Key<?> collectionOfProvidersOfEntryOfProvider = 174 mapKey.ofType(collectionOfProvidersOf(entryOfProviderOf(keyType, valueType))); 175 Key<?> collectionOfJavaxProvidersOfEntryOfProvider = 176 mapKey.ofType(collectionOfJavaxProvidersOf(entryOfProviderOf(keyType, valueType))); 177 boolean entrySetMatch = false; 178 boolean mapJavaxProviderMatch = false; 179 boolean mapProviderMatch = false; 180 boolean mapSetMatch = false; 181 boolean mapSetProviderMatch = false; 182 boolean collectionOfProvidersOfEntryOfProviderMatch = false; 183 boolean collectionOfJavaxProvidersOfEntryOfProviderMatch = false; 184 List<Object> otherMapBindings = Lists.newArrayList(); 185 List<Binding> otherMatches = Lists.newArrayList(); 186 Multimap<Object, IndexedBinding> indexedEntries = 187 MultimapBuilder.hashKeys().hashSetValues().build(); 188 Indexer indexer = new Indexer(injector); 189 int duplicates = 0; 190 for(Binding b : injector.getAllBindings().values()) { 191 boolean contains = mapbinder.containsElement(b); 192 Object visited = b.acceptTargetVisitor(visitor); 193 if(visited instanceof MapBinderBinding) { 194 if(visited.equals(mapbinder)) { 195 assertTrue(contains); 196 } else { 197 otherMapBindings.add(visited); 198 } 199 } else if(b.getKey().equals(mapOfProvider)) { 200 assertTrue(contains); 201 mapProviderMatch = true; 202 } else if (b.getKey().equals(mapOfJavaxProvider)) { 203 assertTrue(contains); 204 mapJavaxProviderMatch = true; 205 } else if(b.getKey().equals(mapOfSet)) { 206 assertTrue(contains); 207 mapSetMatch = true; 208 } else if(b.getKey().equals(mapOfSetOfProvider)) { 209 assertTrue(contains); 210 mapSetProviderMatch = true; 211 } else if(b.getKey().equals(setOfEntry)) { 212 assertTrue(contains); 213 entrySetMatch = true; 214 // Validate that this binding is also a MultibinderBinding. 215 assertTrue(b.acceptTargetVisitor(visitor) instanceof MultibinderBinding); 216 } else if(b.getKey().equals(collectionOfProvidersOfEntryOfProvider)) { 217 assertTrue(contains); 218 collectionOfProvidersOfEntryOfProviderMatch = true; 219 } else if(b.getKey().equals(collectionOfJavaxProvidersOfEntryOfProvider)) { 220 assertTrue(contains); 221 collectionOfJavaxProvidersOfEntryOfProviderMatch = true; 222 } else if (contains) { 223 if (b instanceof ProviderInstanceBinding) { 224 ProviderInstanceBinding<?> pib = (ProviderInstanceBinding<?>)b; 225 if (pib.getUserSuppliedProvider() instanceof ProviderMapEntry) { 226 // weird casting required to workaround compilation issues with jdk6 227 ProviderMapEntry<?, ?> pme = 228 (ProviderMapEntry<?, ?>) (Provider) pib.getUserSuppliedProvider(); 229 Binding<?> valueBinding = injector.getBinding(pme.getValueKey()); 230 if (indexer.isIndexable(valueBinding) 231 && !indexedEntries.put(pme.getKey(), valueBinding.acceptTargetVisitor(indexer))) { 232 duplicates++; 233 } 234 } 235 } 236 otherMatches.add(b); 237 } 238 } 239 240 int sizeOfOther = otherMatches.size(); 241 if(allowDuplicates) { 242 sizeOfOther--; // account for 1 duplicate binding 243 } 244 // Multiply by two because each has a value and Map.Entry. 245 int expectedSize = 2 * (mapResults.size() + duplicates); 246 assertEquals("Incorrect other matches: " + otherMatches, expectedSize, sizeOfOther); 247 assertTrue(entrySetMatch); 248 assertTrue(mapProviderMatch); 249 assertTrue(mapJavaxProviderMatch); 250 assertTrue(collectionOfProvidersOfEntryOfProviderMatch); 251 assertTrue(collectionOfJavaxProvidersOfEntryOfProviderMatch); 252 assertEquals(allowDuplicates, mapSetMatch); 253 assertEquals(allowDuplicates, mapSetProviderMatch); 254 assertEquals("other MapBindings found: " + otherMapBindings, expectedMapBindings, 255 otherMapBindings.size()); 256 } 257 258 @SuppressWarnings("unchecked") 259 private static <T> void mapModuleTest(Key<T> mapKey, TypeLiteral<?> keyType, 260 TypeLiteral<?> valueType, Iterable<? extends Module> modules, boolean allowDuplicates, 261 int expectedMapBindings, MapResult... results) { 262 Set<Element> elements = ImmutableSet.copyOf(Elements.getElements(modules)); 263 Visitor<T> visitor = new Visitor<T>(); 264 MapBinderBinding<T> mapbinder = null; 265 Map<Key<?>, Binding<?>> keyMap = Maps.newHashMap(); 266 for(Element element : elements) { 267 if(element instanceof Binding) { 268 Binding<?> binding = (Binding<?>)element; 269 keyMap.put(binding.getKey(), binding); 270 if (binding.getKey().equals(mapKey)) { 271 mapbinder = (MapBinderBinding<T>)((Binding<T>)binding).acceptTargetVisitor(visitor); 272 } 273 } 274 } 275 assertNotNull(mapbinder); 276 277 assertEquals(keyType, mapbinder.getKeyTypeLiteral()); 278 assertEquals(valueType, mapbinder.getValueTypeLiteral()); 279 List<MapResult> mapResults = Lists.newArrayList(results); 280 281 Key<?> mapOfProvider = mapKey.ofType(mapOfProviderOf(keyType, valueType)); 282 Key<?> mapOfJavaxProvider = mapKey.ofType(mapOfJavaxProviderOf(keyType, valueType)); 283 Key<?> mapOfSetOfProvider = mapKey.ofType(mapOfSetOfProviderOf(keyType, valueType)); 284 Key<?> mapOfSet = mapKey.ofType(mapOf(keyType, setOf(valueType))); 285 Key<?> setOfEntry = mapKey.ofType(setOf(entryOfProviderOf(keyType, valueType))); 286 Key<?> collectionOfProvidersOfEntry = 287 mapKey.ofType(collectionOfProvidersOf(entryOfProviderOf(keyType, valueType))); 288 Key<?> collectionOfJavaxProvidersOfEntry = 289 mapKey.ofType(collectionOfJavaxProvidersOf(entryOfProviderOf(keyType, valueType))); 290 boolean entrySetMatch = false; 291 boolean mapProviderMatch = false; 292 boolean mapJavaxProviderMatch = false; 293 boolean mapSetMatch = false; 294 boolean mapSetProviderMatch = false; 295 boolean collectionOfProvidersOfEntryMatch = false; 296 boolean collectionOfJavaxProvidersOfEntryMatch = false; 297 List<Object> otherMapBindings = Lists.newArrayList(); 298 List<Element> otherMatches = Lists.newArrayList(); 299 List<Element> otherElements = Lists.newArrayList(); 300 Indexer indexer = new Indexer(null); 301 Multimap<Object, IndexedBinding> indexedEntries = 302 MultimapBuilder.hashKeys().hashSetValues().build(); 303 int duplicates = 0; 304 for(Element element : elements) { 305 boolean contains = mapbinder.containsElement(element); 306 if(!contains) { 307 otherElements.add(element); 308 } 309 boolean matched = false; 310 Key key = null; 311 Binding b = null; 312 if(element instanceof Binding) { 313 b = (Binding)element; 314 if (b instanceof ProviderInstanceBinding) { 315 ProviderInstanceBinding<?> pb = (ProviderInstanceBinding<?>) b; 316 if (pb.getUserSuppliedProvider() instanceof ProviderMapEntry) { 317 // weird casting required to workaround jdk6 compilation problems 318 ProviderMapEntry<?, ?> pme = 319 (ProviderMapEntry<?, ?>) (Provider) pb.getUserSuppliedProvider(); 320 Binding<?> valueBinding = keyMap.get(pme.getValueKey()); 321 if (indexer.isIndexable(valueBinding) 322 && !indexedEntries.put(pme.getKey(), valueBinding.acceptTargetVisitor(indexer))) { 323 duplicates++; 324 } 325 } 326 } 327 328 key = b.getKey(); 329 Object visited = b.acceptTargetVisitor(visitor); 330 if(visited instanceof MapBinderBinding) { 331 matched = true; 332 if(visited.equals(mapbinder)) { 333 assertTrue(contains); 334 } else { 335 otherMapBindings.add(visited); 336 } 337 } 338 } else if(element instanceof ProviderLookup) { 339 key = ((ProviderLookup)element).getKey(); 340 } 341 342 if(!matched && key != null) { 343 if(key.equals(mapOfProvider)) { 344 matched = true; 345 assertTrue(contains); 346 mapProviderMatch = true; 347 } else if(key.equals(mapOfJavaxProvider)) { 348 matched = true; 349 assertTrue(contains); 350 mapJavaxProviderMatch = true; 351 } else if(key.equals(mapOfSet)) { 352 matched = true; 353 assertTrue(contains); 354 mapSetMatch = true; 355 } else if(key.equals(mapOfSetOfProvider)) { 356 matched = true; 357 assertTrue(contains); 358 mapSetProviderMatch = true; 359 } else if(key.equals(setOfEntry)) { 360 matched = true; 361 assertTrue(contains); 362 entrySetMatch = true; 363 // Validate that this binding is also a MultibinderBinding. 364 if(b != null) { 365 assertTrue(b.acceptTargetVisitor(visitor) instanceof MultibinderBinding); 366 } 367 } else if(key.equals(collectionOfProvidersOfEntry)) { 368 matched = true; 369 assertTrue(contains); 370 collectionOfProvidersOfEntryMatch = true; 371 } else if(key.equals(collectionOfJavaxProvidersOfEntry)) { 372 matched = true; 373 assertTrue(contains); 374 collectionOfJavaxProvidersOfEntryMatch = true; 375 } 376 } 377 378 if (!matched && contains) { 379 otherMatches.add(element); 380 } 381 } 382 383 int otherMatchesSize = otherMatches.size(); 384 if (allowDuplicates) { 385 otherMatchesSize--; // allow for 1 duplicate binding 386 } 387 // Multiply by 3 because each has a value, ProviderLookup, and Map.Entry 388 int expectedSize = (mapResults.size() + duplicates) * 3; 389 assertEquals("incorrect number of contains, leftover matches: " + otherMatches, 390 expectedSize, otherMatchesSize); 391 392 assertTrue(entrySetMatch); 393 assertTrue(mapProviderMatch); 394 assertTrue(mapJavaxProviderMatch); 395 assertTrue(collectionOfProvidersOfEntryMatch); 396 assertTrue(collectionOfJavaxProvidersOfEntryMatch); 397 assertEquals(allowDuplicates, mapSetMatch); 398 assertEquals(allowDuplicates, mapSetProviderMatch); 399 assertEquals("other MapBindings found: " + otherMapBindings, expectedMapBindings, 400 otherMapBindings.size()); 401 402 // Validate that we can construct an injector out of the remaining bindings. 403 Guice.createInjector(Elements.getModule(otherElements)); 404 } 405 406 /** 407 * Asserts that MultibinderBinding visitors work correctly. 408 * 409 * @param <T> The type of the binding 410 * @param setKey The key the set belongs to. 411 * @param elementType the TypeLiteral of the element 412 * @param modules The modules that define the multibindings 413 * @param visitType The kind of test we should perform. A live Injector, a raw Elements (Module) test, or both. 414 * @param allowDuplicates If duplicates are allowed. 415 * @param expectedMultibindings The number of other multibinders we expect to see. 416 * @param results The kind of bindings contained in the multibinder. 417 */ 418 static <T> void assertSetVisitor(Key<Set<T>> setKey, TypeLiteral<?> elementType, 419 Iterable<? extends Module> modules, VisitType visitType, boolean allowDuplicates, 420 int expectedMultibindings, BindResult... results) { 421 if(visitType == null) { 422 fail("must test something"); 423 } 424 425 if(visitType == BOTH || visitType == INJECTOR) { 426 setInjectorTest(setKey, elementType, modules, allowDuplicates, 427 expectedMultibindings, results); 428 } 429 430 if(visitType == BOTH || visitType == MODULE) { 431 setModuleTest(setKey, elementType, modules, allowDuplicates, 432 expectedMultibindings, results); 433 } 434 } 435 436 @SuppressWarnings("unchecked") 437 private static <T> void setInjectorTest(Key<Set<T>> setKey, TypeLiteral<?> elementType, 438 Iterable<? extends Module> modules, boolean allowDuplicates, int otherMultibindings, 439 BindResult... results) { 440 Key<?> collectionOfProvidersKey = setKey.ofType(collectionOfProvidersOf(elementType)); 441 Key<?> collectionOfJavaxProvidersKey = 442 setKey.ofType(collectionOfJavaxProvidersOf(elementType)); 443 Injector injector = Guice.createInjector(modules); 444 Visitor<Set<T>> visitor = new Visitor<Set<T>>(); 445 Binding<Set<T>> binding = injector.getBinding(setKey); 446 MultibinderBinding<Set<T>> multibinder = 447 (MultibinderBinding<Set<T>>)binding.acceptTargetVisitor(visitor); 448 assertNotNull(multibinder); 449 assertEquals(elementType, multibinder.getElementTypeLiteral()); 450 assertEquals(allowDuplicates, multibinder.permitsDuplicates()); 451 List<Binding<?>> elements = Lists.newArrayList(multibinder.getElements()); 452 List<BindResult> bindResults = Lists.newArrayList(results); 453 assertEquals("wrong bind elements, expected: " + bindResults 454 + ", but was: " + multibinder.getElements(), 455 bindResults.size(), elements.size()); 456 457 for(BindResult result : bindResults) { 458 Binding found = null; 459 for(Binding item : elements) { 460 if (matches(item, result)) { 461 found = item; 462 break; 463 } 464 } 465 if(found == null) { 466 fail("Could not find element: " + result + " in remaining elements: " + elements); 467 } else { 468 elements.remove(found); 469 } 470 } 471 472 if(!elements.isEmpty()) { 473 fail("Found all elements of: " + bindResults + ", but more were left over: " + elements); 474 } 475 476 Set<Binding> setOfElements = new HashSet<Binding>(multibinder.getElements()); 477 Set<IndexedBinding> setOfIndexed = Sets.newHashSet(); 478 Indexer indexer = new Indexer(injector); 479 for (Binding<?> oneBinding : setOfElements) { 480 setOfIndexed.add(oneBinding.acceptTargetVisitor(indexer)); 481 } 482 483 List<Object> otherMultibinders = Lists.newArrayList(); 484 List<Binding> otherContains = Lists.newArrayList(); 485 boolean collectionOfProvidersMatch = false; 486 boolean collectionOfJavaxProvidersMatch = false; 487 for(Binding b : injector.getAllBindings().values()) { 488 boolean contains = multibinder.containsElement(b); 489 Key key = b.getKey(); 490 Object visited = b.acceptTargetVisitor(visitor); 491 if(visited != null) { 492 if(visited.equals(multibinder)) { 493 assertTrue(contains); 494 } else { 495 otherMultibinders.add(visited); 496 } 497 } else if(setOfElements.contains(b)) { 498 assertTrue(contains); 499 } else if (key.equals(collectionOfProvidersKey)) { 500 assertTrue(contains); 501 collectionOfProvidersMatch = true; 502 } else if (key.equals(collectionOfJavaxProvidersKey)) { 503 assertTrue(contains); 504 collectionOfJavaxProvidersMatch = true; 505 } else if (contains) { 506 if (!indexer.isIndexable(b) || !setOfIndexed.contains(b.acceptTargetVisitor(indexer))) { 507 otherContains.add(b); 508 } 509 } 510 } 511 512 assertTrue(collectionOfProvidersMatch); 513 assertTrue(collectionOfJavaxProvidersMatch); 514 515 if(allowDuplicates) { 516 assertEquals("contained more than it should: " + otherContains, 1, otherContains.size()); 517 } else { 518 assertTrue("contained more than it should: " + otherContains, otherContains.isEmpty()); 519 } 520 assertEquals("other multibindings found: " + otherMultibinders, otherMultibindings, 521 otherMultibinders.size()); 522 523 } 524 525 @SuppressWarnings("unchecked") 526 private static <T> void setModuleTest(Key<Set<T>> setKey, TypeLiteral<?> elementType, 527 Iterable<? extends Module> modules, boolean allowDuplicates, int otherMultibindings, 528 BindResult... results) { 529 Key<?> collectionOfProvidersKey = setKey.ofType(collectionOfProvidersOf(elementType)); 530 Key<?> collectionOfJavaxProvidersKey = 531 setKey.ofType(collectionOfJavaxProvidersOf(elementType)); 532 List<BindResult> bindResults = Lists.newArrayList(results); 533 List<Element> elements = Elements.getElements(modules); 534 Visitor<T> visitor = new Visitor<T>(); 535 MultibinderBinding<Set<T>> multibinder = null; 536 for(Element element : elements) { 537 if(element instanceof Binding && ((Binding)element).getKey().equals(setKey)) { 538 multibinder = (MultibinderBinding<Set<T>>)((Binding)element).acceptTargetVisitor(visitor); 539 break; 540 } 541 } 542 assertNotNull(multibinder); 543 544 assertEquals(elementType, multibinder.getElementTypeLiteral()); 545 List<Object> otherMultibinders = Lists.newArrayList(); 546 Set<Element> otherContains = new HashSet<Element>(); 547 List<Element> otherElements = Lists.newArrayList(); 548 int duplicates = 0; 549 Set<IndexedBinding> setOfIndexed = Sets.newHashSet(); 550 Indexer indexer = new Indexer(null); 551 boolean collectionOfProvidersMatch = false; 552 boolean collectionOfJavaxProvidersMatch = false; 553 for(Element element : elements) { 554 boolean contains = multibinder.containsElement(element); 555 if(!contains) { 556 otherElements.add(element); 557 } 558 boolean matched = false; 559 Key key = null; 560 if(element instanceof Binding) { 561 Binding binding = (Binding)element; 562 if (indexer.isIndexable(binding) 563 && !setOfIndexed.add((IndexedBinding) binding.acceptTargetVisitor(indexer))) { 564 duplicates++; 565 } 566 key = binding.getKey(); 567 Object visited = binding.acceptTargetVisitor(visitor); 568 if(visited != null) { 569 matched = true; 570 if(visited.equals(multibinder)) { 571 assertTrue(contains); 572 } else { 573 otherMultibinders.add(visited); 574 } 575 } 576 } 577 578 if (collectionOfProvidersKey.equals(key)) { 579 assertTrue(contains); 580 assertFalse(matched); 581 collectionOfProvidersMatch = true; 582 } else if (collectionOfJavaxProvidersKey.equals(key)) { 583 assertTrue(contains); 584 assertFalse(matched); 585 collectionOfJavaxProvidersMatch = true; 586 } else if (!matched && contains) { 587 otherContains.add(element); 588 } 589 } 590 591 if(allowDuplicates) { 592 assertEquals("wrong contained elements: " + otherContains, 593 bindResults.size() + 1 + duplicates, otherContains.size()); 594 } else { 595 assertEquals("wrong contained elements: " + otherContains, 596 bindResults.size() + duplicates, otherContains.size()); 597 } 598 599 assertEquals("other multibindings found: " + otherMultibinders, otherMultibindings, 600 otherMultibinders.size()); 601 assertTrue(collectionOfProvidersMatch); 602 assertTrue(collectionOfJavaxProvidersMatch); 603 604 // Validate that we can construct an injector out of the remaining bindings. 605 Guice.createInjector(Elements.getModule(otherElements)); 606 } 607 608 /** 609 * Asserts that OptionalBinderBinding visitors for work correctly. 610 * 611 * @param <T> The type of the binding 612 * @param keyType The key OptionalBinder is binding 613 * @param modules The modules that define the bindings 614 * @param visitType The kind of test we should perform. A live Injector, a raw Elements (Module) 615 * test, or both. 616 * @param expectedOtherOptionalBindings the # of other optional bindings we expect to see. 617 * @param expectedDefault the expected default binding, or null if none 618 * @param expectedActual the expected actual binding, or null if none 619 * @param expectedUserLinkedActual the user binding that is the actual binding, used if 620 * neither the default nor actual are set and a user binding existed for the type. 621 */ 622 static <T> void assertOptionalVisitor(Key<T> keyType, 623 Iterable<? extends Module> modules, 624 VisitType visitType, 625 int expectedOtherOptionalBindings, 626 BindResult<?> expectedDefault, 627 BindResult<?> expectedActual, 628 BindResult<?> expectedUserLinkedActual) { 629 if (visitType == null) { 630 fail("must test something"); 631 } 632 633 // if java.util.Optional is bound, there'll be twice as many as we expect. 634 if (HAS_JAVA_OPTIONAL) { 635 expectedOtherOptionalBindings *= 2; 636 } 637 638 if (visitType == BOTH || visitType == INJECTOR) { 639 optionalInjectorTest(keyType, modules, expectedOtherOptionalBindings, expectedDefault, 640 expectedActual, expectedUserLinkedActual); 641 } 642 643 if (visitType == BOTH || visitType == MODULE) { 644 optionalModuleTest(keyType, modules, expectedOtherOptionalBindings, expectedDefault, 645 expectedActual, expectedUserLinkedActual); 646 } 647 } 648 649 @SuppressWarnings({ "unchecked", "rawtypes" }) 650 private static <T> void optionalInjectorTest(Key<T> keyType, 651 Iterable<? extends Module> modules, 652 int expectedOtherOptionalBindings, 653 BindResult<?> expectedDefault, 654 BindResult<?> expectedActual, 655 BindResult<?> expectedUserLinkedActual) { 656 if (expectedUserLinkedActual != null) { 657 assertNull("cannot have actual if expecting user binding", expectedActual); 658 assertNull("cannot have default if expecting user binding", expectedDefault); 659 } 660 661 Key<Optional<T>> optionalKey = 662 keyType.ofType(OptionalBinder.optionalOf(keyType.getTypeLiteral())); 663 Key<?> javaOptionalKey = HAS_JAVA_OPTIONAL ? 664 keyType.ofType(OptionalBinder.javaOptionalOf(keyType.getTypeLiteral())) : null; 665 Injector injector = Guice.createInjector(modules); 666 Binding<Optional<T>> optionalBinding = injector.getBinding(optionalKey); 667 Visitor visitor = new Visitor(); 668 OptionalBinderBinding<Optional<T>> optionalBinder = 669 (OptionalBinderBinding<Optional<T>>) optionalBinding.acceptTargetVisitor(visitor); 670 assertNotNull(optionalBinder); 671 assertEquals(optionalKey, optionalBinder.getKey()); 672 673 Binding<?> javaOptionalBinding = null; 674 OptionalBinderBinding<?> javaOptionalBinder = null; 675 if (HAS_JAVA_OPTIONAL) { 676 javaOptionalBinding = injector.getBinding(javaOptionalKey); 677 javaOptionalBinder = (OptionalBinderBinding<?>) javaOptionalBinding.acceptTargetVisitor(visitor); 678 assertNotNull(javaOptionalBinder); 679 assertEquals(javaOptionalKey, javaOptionalBinder.getKey()); 680 } 681 682 if (expectedDefault == null) { 683 assertNull("did not expect a default binding", optionalBinder.getDefaultBinding()); 684 if (HAS_JAVA_OPTIONAL) { 685 assertNull("did not expect a default binding", javaOptionalBinder.getDefaultBinding()); 686 } 687 } else { 688 assertTrue("expectedDefault: " + expectedDefault + ", actualDefault: " 689 + optionalBinder.getDefaultBinding(), 690 matches(optionalBinder.getDefaultBinding(), expectedDefault)); 691 if (HAS_JAVA_OPTIONAL) { 692 assertTrue("expectedDefault: " + expectedDefault + ", actualDefault: " 693 + javaOptionalBinder.getDefaultBinding(), 694 matches(javaOptionalBinder.getDefaultBinding(), expectedDefault)); 695 } 696 } 697 698 if (expectedActual == null && expectedUserLinkedActual == null) { 699 assertNull(optionalBinder.getActualBinding()); 700 if (HAS_JAVA_OPTIONAL) { 701 assertNull(javaOptionalBinder.getActualBinding()); 702 } 703 } else if (expectedActual != null) { 704 assertTrue("expectedActual: " + expectedActual + ", actualActual: " 705 + optionalBinder.getActualBinding(), 706 matches(optionalBinder.getActualBinding(), expectedActual)); 707 if (HAS_JAVA_OPTIONAL) { 708 assertTrue("expectedActual: " + expectedActual + ", actualActual: " 709 + javaOptionalBinder.getActualBinding(), 710 matches(javaOptionalBinder.getActualBinding(), expectedActual)); 711 } 712 } else if (expectedUserLinkedActual != null) { 713 assertTrue("expectedUserLinkedActual: " + expectedUserLinkedActual + ", actualActual: " 714 + optionalBinder.getActualBinding(), 715 matches(optionalBinder.getActualBinding(), expectedUserLinkedActual)); 716 if (HAS_JAVA_OPTIONAL) { 717 assertTrue("expectedUserLinkedActual: " + expectedUserLinkedActual + ", actualActual: " 718 + javaOptionalBinder.getActualBinding(), 719 matches(javaOptionalBinder.getActualBinding(), expectedUserLinkedActual)); 720 } 721 } 722 723 724 Key<Optional<javax.inject.Provider<T>>> optionalJavaxProviderKey = 725 keyType.ofType(optionalOfJavaxProvider(keyType.getTypeLiteral())); 726 Key<?> javaOptionalJavaxProviderKey = HAS_JAVA_OPTIONAL ? 727 keyType.ofType(javaOptionalOfJavaxProvider(keyType.getTypeLiteral())) : null; 728 Key<Optional<Provider<T>>> optionalProviderKey = 729 keyType.ofType(optionalOfProvider(keyType.getTypeLiteral())); 730 Key<?> javaOptionalProviderKey = HAS_JAVA_OPTIONAL ? 731 keyType.ofType(javaOptionalOfProvider(keyType.getTypeLiteral())) : null; 732 733 boolean keyMatch = false; 734 boolean optionalKeyMatch = false; 735 boolean javaOptionalKeyMatch = false; 736 boolean optionalJavaxProviderKeyMatch = false; 737 boolean javaOptionalJavaxProviderKeyMatch = false; 738 boolean optionalProviderKeyMatch = false; 739 boolean javaOptionalProviderKeyMatch = false; 740 boolean defaultMatch = false; 741 boolean actualMatch = false; 742 List<Object> otherOptionalBindings = Lists.newArrayList(); 743 List<Binding> otherMatches = Lists.newArrayList(); 744 for (Binding b : injector.getAllBindings().values()) { 745 boolean contains = optionalBinder.containsElement(b); 746 if (HAS_JAVA_OPTIONAL) { 747 assertEquals(contains, javaOptionalBinder.containsElement(b)); 748 } 749 Object visited = b.acceptTargetVisitor(visitor); 750 if (visited instanceof OptionalBinderBinding) { 751 if (visited.equals(optionalBinder)) { 752 assertTrue(contains); 753 } else if (HAS_JAVA_OPTIONAL && visited.equals(javaOptionalBinder)) { 754 assertTrue(contains); 755 } else { 756 otherOptionalBindings.add(visited); 757 } 758 } 759 if (b.getKey().equals(keyType)) { 760 // keyType might match because a user bound it 761 // (which is possible in a purely absent OptionalBinder) 762 assertEquals(expectedDefault != null || expectedActual != null, contains); 763 if (contains) { 764 keyMatch = true; 765 } 766 } else if (b.getKey().equals(optionalKey)) { 767 assertTrue(contains); 768 optionalKeyMatch = true; 769 } else if (b.getKey().equals(javaOptionalKey)) { 770 assertTrue(contains); 771 javaOptionalKeyMatch = true; 772 } else if (b.getKey().equals(optionalJavaxProviderKey)) { 773 assertTrue(contains); 774 optionalJavaxProviderKeyMatch = true; 775 } else if (b.getKey().equals(javaOptionalJavaxProviderKey)) { 776 assertTrue(contains); 777 javaOptionalJavaxProviderKeyMatch = true; 778 } else if (b.getKey().equals(optionalProviderKey)) { 779 assertTrue(contains); 780 optionalProviderKeyMatch = true; 781 } else if (b.getKey().equals(javaOptionalProviderKey)) { 782 assertTrue(contains); 783 javaOptionalProviderKeyMatch = true; 784 } else if (expectedDefault != null && matches(b, expectedDefault)) { 785 assertTrue(contains); 786 defaultMatch = true; 787 } else if (expectedActual != null && matches(b, expectedActual)) { 788 assertTrue(contains); 789 actualMatch = true; 790 } else if (contains) { 791 otherMatches.add(b); 792 } 793 } 794 795 assertEquals(otherMatches.toString(), 0, otherMatches.size()); 796 // only expect a keymatch if either default or actual are set 797 assertEquals(expectedDefault != null || expectedActual != null, keyMatch); 798 assertTrue(optionalKeyMatch); 799 assertTrue(optionalJavaxProviderKeyMatch); 800 assertTrue(optionalProviderKeyMatch); 801 assertEquals(HAS_JAVA_OPTIONAL, javaOptionalKeyMatch); 802 assertEquals(HAS_JAVA_OPTIONAL, javaOptionalJavaxProviderKeyMatch); 803 assertEquals(HAS_JAVA_OPTIONAL, javaOptionalProviderKeyMatch); 804 assertEquals(expectedDefault != null, defaultMatch); 805 assertEquals(expectedActual != null, actualMatch); 806 assertEquals("other OptionalBindings found: " + otherOptionalBindings, 807 expectedOtherOptionalBindings, otherOptionalBindings.size()); 808 } 809 810 @SuppressWarnings({ "unchecked", "rawtypes" }) 811 private static <T> void optionalModuleTest(Key<T> keyType, 812 Iterable<? extends Module> modules, 813 int expectedOtherOptionalBindings, 814 BindResult<?> expectedDefault, 815 BindResult<?> expectedActual, 816 BindResult<?> expectedUserLinkedActual) { 817 if (expectedUserLinkedActual != null) { 818 assertNull("cannot have actual if expecting user binding", expectedActual); 819 assertNull("cannot have default if expecting user binding", expectedDefault); 820 } 821 Set<Element> elements = ImmutableSet.copyOf(Elements.getElements(modules)); 822 Map<Key<?>, Binding<?>> indexed = index(elements); 823 Key<Optional<T>> optionalKey = 824 keyType.ofType(OptionalBinder.optionalOf(keyType.getTypeLiteral())); 825 Key<?> javaOptionalKey = HAS_JAVA_OPTIONAL ? 826 keyType.ofType(OptionalBinder.javaOptionalOf(keyType.getTypeLiteral())) : null; 827 Visitor visitor = new Visitor(); 828 OptionalBinderBinding<Optional<T>> optionalBinder = null; 829 OptionalBinderBinding<?> javaOptionalBinder = null; 830 Key<?> defaultKey = null; 831 Key<?> actualKey = null; 832 833 Binding optionalBinding = indexed.get(optionalKey); 834 optionalBinder = 835 (OptionalBinderBinding<Optional<T>>) optionalBinding.acceptTargetVisitor(visitor); 836 837 if (HAS_JAVA_OPTIONAL) { 838 Binding javaOptionalBinding = indexed.get(javaOptionalKey); 839 javaOptionalBinder = (OptionalBinderBinding) javaOptionalBinding.acceptTargetVisitor(visitor); 840 } 841 842 // Locate the defaultKey & actualKey 843 for (Element element : elements) { 844 if (optionalBinder.containsElement(element) && element instanceof Binding) { 845 Binding binding = (Binding) element; 846 if (isSourceEntry(binding, Source.DEFAULT)) { 847 defaultKey = binding.getKey(); 848 } else if (isSourceEntry(binding, Source.ACTUAL)) { 849 actualKey = binding.getKey(); 850 } 851 } 852 } 853 assertNotNull(optionalBinder); 854 if (HAS_JAVA_OPTIONAL) { 855 assertNotNull(javaOptionalBinder); 856 } 857 assertEquals(expectedDefault == null, defaultKey == null); 858 assertEquals(expectedActual == null, actualKey == null); 859 860 Key<Optional<javax.inject.Provider<T>>> optionalJavaxProviderKey = 861 keyType.ofType(optionalOfJavaxProvider(keyType.getTypeLiteral())); 862 Key<?> javaOptionalJavaxProviderKey = HAS_JAVA_OPTIONAL ? 863 keyType.ofType(javaOptionalOfJavaxProvider(keyType.getTypeLiteral())) : null; 864 Key<Optional<Provider<T>>> optionalProviderKey = 865 keyType.ofType(optionalOfProvider(keyType.getTypeLiteral())); 866 Key<?> javaOptionalProviderKey = HAS_JAVA_OPTIONAL ? 867 keyType.ofType(javaOptionalOfProvider(keyType.getTypeLiteral())) : null; 868 boolean keyMatch = false; 869 boolean optionalKeyMatch = false; 870 boolean javaOptionalKeyMatch = false; 871 boolean optionalJavaxProviderKeyMatch = false; 872 boolean javaOptionalJavaxProviderKeyMatch = false; 873 boolean optionalProviderKeyMatch = false; 874 boolean javaOptionalProviderKeyMatch = false; 875 boolean defaultMatch = false; 876 boolean actualMatch = false; 877 List<Object> otherOptionalElements = Lists.newArrayList(); 878 List<Element> otherContains = Lists.newArrayList(); 879 List<Element> nonContainedElements = Lists.newArrayList(); 880 for (Element element : elements) { 881 boolean contains = optionalBinder.containsElement(element); 882 if (HAS_JAVA_OPTIONAL) { 883 assertEquals(contains, javaOptionalBinder.containsElement(element)); 884 } 885 if (!contains) { 886 nonContainedElements.add(element); 887 } 888 Key key = null; 889 Binding b = null; 890 if (element instanceof Binding) { 891 b = (Binding) element; 892 key = b.getKey(); 893 Object visited = b.acceptTargetVisitor(visitor); 894 if (visited instanceof OptionalBinderBinding) { 895 if (visited.equals(optionalBinder)) { 896 assertTrue(contains); 897 } else if (HAS_JAVA_OPTIONAL && visited.equals(javaOptionalBinder)) { 898 assertTrue(contains); 899 } else { 900 otherOptionalElements.add(visited); 901 } 902 } 903 } else if (element instanceof ProviderLookup) { 904 key = ((ProviderLookup) element).getKey(); 905 } 906 907 if (key != null && key.equals(keyType)) { 908 // keyType might match because a user bound it 909 // (which is possible in a purely absent OptionalBinder) 910 assertEquals(expectedDefault != null || expectedActual != null, contains); 911 if (contains) { 912 keyMatch = true; 913 } 914 } else if (key != null && key.equals(optionalKey)) { 915 assertTrue(contains); 916 optionalKeyMatch = true; 917 } else if (key != null && key.equals(javaOptionalKey)) { 918 assertTrue(contains); 919 javaOptionalKeyMatch = true; 920 } else if (key != null && key.equals(optionalJavaxProviderKey)) { 921 assertTrue(contains); 922 optionalJavaxProviderKeyMatch = true; 923 } else if (key != null && key.equals(javaOptionalJavaxProviderKey)) { 924 assertTrue(contains); 925 javaOptionalJavaxProviderKeyMatch = true; 926 } else if (key != null && key.equals(optionalProviderKey)) { 927 assertTrue(contains); 928 optionalProviderKeyMatch = true; 929 } else if (key != null && key.equals(javaOptionalProviderKey)) { 930 assertTrue(contains); 931 javaOptionalProviderKeyMatch = true; 932 } else if (key != null && key.equals(defaultKey)) { 933 assertTrue(contains); 934 if (b != null) { // otherwise it might just be a ProviderLookup into it 935 assertTrue("expected: " + expectedDefault + ", but was: " + b, 936 matches(b, expectedDefault)); 937 defaultMatch = true; 938 } 939 } else if (key != null && key.equals(actualKey)) { 940 assertTrue(contains); 941 if (b != null) { // otherwise it might just be a ProviderLookup into it 942 assertTrue("expected: " + expectedActual + ", but was: " + b, matches(b, expectedActual)); 943 actualMatch = true; 944 } 945 } else if (contains) { 946 otherContains.add(element); 947 } 948 } 949 950 // only expect a keymatch if either default or actual are set 951 assertEquals(expectedDefault != null || expectedActual != null, keyMatch); 952 assertTrue(optionalKeyMatch); 953 assertTrue(optionalJavaxProviderKeyMatch); 954 assertTrue(optionalProviderKeyMatch); 955 assertEquals(HAS_JAVA_OPTIONAL, javaOptionalKeyMatch); 956 assertEquals(HAS_JAVA_OPTIONAL, javaOptionalJavaxProviderKeyMatch); 957 assertEquals(HAS_JAVA_OPTIONAL, javaOptionalProviderKeyMatch); 958 assertEquals(expectedDefault != null, defaultMatch); 959 assertEquals(expectedActual != null, actualMatch); 960 assertEquals(otherContains.toString(), 0, otherContains.size()); 961 assertEquals("other OptionalBindings found: " + otherOptionalElements, 962 expectedOtherOptionalBindings, otherOptionalElements.size()); 963 964 // Validate that we can construct an injector out of the remaining bindings. 965 Guice.createInjector(Elements.getModule(nonContainedElements)); 966 } 967 968 private static boolean isSourceEntry(Binding b, Source type) { 969 switch(type) { 970 case ACTUAL: 971 return b.getKey().getAnnotation() instanceof OptionalBinder.Actual; 972 case DEFAULT: 973 return b.getKey().getAnnotation() instanceof OptionalBinder.Default; 974 default: 975 throw new IllegalStateException("invalid type: " + type); 976 } 977 } 978 979 /** Returns the subset of elements that have keys, indexed by them. */ 980 private static Map<Key<?>, Binding<?>> index(Iterable<Element> elements) { 981 ImmutableMap.Builder<Key<?>, Binding<?>> builder = ImmutableMap.builder(); 982 for (Element element : elements) { 983 if (element instanceof Binding) { 984 builder.put(((Binding) element).getKey(), (Binding) element); 985 } 986 } 987 return builder.build(); 988 } 989 990 static <K, V> MapResult instance(K k, V v) { 991 return new MapResult<K, V>(k, new BindResult<V>(INSTANCE, v, null)); 992 } 993 994 static <K, V> MapResult linked(K k, Class<? extends V> clazz) { 995 return new MapResult<K, V>(k, new BindResult<V>(LINKED, null, Key.get(clazz))); 996 } 997 998 static <K, V> MapResult linked(K k, Key<? extends V> key) { 999 return new MapResult<K, V>(k, new BindResult<V>(LINKED, null, key)); 1000 } 1001 1002 static <K, V> MapResult providerInstance(K k, V v) { 1003 return new MapResult<K, V>(k, new BindResult<V>(PROVIDER_INSTANCE, v, null)); 1004 } 1005 1006 static class MapResult<K, V> { 1007 private final K k; 1008 private final BindResult<V> v; 1009 1010 MapResult(K k, BindResult<V> v) { 1011 this.k = k; 1012 this.v = v; 1013 } 1014 1015 @Override 1016 public String toString() { 1017 return "entry[key[" + k + "],value[" + v + "]]"; 1018 } 1019 } 1020 1021 private static boolean matches(Binding<?> item, BindResult<?> result) { 1022 switch (result.type) { 1023 case INSTANCE: 1024 if (item instanceof InstanceBinding 1025 && ((InstanceBinding) item).getInstance().equals(result.instance)) { 1026 return true; 1027 } 1028 break; 1029 case LINKED: 1030 if (item instanceof LinkedKeyBinding 1031 && ((LinkedKeyBinding) item).getLinkedKey().equals(result.key)) { 1032 return true; 1033 } 1034 break; 1035 case PROVIDER_INSTANCE: 1036 if (item instanceof ProviderInstanceBinding 1037 && Objects.equal(((ProviderInstanceBinding) item).getUserSuppliedProvider().get(), 1038 result.instance)) { 1039 return true; 1040 } 1041 break; 1042 case PROVIDER_KEY: 1043 if (item instanceof ProviderKeyBinding 1044 && ((ProviderKeyBinding) item).getProviderKey().equals(result.key)) { 1045 return true; 1046 } 1047 break; 1048 } 1049 return false; 1050 } 1051 1052 static <T> BindResult<T> instance(T t) { 1053 return new BindResult<T>(INSTANCE, t, null); 1054 } 1055 1056 static <T> BindResult<T> linked(Class<? extends T> clazz) { 1057 return new BindResult<T>(LINKED, null, Key.get(clazz)); 1058 } 1059 1060 static <T> BindResult<T> linked(Key<? extends T> key) { 1061 return new BindResult<T>(LINKED, null, key); 1062 } 1063 1064 static <T> BindResult<T> providerInstance(T t) { 1065 return new BindResult<T>(PROVIDER_INSTANCE, t, null); 1066 } 1067 1068 static <T> BindResult<T> providerKey(Key<T> key) { 1069 return new BindResult<T>(PROVIDER_KEY, null, key); 1070 } 1071 1072 /** The kind of binding. */ 1073 static enum BindType { INSTANCE, LINKED, PROVIDER_INSTANCE, PROVIDER_KEY } 1074 /** The result of the binding. */ 1075 static class BindResult<T> { 1076 private final BindType type; 1077 private final Key<?> key; 1078 private final T instance; 1079 1080 private BindResult(BindType type, T instance, Key<?> key) { 1081 this.type = type; 1082 this.instance = instance; 1083 this.key = key; 1084 } 1085 1086 @Override 1087 public String toString() { 1088 switch(type) { 1089 case INSTANCE: 1090 return "instance[" + instance + "]"; 1091 case LINKED: 1092 return "linkedKey[" + key + "]"; 1093 case PROVIDER_INSTANCE: 1094 return "providerInstance[" + instance + "]"; 1095 case PROVIDER_KEY: 1096 return "providerKey[" + key + "]"; 1097 } 1098 return null; 1099 } 1100 } 1101 1102 private static class Visitor<T> extends 1103 DefaultBindingTargetVisitor<T, Object> implements MultibindingsTargetVisitor<T, Object> { 1104 1105 public Object visit(MultibinderBinding<? extends T> multibinding) { 1106 return multibinding; 1107 } 1108 1109 public Object visit(MapBinderBinding<? extends T> mapbinding) { 1110 return mapbinding; 1111 } 1112 1113 public Object visit(OptionalBinderBinding<? extends T> optionalbinding) { 1114 return optionalbinding; 1115 } 1116 } 1117} 1118