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