• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.multibindings;
18 
19 import static com.google.inject.multibindings.MapBinder.entryOfProviderOf;
20 import static com.google.inject.multibindings.MapBinder.mapOf;
21 import static com.google.inject.multibindings.MapBinder.mapOfJavaxProviderOf;
22 import static com.google.inject.multibindings.MapBinder.mapOfProviderOf;
23 import static com.google.inject.multibindings.MapBinder.mapOfSetOfProviderOf;
24 import static com.google.inject.multibindings.Multibinder.collectionOfJavaxProvidersOf;
25 import static com.google.inject.multibindings.Multibinder.collectionOfProvidersOf;
26 import static com.google.inject.multibindings.Multibinder.setOf;
27 import static com.google.inject.multibindings.OptionalBinder.javaOptionalOfJavaxProvider;
28 import static com.google.inject.multibindings.OptionalBinder.javaOptionalOfProvider;
29 import static com.google.inject.multibindings.OptionalBinder.optionalOfJavaxProvider;
30 import static com.google.inject.multibindings.OptionalBinder.optionalOfProvider;
31 import static com.google.inject.multibindings.SpiUtils.BindType.INSTANCE;
32 import static com.google.inject.multibindings.SpiUtils.BindType.LINKED;
33 import static com.google.inject.multibindings.SpiUtils.BindType.PROVIDER_INSTANCE;
34 import static com.google.inject.multibindings.SpiUtils.BindType.PROVIDER_KEY;
35 import static com.google.inject.multibindings.SpiUtils.VisitType.BOTH;
36 import static com.google.inject.multibindings.SpiUtils.VisitType.INJECTOR;
37 import static com.google.inject.multibindings.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.Objects;
46 import com.google.common.base.Optional;
47 import com.google.common.collect.ImmutableMap;
48 import com.google.common.collect.ImmutableSet;
49 import com.google.common.collect.Lists;
50 import com.google.common.collect.Maps;
51 import com.google.common.collect.Multimap;
52 import com.google.common.collect.MultimapBuilder;
53 import com.google.common.collect.Sets;
54 import com.google.inject.Binding;
55 import com.google.inject.Guice;
56 import com.google.inject.Injector;
57 import com.google.inject.Key;
58 import com.google.inject.Module;
59 import com.google.inject.Provider;
60 import com.google.inject.TypeLiteral;
61 import com.google.inject.multibindings.Indexer.IndexedBinding;
62 import com.google.inject.multibindings.MapBinder.RealMapBinder.ProviderMapEntry;
63 import com.google.inject.multibindings.OptionalBinder.Source;
64 import com.google.inject.spi.DefaultBindingTargetVisitor;
65 import com.google.inject.spi.Element;
66 import com.google.inject.spi.Elements;
67 import com.google.inject.spi.InstanceBinding;
68 import com.google.inject.spi.LinkedKeyBinding;
69 import com.google.inject.spi.ProviderInstanceBinding;
70 import com.google.inject.spi.ProviderKeyBinding;
71 import com.google.inject.spi.ProviderLookup;
72 
73 import java.util.HashSet;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.Set;
77 
78 /**
79  * Utilities for testing the Multibinder & MapBinder extension SPI.
80  *
81  * @author sameb@google.com (Sam Berlin)
82  */
83 public 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    */
assertMapVisitor(Key<T> mapKey, TypeLiteral<?> keyType, TypeLiteral<?> valueType, Iterable<? extends Module> modules, VisitType visitType, boolean allowDuplicates, int expectedMapBindings, MapResult... results)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")
mapInjectorTest(Key<T> mapKey, TypeLiteral<?> keyType, TypeLiteral<?> valueType, Iterable<? extends Module> modules, boolean allowDuplicates, int expectedMapBindings, MapResult... results)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")
mapModuleTest(Key<T> mapKey, TypeLiteral<?> keyType, TypeLiteral<?> valueType, Iterable<? extends Module> modules, boolean allowDuplicates, int expectedMapBindings, MapResult... results)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    */
assertSetVisitor(Key<Set<T>> setKey, TypeLiteral<?> elementType, Iterable<? extends Module> modules, VisitType visitType, boolean allowDuplicates, int expectedMultibindings, BindResult... results)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")
setInjectorTest(Key<Set<T>> setKey, TypeLiteral<?> elementType, Iterable<? extends Module> modules, boolean allowDuplicates, int otherMultibindings, BindResult... results)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")
setModuleTest(Key<Set<T>> setKey, TypeLiteral<?> elementType, Iterable<? extends Module> modules, boolean allowDuplicates, int otherMultibindings, BindResult... results)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    */
assertOptionalVisitor(Key<T> keyType, Iterable<? extends Module> modules, VisitType visitType, int expectedOtherOptionalBindings, BindResult<?> expectedDefault, BindResult<?> expectedActual, BindResult<?> expectedUserLinkedActual)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" })
optionalInjectorTest(Key<T> keyType, Iterable<? extends Module> modules, int expectedOtherOptionalBindings, BindResult<?> expectedDefault, BindResult<?> expectedActual, BindResult<?> expectedUserLinkedActual)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" })
optionalModuleTest(Key<T> keyType, Iterable<? extends Module> modules, int expectedOtherOptionalBindings, BindResult<?> expectedDefault, BindResult<?> expectedActual, BindResult<?> expectedUserLinkedActual)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 
isSourceEntry(Binding b, Source type)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. */
index(Iterable<Element> elements)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 
instance(K k, V v)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 
linked(K k, Class<? extends V> clazz)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 
linked(K k, Key<? extends V> key)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 
providerInstance(K k, V v)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 
MapResult(K k, BindResult<V> v)1010     MapResult(K k, BindResult<V> v) {
1011       this.k = k;
1012       this.v = v;
1013     }
1014 
1015     @Override
toString()1016     public String toString() {
1017       return "entry[key[" + k + "],value[" + v + "]]";
1018     }
1019   }
1020 
matches(Binding<?> item, BindResult<?> result)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 
instance(T t)1052   static <T> BindResult<T> instance(T t) {
1053     return new BindResult<T>(INSTANCE, t, null);
1054   }
1055 
linked(Class<? extends T> clazz)1056   static <T> BindResult<T> linked(Class<? extends T> clazz) {
1057     return new BindResult<T>(LINKED, null, Key.get(clazz));
1058   }
1059 
linked(Key<? extends T> key)1060   static <T> BindResult<T> linked(Key<? extends T> key) {
1061     return new BindResult<T>(LINKED, null, key);
1062   }
1063 
providerInstance(T t)1064   static <T> BindResult<T> providerInstance(T t) {
1065     return new BindResult<T>(PROVIDER_INSTANCE, t, null);
1066   }
1067 
providerKey(Key<T> key)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 
BindResult(BindType type, T instance, Key<?> key)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
toString()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 
visit(MultibinderBinding<? extends T> multibinding)1105     public Object visit(MultibinderBinding<? extends T> multibinding) {
1106       return multibinding;
1107     }
1108 
visit(MapBinderBinding<? extends T> mapbinding)1109     public Object visit(MapBinderBinding<? extends T> mapbinding) {
1110       return mapbinding;
1111     }
1112 
visit(OptionalBinderBinding<? extends T> optionalbinding)1113     public Object visit(OptionalBinderBinding<? extends T> optionalbinding) {
1114       return optionalbinding;
1115     }
1116   }
1117 }
1118