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