Home | History | Annotate | Download | only in multibindings
      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 (at) 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    */
    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