• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2008 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.Element.Type.MAPBINDER;
20 import static com.google.inject.multibindings.Multibinder.checkConfiguration;
21 import static com.google.inject.multibindings.Multibinder.checkNotNull;
22 import static com.google.inject.multibindings.Multibinder.setOf;
23 import static com.google.inject.util.Types.newParameterizedType;
24 import static com.google.inject.util.Types.newParameterizedTypeWithOwner;
25 
26 import com.google.common.base.Joiner;
27 import com.google.common.base.Objects;
28 import com.google.common.base.Supplier;
29 import com.google.common.collect.HashMultimap;
30 import com.google.common.collect.ImmutableList;
31 import com.google.common.collect.ImmutableMap;
32 import com.google.common.collect.ImmutableSet;
33 import com.google.common.collect.Lists;
34 import com.google.common.collect.Maps;
35 import com.google.common.collect.Multimap;
36 import com.google.common.collect.Multimaps;
37 import com.google.common.collect.Sets;
38 import com.google.inject.Binder;
39 import com.google.inject.Binding;
40 import com.google.inject.Inject;
41 import com.google.inject.Injector;
42 import com.google.inject.Key;
43 import com.google.inject.Module;
44 import com.google.inject.Provider;
45 import com.google.inject.TypeLiteral;
46 import com.google.inject.binder.LinkedBindingBuilder;
47 import com.google.inject.internal.Errors;
48 import com.google.inject.multibindings.Indexer.IndexedBinding;
49 import com.google.inject.multibindings.Multibinder.RealMultibinder;
50 import com.google.inject.spi.BindingTargetVisitor;
51 import com.google.inject.spi.Dependency;
52 import com.google.inject.spi.Element;
53 import com.google.inject.spi.HasDependencies;
54 import com.google.inject.spi.ProviderInstanceBinding;
55 import com.google.inject.spi.ProviderLookup;
56 import com.google.inject.spi.ProviderWithDependencies;
57 import com.google.inject.spi.ProviderWithExtensionVisitor;
58 import com.google.inject.spi.Toolable;
59 import com.google.inject.util.Types;
60 
61 import java.lang.annotation.Annotation;
62 import java.util.Collection;
63 import java.util.Collections;
64 import java.util.LinkedHashMap;
65 import java.util.List;
66 import java.util.Map;
67 import java.util.Map.Entry;
68 import java.util.Set;
69 
70 /**
71  * An API to bind multiple map entries separately, only to later inject them as
72  * a complete map. MapBinder is intended for use in your application's module:
73  * <pre><code>
74  * public class SnacksModule extends AbstractModule {
75  *   protected void configure() {
76  *     MapBinder&lt;String, Snack&gt; mapbinder
77  *         = MapBinder.newMapBinder(binder(), String.class, Snack.class);
78  *     mapbinder.addBinding("twix").toInstance(new Twix());
79  *     mapbinder.addBinding("snickers").toProvider(SnickersProvider.class);
80  *     mapbinder.addBinding("skittles").to(Skittles.class);
81  *   }
82  * }</code></pre>
83  *
84  * <p>With this binding, a {@link Map}{@code <String, Snack>} can now be
85  * injected:
86  * <pre><code>
87  * class SnackMachine {
88  *   {@literal @}Inject
89  *   public SnackMachine(Map&lt;String, Snack&gt; snacks) { ... }
90  * }</code></pre>
91  *
92  * <p>In addition to binding {@code Map<K, V>}, a mapbinder will also bind
93  * {@code Map<K, Provider<V>>} for lazy value provision:
94  * <pre><code>
95  * class SnackMachine {
96  *   {@literal @}Inject
97  *   public SnackMachine(Map&lt;String, Provider&lt;Snack&gt;&gt; snackProviders) { ... }
98  * }</code></pre>
99  *
100  * <p>Contributing mapbindings from different modules is supported. For example,
101  * it is okay to have both {@code CandyModule} and {@code ChipsModule} both
102  * create their own {@code MapBinder<String, Snack>}, and to each contribute
103  * bindings to the snacks map. When that map is injected, it will contain
104  * entries from both modules.
105  *
106  * <p>The map's iteration order is consistent with the binding order. This is
107  * convenient when multiple elements are contributed by the same module because
108  * that module can order its bindings appropriately. Avoid relying on the
109  * iteration order of elements contributed by different modules, since there is
110  * no equivalent mechanism to order modules.
111  *
112  * <p>The map is unmodifiable.  Elements can only be added to the map by
113  * configuring the MapBinder.  Elements can never be removed from the map.
114  *
115  * <p>Values are resolved at map injection time. If a value is bound to a
116  * provider, that provider's get method will be called each time the map is
117  * injected (unless the binding is also scoped, or a map of providers is injected).
118  *
119  * <p>Annotations are used to create different maps of the same key/value
120  * type. Each distinct annotation gets its own independent map.
121  *
122  * <p><strong>Keys must be distinct.</strong> If the same key is bound more than
123  * once, map injection will fail. However, use {@link #permitDuplicates()} in
124  * order to allow duplicate keys; extra bindings to {@code Map<K, Set<V>>} and
125  * {@code Map<K, Set<Provider<V>>} will be added.
126  *
127  * <p><strong>Keys must be non-null.</strong> {@code addBinding(null)} will
128  * throw an unchecked exception.
129  *
130  * <p><strong>Values must be non-null to use map injection.</strong> If any
131  * value is null, map injection will fail (although injecting a map of providers
132  * will not).
133  *
134  * @author dpb@google.com (David P. Baker)
135  */
136 public abstract class MapBinder<K, V> {
MapBinder()137   private MapBinder() {}
138 
139   /**
140    * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a
141    * {@link Map} that is itself bound with no binding annotation.
142    */
newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType)143   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder,
144       TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
145     binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
146     return newRealMapBinder(binder, keyType, valueType, Key.get(mapOf(keyType, valueType)),
147         Multibinder.newSetBinder(binder, entryOfProviderOf(keyType, valueType)));
148   }
149 
150   /**
151    * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a
152    * {@link Map} that is itself bound with no binding annotation.
153    */
newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType)154   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder,
155       Class<K> keyType, Class<V> valueType) {
156     return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType));
157   }
158 
159   /**
160    * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a
161    * {@link Map} that is itself bound with {@code annotation}.
162    */
newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType, Annotation annotation)163   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder,
164       TypeLiteral<K> keyType, TypeLiteral<V> valueType, Annotation annotation) {
165     binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
166     return newRealMapBinder(binder, keyType, valueType,
167         Key.get(mapOf(keyType, valueType), annotation),
168         Multibinder.newSetBinder(binder, entryOfProviderOf(keyType, valueType), annotation));
169   }
170 
171   /**
172    * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a
173    * {@link Map} that is itself bound with {@code annotation}.
174    */
newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType, Annotation annotation)175   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder,
176       Class<K> keyType, Class<V> valueType, Annotation annotation) {
177     return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotation);
178   }
179 
180   /**
181    * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a
182    * {@link Map} that is itself bound with {@code annotationType}.
183    */
newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType, Class<? extends Annotation> annotationType)184   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<K> keyType,
185       TypeLiteral<V> valueType, Class<? extends Annotation> annotationType) {
186     binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
187     return newRealMapBinder(binder, keyType, valueType,
188         Key.get(mapOf(keyType, valueType), annotationType),
189         Multibinder.newSetBinder(binder, entryOfProviderOf(keyType, valueType), annotationType));
190   }
191 
192   /**
193    * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a
194    * {@link Map} that is itself bound with {@code annotationType}.
195    */
newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType, Class<? extends Annotation> annotationType)196   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, Class<K> keyType,
197       Class<V> valueType, Class<? extends Annotation> annotationType) {
198     return newMapBinder(
199         binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotationType);
200   }
201 
202   @SuppressWarnings("unchecked") // a map of <K, V> is safely a Map<K, V>
mapOf( TypeLiteral<K> keyType, TypeLiteral<V> valueType)203   static <K, V> TypeLiteral<Map<K, V>> mapOf(
204       TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
205     return (TypeLiteral<Map<K, V>>) TypeLiteral.get(
206         Types.mapOf(keyType.getType(), valueType.getType()));
207   }
208 
209   @SuppressWarnings("unchecked") // a provider map <K, V> is safely a Map<K, Provider<V>>
mapOfProviderOf( TypeLiteral<K> keyType, TypeLiteral<V> valueType)210   static <K, V> TypeLiteral<Map<K, Provider<V>>> mapOfProviderOf(
211       TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
212     return (TypeLiteral<Map<K, Provider<V>>>) TypeLiteral.get(
213         Types.mapOf(keyType.getType(), Types.providerOf(valueType.getType())));
214   }
215 
216   // provider map <K, V> is safely a Map<K, javax.inject.Provider<V>>>
217   @SuppressWarnings("unchecked")
mapOfJavaxProviderOf( TypeLiteral<K> keyType, TypeLiteral<V> valueType)218   static <K, V> TypeLiteral<Map<K, javax.inject.Provider<V>>> mapOfJavaxProviderOf(
219       TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
220     return (TypeLiteral<Map<K, javax.inject.Provider<V>>>) TypeLiteral.get(
221         Types.mapOf(keyType.getType(),
222             newParameterizedType(javax.inject.Provider.class, valueType.getType())));
223   }
224 
225   @SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
mapOfSetOfProviderOf( TypeLiteral<K> keyType, TypeLiteral<V> valueType)226   static <K, V> TypeLiteral<Map<K, Set<Provider<V>>>> mapOfSetOfProviderOf(
227       TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
228     return (TypeLiteral<Map<K, Set<Provider<V>>>>) TypeLiteral.get(
229         Types.mapOf(keyType.getType(), Types.setOf(Types.providerOf(valueType.getType()))));
230   }
231 
232   @SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
entryOfProviderOf( TypeLiteral<K> keyType, TypeLiteral<V> valueType)233   static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfProviderOf(
234       TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
235     return (TypeLiteral<Entry<K, Provider<V>>>) TypeLiteral.get(newParameterizedTypeWithOwner(
236         Map.class, Entry.class, keyType.getType(), Types.providerOf(valueType.getType())));
237   }
238 
239   // Note: We use valueTypeAndAnnotation effectively as a Pair<TypeLiteral, Annotation|Class>
240   // since it's an easy way to group a type and an optional annotation type or instance.
newRealMapBinder(Binder binder, TypeLiteral<K> keyType, Key<V> valueTypeAndAnnotation)241   static <K, V> RealMapBinder<K, V> newRealMapBinder(Binder binder, TypeLiteral<K> keyType,
242       Key<V> valueTypeAndAnnotation) {
243     binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
244     TypeLiteral<V> valueType = valueTypeAndAnnotation.getTypeLiteral();
245     return newRealMapBinder(binder, keyType, valueType,
246         valueTypeAndAnnotation.ofType(mapOf(keyType, valueType)),
247         Multibinder.newSetBinder(binder,
248             valueTypeAndAnnotation.ofType(entryOfProviderOf(keyType, valueType))));
249   }
250 
newRealMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType, Key<Map<K, V>> mapKey, Multibinder<Entry<K, Provider<V>>> entrySetBinder)251   private static <K, V> RealMapBinder<K, V> newRealMapBinder(Binder binder,
252       TypeLiteral<K> keyType, TypeLiteral<V> valueType, Key<Map<K, V>> mapKey,
253       Multibinder<Entry<K, Provider<V>>> entrySetBinder) {
254     RealMapBinder<K, V> mapBinder =
255         new RealMapBinder<K, V>(binder, keyType, valueType, mapKey, entrySetBinder);
256     binder.install(mapBinder);
257     return mapBinder;
258   }
259 
260   /**
261    * Configures the {@code MapBinder} to handle duplicate entries.
262    * <p>When multiple equal keys are bound, the value that gets included in the map is
263    * arbitrary.
264    * <p>In addition to the {@code Map<K, V>} and {@code Map<K, Provider<V>>}
265    * maps that are normally bound, a {@code Map<K, Set<V>>} and
266    * {@code Map<K, Set<Provider<V>>>} are <em>also</em> bound, which contain
267    * all values bound to each key.
268    * <p>
269    * When multiple modules contribute elements to the map, this configuration
270    * option impacts all of them.
271    *
272    * @return this map binder
273    * @since 3.0
274    */
permitDuplicates()275   public abstract MapBinder<K, V> permitDuplicates();
276 
277   /**
278    * Returns a binding builder used to add a new entry in the map. Each
279    * key must be distinct (and non-null). Bound providers will be evaluated each
280    * time the map is injected.
281    *
282    * <p>It is an error to call this method without also calling one of the
283    * {@code to} methods on the returned binding builder.
284    *
285    * <p>Scoping elements independently is supported. Use the {@code in} method
286    * to specify a binding scope.
287    */
addBinding(K key)288   public abstract LinkedBindingBuilder<V> addBinding(K key);
289 
290   /**
291    * The actual mapbinder plays several roles:
292    *
293    * <p>As a MapBinder, it acts as a factory for LinkedBindingBuilders for
294    * each of the map's values. It delegates to a {@link Multibinder} of
295    * entries (keys to value providers).
296    *
297    * <p>As a Module, it installs the binding to the map itself, as well as to
298    * a corresponding map whose values are providers. It uses the entry set
299    * multibinder to construct the map and the provider map.
300    *
301    * <p>As a module, this implements equals() and hashcode() in order to trick
302    * Guice into executing its configure() method only once. That makes it so
303    * that multiple mapbinders can be created for the same target map, but
304    * only one is bound. Since the list of bindings is retrieved from the
305    * injector itself (and not the mapbinder), each mapbinder has access to
306    * all contributions from all equivalent mapbinders.
307    *
308    * <p>Rather than binding a single Map.Entry&lt;K, V&gt;, the map binder
309    * binds keys and values independently. This allows the values to be properly
310    * scoped.
311    *
312    * <p>We use a subclass to hide 'implements Module' from the public API.
313    */
314   static final class RealMapBinder<K, V> extends MapBinder<K, V> implements Module {
315     private final TypeLiteral<K> keyType;
316     private final TypeLiteral<V> valueType;
317     private final Key<Map<K, V>> mapKey;
318     private final Key<Map<K, javax.inject.Provider<V>>> javaxProviderMapKey;
319     private final Key<Map<K, Provider<V>>> providerMapKey;
320     private final Key<Map<K, Set<V>>> multimapKey;
321     private final Key<Map<K, Set<Provider<V>>>> providerMultimapKey;
322     private final RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder;
323     private final Map<K, String> duplicateKeyErrorMessages;
324 
325     /* the target injector's binder. non-null until initialization, null afterwards */
326     private Binder binder;
327 
328     private boolean permitDuplicates;
329     private ImmutableList<Map.Entry<K, Binding<V>>> mapBindings;
330 
RealMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType, Key<Map<K, V>> mapKey, Multibinder<Map.Entry<K, Provider<V>>> entrySetBinder)331     private RealMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType,
332         Key<Map<K, V>> mapKey, Multibinder<Map.Entry<K, Provider<V>>> entrySetBinder) {
333       this.keyType = keyType;
334       this.valueType = valueType;
335       this.mapKey = mapKey;
336       this.providerMapKey = mapKey.ofType(mapOfProviderOf(keyType, valueType));
337       this.javaxProviderMapKey = mapKey.ofType(mapOfJavaxProviderOf(keyType, valueType));
338       this.multimapKey = mapKey.ofType(mapOf(keyType, setOf(valueType)));
339       this.providerMultimapKey = mapKey.ofType(mapOfSetOfProviderOf(keyType, valueType));
340       this.entrySetBinder = (RealMultibinder<Entry<K, Provider<V>>>) entrySetBinder;
341       this.binder = binder;
342       this.duplicateKeyErrorMessages = Maps.newHashMap();
343     }
344 
345     /** Sets the error message to be shown if the key had duplicate non-equal bindings. */
updateDuplicateKeyMessage(K k, String errMsg)346     void updateDuplicateKeyMessage(K k, String errMsg) {
347       duplicateKeyErrorMessages.put(k, errMsg);
348     }
349 
350     @Override
permitDuplicates()351     public MapBinder<K, V> permitDuplicates() {
352       entrySetBinder.permitDuplicates();
353       binder.install(new MultimapBinder<K, V>(
354           multimapKey, providerMultimapKey, entrySetBinder.getSetKey()));
355       return this;
356     }
357 
getKeyForNewValue(K key)358     Key<V> getKeyForNewValue(K key) {
359       checkNotNull(key, "key");
360       checkConfiguration(!isInitialized(), "MapBinder was already initialized");
361 
362       Key<V> valueKey = Key.get(valueType,
363           new RealElement(entrySetBinder.getSetName(), MAPBINDER, keyType.toString()));
364       entrySetBinder.addBinding().toProvider(new ProviderMapEntry<K, V>(
365           key, binder.getProvider(valueKey), valueKey));
366       return valueKey;
367     }
368 
369     /**
370      * This creates two bindings. One for the {@code Map.Entry<K, Provider<V>>}
371      * and another for {@code V}.
372      */
addBinding(K key)373     @Override public LinkedBindingBuilder<V> addBinding(K key) {
374       return binder.bind(getKeyForNewValue(key));
375     }
376 
configure(Binder binder)377     @Override public void configure(Binder binder) {
378       checkConfiguration(!isInitialized(), "MapBinder was already initialized");
379 
380       ImmutableSet<Dependency<?>> dependencies
381           = ImmutableSet.<Dependency<?>>of(Dependency.get(entrySetBinder.getSetKey()));
382 
383       // Binds a Map<K, Provider<V>> from a collection of Set<Entry<K, Provider<V>>.
384       Provider<Set<Entry<K, Provider<V>>>> entrySetProvider = binder
385           .getProvider(entrySetBinder.getSetKey());
386 
387       binder.bind(providerMapKey).toProvider(
388           new RealProviderMapProvider(dependencies, entrySetProvider));
389 
390       // The map this exposes is internally an ImmutableMap, so it's OK to massage
391       // the guice Provider to javax Provider in the value (since Guice provider
392       // implements javax Provider).
393       @SuppressWarnings("unchecked")
394       Key massagedProviderMapKey = (Key)providerMapKey;
395       binder.bind(javaxProviderMapKey).to(massagedProviderMapKey);
396 
397       Provider<Map<K, Provider<V>>> mapProvider = binder.getProvider(providerMapKey);
398       binder.bind(mapKey).toProvider(new RealMapProvider(dependencies, mapProvider));
399     }
400 
containsElement(Element element)401     boolean containsElement(Element element) {
402       if (entrySetBinder.containsElement(element)) {
403         return true;
404       } else {
405         Key<?> key;
406         if (element instanceof Binding) {
407           key = ((Binding<?>)element).getKey();
408         } else if (element instanceof ProviderLookup) {
409           key = ((ProviderLookup<?>)element).getKey();
410         } else {
411           return false; // cannot match;
412         }
413 
414         return key.equals(mapKey)
415             || key.equals(providerMapKey)
416             || key.equals(javaxProviderMapKey)
417             || key.equals(multimapKey)
418             || key.equals(providerMultimapKey)
419             || key.equals(entrySetBinder.getSetKey())
420             || matchesValueKey(key);
421         }
422     }
423 
424     /** Returns true if the key indicates this is a value in the map. */
matchesValueKey(Key<?> key)425     private boolean matchesValueKey(Key<?> key) {
426       return key.getAnnotation() instanceof RealElement
427           && ((RealElement) key.getAnnotation()).setName().equals(entrySetBinder.getSetName())
428           && ((RealElement) key.getAnnotation()).type() == MAPBINDER
429           && ((RealElement) key.getAnnotation()).keyType().equals(keyType.toString())
430           && key.getTypeLiteral().equals(valueType);
431     }
432 
isInitialized()433     private boolean isInitialized() {
434       return binder == null;
435     }
436 
equals(Object o)437     @Override public boolean equals(Object o) {
438       return o instanceof RealMapBinder
439           && ((RealMapBinder<?, ?>) o).mapKey.equals(mapKey);
440     }
441 
hashCode()442     @Override public int hashCode() {
443       return mapKey.hashCode();
444     }
445 
446     final class RealProviderMapProvider
447         extends RealMapBinderProviderWithDependencies<Map<K, Provider<V>>> {
448       private final ImmutableSet<Dependency<?>> dependencies;
449       private final Provider<Set<Entry<K, Provider<V>>>> entrySetProvider;
450       private Map<K, Provider<V>> providerMap;
451 
RealProviderMapProvider( ImmutableSet<Dependency<?>> dependencies, Provider<Set<Entry<K, Provider<V>>>> entrySetProvider)452       private RealProviderMapProvider(
453           ImmutableSet<Dependency<?>> dependencies,
454           Provider<Set<Entry<K, Provider<V>>>> entrySetProvider) {
455         super(mapKey);
456         this.dependencies = dependencies;
457         this.entrySetProvider = entrySetProvider;
458       }
459 
initialize(Injector injector)460       @Toolable @Inject void initialize(Injector injector) {
461         RealMapBinder.this.binder = null;
462         permitDuplicates = entrySetBinder.permitsDuplicates(injector);
463 
464         Map<K, Provider<V>> providerMapMutable = new LinkedHashMap<K, Provider<V>>();
465         List<Map.Entry<K, Binding<V>>> bindingsMutable = Lists.newArrayList();
466         Indexer indexer = new Indexer(injector);
467         Multimap<K, IndexedBinding> index = HashMultimap.create();
468         Set<K> duplicateKeys = null;
469         for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
470           ProviderMapEntry<K, V> providerEntry = (ProviderMapEntry<K, V>) entry;
471           Key<V> valueKey = providerEntry.getValueKey();
472           Binding<V> valueBinding = injector.getBinding(valueKey);
473           // If this isn't a dup due to an exact same binding, add it.
474           if (index.put(providerEntry.getKey(), valueBinding.acceptTargetVisitor(indexer))) {
475             Provider<V> previous = providerMapMutable.put(providerEntry.getKey(),
476                 new ValueProvider<V>(providerEntry.getValue(), valueBinding));
477             if (previous != null && !permitDuplicates) {
478               if (duplicateKeys == null) {
479                 duplicateKeys = Sets.newHashSet();
480               }
481               duplicateKeys.add(providerEntry.getKey());
482             }
483             bindingsMutable.add(Maps.immutableEntry(providerEntry.getKey(), valueBinding));
484           }
485         }
486         if (duplicateKeys != null) {
487           // Must use a ListMultimap in case more than one binding has the same source
488           // and is listed multiple times.
489           Multimap<K, String> dups = newLinkedKeyArrayValueMultimap();
490           for (Map.Entry<K, Binding<V>> entry : bindingsMutable) {
491             if (duplicateKeys.contains(entry.getKey())) {
492               dups.put(entry.getKey(), "\t at " + Errors.convert(entry.getValue().getSource()));
493             }
494           }
495           StringBuilder sb = new StringBuilder("Map injection failed due to duplicated key ");
496           boolean first = true;
497           for (K key : dups.keySet()) {
498             if (first) {
499               first = false;
500               if (duplicateKeyErrorMessages.containsKey(key)) {
501                 sb.setLength(0);
502                 sb.append(duplicateKeyErrorMessages.get(key));
503               } else {
504                 sb.append("\"" + key + "\", from bindings:\n");
505               }
506             } else {
507               if (duplicateKeyErrorMessages.containsKey(key)) {
508                 sb.append("\n and " + duplicateKeyErrorMessages.get(key));
509               } else {
510                 sb.append("\n and key: \"" + key + "\", from bindings:\n");
511               }
512             }
513             Joiner.on('\n').appendTo(sb, dups.get(key)).append("\n");
514           }
515           checkConfiguration(false, sb.toString());
516         }
517 
518         providerMap = ImmutableMap.copyOf(providerMapMutable);
519         mapBindings = ImmutableList.copyOf(bindingsMutable);
520       }
521 
get()522       @Override public Map<K, Provider<V>> get() {
523         return providerMap;
524       }
525 
getDependencies()526       @Override public Set<Dependency<?>> getDependencies() {
527         return dependencies;
528       }
529     }
530 
531     final class RealMapProvider extends RealMapWithExtensionProvider<Map<K, V>> {
532       private final ImmutableSet<Dependency<?>> dependencies;
533       private final Provider<Map<K, Provider<V>>> mapProvider;
534 
RealMapProvider( ImmutableSet<Dependency<?>> dependencies, Provider<Map<K, Provider<V>>> mapProvider)535       private RealMapProvider(
536           ImmutableSet<Dependency<?>> dependencies,
537           Provider<Map<K, Provider<V>>> mapProvider) {
538         super(mapKey);
539         this.dependencies = dependencies;
540         this.mapProvider = mapProvider;
541       }
542 
get()543       @Override public Map<K, V> get() {
544         // We can initialize the internal table efficiently this way and then swap the values
545         // one by one.
546         Map<K, Object> map = new LinkedHashMap<K, Object>(mapProvider.get());
547         for (Entry<K, Object> entry : map.entrySet()) {
548           @SuppressWarnings("unchecked")  // we initialized the entries with providers
549           ValueProvider<V> provider = (ValueProvider<V>)entry.getValue();
550           V value = provider.get();
551           checkConfiguration(value != null,
552               "Map injection failed due to null value for key \"%s\", bound at: %s",
553               entry.getKey(),
554               provider.getValueBinding().getSource());
555           entry.setValue(value);
556         }
557         @SuppressWarnings("unchecked")  // if we exited the loop then we replaced all Providers
558         Map<K, V> typedMap = (Map<K, V>) map;
559         return Collections.unmodifiableMap(typedMap);
560       }
561 
getDependencies()562       @Override public Set<Dependency<?>> getDependencies() {
563         return dependencies;
564       }
565 
566       @SuppressWarnings("unchecked")
567       @Override
acceptExtensionVisitor(BindingTargetVisitor<B, R> visitor, ProviderInstanceBinding<? extends B> binding)568       public <B, R> R acceptExtensionVisitor(BindingTargetVisitor<B, R> visitor,
569           ProviderInstanceBinding<? extends B> binding) {
570         if (visitor instanceof MultibindingsTargetVisitor) {
571           return ((MultibindingsTargetVisitor<Map<K, V>, R>)visitor).visit(this);
572         } else {
573           return visitor.visit(binding);
574         }
575       }
576 
getMapKey()577       @Override public Key<Map<K, V>> getMapKey() {
578         return mapKey;
579       }
580 
getKeyTypeLiteral()581       @Override public TypeLiteral<?> getKeyTypeLiteral() {
582         return keyType;
583       }
584 
getValueTypeLiteral()585       @Override public TypeLiteral<?> getValueTypeLiteral() {
586         return valueType;
587       }
588 
589       @SuppressWarnings("unchecked")
590       @Override
getEntries()591       public List<Entry<?, Binding<?>>> getEntries() {
592         if (isInitialized()) {
593           return (List)mapBindings; // safe because mapBindings is immutable
594         } else {
595           throw new UnsupportedOperationException(
596               "getElements() not supported for module bindings");
597         }
598       }
599 
permitsDuplicates()600       @Override public boolean permitsDuplicates() {
601         if (isInitialized()) {
602           return permitDuplicates;
603         } else {
604           throw new UnsupportedOperationException(
605               "permitsDuplicates() not supported for module bindings");
606         }
607       }
608 
containsElement(Element element)609       @Override public boolean containsElement(Element element) {
610         return RealMapBinder.this.containsElement(element);
611       }
612     }
613 
614     /**
615      * Binds {@code Map<K, Set<V>>} and {{@code Map<K, Set<Provider<V>>>}.
616      */
617     static final class MultimapBinder<K, V> implements Module {
618 
619       private final Key<Map<K, Set<V>>> multimapKey;
620       private final Key<Map<K, Set<Provider<V>>>> providerMultimapKey;
621       private final Key<Set<Entry<K,Provider<V>>>> entrySetKey;
622 
MultimapBinder( Key<Map<K, Set<V>>> multimapKey, Key<Map<K, Set<Provider<V>>>> providerMultimapKey, Key<Set<Entry<K,Provider<V>>>> entrySetKey)623       public MultimapBinder(
624           Key<Map<K, Set<V>>> multimapKey,
625           Key<Map<K, Set<Provider<V>>>> providerMultimapKey,
626           Key<Set<Entry<K,Provider<V>>>> entrySetKey) {
627         this.multimapKey = multimapKey;
628         this.providerMultimapKey = providerMultimapKey;
629         this.entrySetKey = entrySetKey;
630       }
631 
configure(Binder binder)632       @Override public void configure(Binder binder) {
633         ImmutableSet<Dependency<?>> dependencies
634             = ImmutableSet.<Dependency<?>>of(Dependency.get(entrySetKey));
635 
636         Provider<Set<Entry<K, Provider<V>>>> entrySetProvider =
637             binder.getProvider(entrySetKey);
638         // Binds a Map<K, Set<Provider<V>>> from a collection of Map<Entry<K, Provider<V>> if
639         // permitDuplicates was called.
640         binder.bind(providerMultimapKey).toProvider(
641             new RealProviderMultimapProvider(dependencies, entrySetProvider));
642 
643         Provider<Map<K, Set<Provider<V>>>> multimapProvider =
644             binder.getProvider(providerMultimapKey);
645         binder.bind(multimapKey).toProvider(
646             new RealMultimapProvider(dependencies, multimapProvider));
647       }
648 
hashCode()649       @Override public int hashCode() {
650         return multimapKey.hashCode();
651       }
652 
equals(Object o)653       @Override public boolean equals(Object o) {
654         return o instanceof MultimapBinder
655             && ((MultimapBinder<?, ?>) o).multimapKey.equals(multimapKey);
656       }
657 
658       final class RealProviderMultimapProvider
659           extends RealMapBinderProviderWithDependencies<Map<K, Set<Provider<V>>>> {
660         private final ImmutableSet<Dependency<?>> dependencies;
661         private final Provider<Set<Entry<K, Provider<V>>>> entrySetProvider;
662         private Map<K, Set<Provider<V>>> providerMultimap;
663 
RealProviderMultimapProvider(ImmutableSet<Dependency<?>> dependencies, Provider<Set<Entry<K, Provider<V>>>> entrySetProvider)664         private RealProviderMultimapProvider(ImmutableSet<Dependency<?>> dependencies,
665             Provider<Set<Entry<K, Provider<V>>>> entrySetProvider) {
666           super(multimapKey);
667           this.dependencies = dependencies;
668           this.entrySetProvider = entrySetProvider;
669         }
670 
671         @SuppressWarnings("unused")
initialize(Injector injector)672         @Inject void initialize(Injector injector) {
673           Map<K, ImmutableSet.Builder<Provider<V>>> providerMultimapMutable =
674               new LinkedHashMap<K, ImmutableSet.Builder<Provider<V>>>();
675           for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
676             if (!providerMultimapMutable.containsKey(entry.getKey())) {
677               providerMultimapMutable.put(
678                   entry.getKey(), ImmutableSet.<Provider<V>>builder());
679             }
680             providerMultimapMutable.get(entry.getKey()).add(entry.getValue());
681           }
682 
683           ImmutableMap.Builder<K, Set<Provider<V>>> providerMultimapBuilder =
684               ImmutableMap.builder();
685           for (Entry<K, ImmutableSet.Builder<Provider<V>>> entry
686               : providerMultimapMutable.entrySet()) {
687             providerMultimapBuilder.put(entry.getKey(), entry.getValue().build());
688           }
689           providerMultimap = providerMultimapBuilder.build();
690         }
691 
get()692         @Override public Map<K, Set<Provider<V>>> get() {
693           return providerMultimap;
694         }
695 
getDependencies()696         @Override public Set<Dependency<?>> getDependencies() {
697           return dependencies;
698         }
699       }
700 
701       final class RealMultimapProvider
702           extends RealMapBinderProviderWithDependencies<Map<K, Set<V>>> {
703         private final ImmutableSet<Dependency<?>> dependencies;
704         private final Provider<Map<K, Set<Provider<V>>>> multimapProvider;
705 
RealMultimapProvider( ImmutableSet<Dependency<?>> dependencies, Provider<Map<K, Set<Provider<V>>>> multimapProvider)706         RealMultimapProvider(
707             ImmutableSet<Dependency<?>> dependencies,
708             Provider<Map<K, Set<Provider<V>>>> multimapProvider) {
709           super(multimapKey);
710           this.dependencies = dependencies;
711           this.multimapProvider = multimapProvider;
712         }
713 
get()714         @Override public Map<K, Set<V>> get() {
715           ImmutableMap.Builder<K, Set<V>> multimapBuilder = ImmutableMap.builder();
716           for (Entry<K, Set<Provider<V>>> entry : multimapProvider.get().entrySet()) {
717             K key = entry.getKey();
718             ImmutableSet.Builder<V> valuesBuilder = ImmutableSet.builder();
719             for (Provider<V> valueProvider : entry.getValue()) {
720               V value = valueProvider.get();
721               checkConfiguration(value != null,
722                   "Multimap injection failed due to null value for key \"%s\"", key);
723               valuesBuilder.add(value);
724             }
725             multimapBuilder.put(key, valuesBuilder.build());
726           }
727           return multimapBuilder.build();
728         }
729 
getDependencies()730         @Override public Set<Dependency<?>> getDependencies() {
731           return dependencies;
732         }
733       }
734     }
735 
736     static final class ValueProvider<V> implements Provider<V> {
737       private final Provider<V> delegate;
738       private final Binding<V> binding;
739 
ValueProvider(Provider<V> delegate, Binding<V> binding)740       ValueProvider(Provider<V> delegate, Binding<V> binding) {
741         this.delegate = delegate;
742         this.binding = binding;
743       }
744 
get()745       @Override public V get() {
746         return delegate.get();
747       }
748 
getValueBinding()749       public Binding<V> getValueBinding() {
750         return binding;
751       }
752     }
753 
754     /**
755      * A Provider that Map.Entry that is also a Provider.  The key is the entry in the
756      * map this corresponds to and the value is the provider of the user's binding.
757      * This returns itself as the Provider.get value.
758      */
759     static final class ProviderMapEntry<K, V> implements
760         ProviderWithDependencies<Map.Entry<K, Provider<V>>>, Map.Entry<K, Provider<V>> {
761       private final K key;
762       private final Provider<V> provider;
763       private final Key<V> valueKey;
764 
ProviderMapEntry(K key, Provider<V> provider, Key<V> valueKey)765       private ProviderMapEntry(K key, Provider<V> provider, Key<V> valueKey) {
766         this.key = key;
767         this.provider = provider;
768         this.valueKey = valueKey;
769       }
770 
get()771       @Override public Entry<K, Provider<V>> get() {
772         return this;
773       }
774 
getDependencies()775       @Override public Set<Dependency<?>> getDependencies() {
776         return ((HasDependencies) provider).getDependencies();
777       }
778 
getValueKey()779       public Key<V> getValueKey() {
780         return valueKey;
781       }
782 
getKey()783       @Override public K getKey() {
784         return key;
785       }
786 
getValue()787       @Override public Provider<V> getValue() {
788         return provider;
789       }
790 
setValue(Provider<V> value)791       @Override public Provider<V> setValue(Provider<V> value) {
792         throw new UnsupportedOperationException();
793       }
794 
equals(Object obj)795        @Override public boolean equals(Object obj) {
796          if (obj instanceof Map.Entry) {
797            Map.Entry o = (Map.Entry)obj;
798            return Objects.equal(key, o.getKey())
799                && Objects.equal(provider, o.getValue());
800          }
801          return false;
802       }
803 
hashCode()804       @Override public int hashCode() {
805         return key.hashCode() ^ provider.hashCode();
806       }
807 
toString()808       @Override public String toString() {
809         return "ProviderMapEntry(" + key + ", " + provider + ")";
810       }
811     }
812 
813     private static abstract class RealMapWithExtensionProvider<T>
814         extends RealMapBinderProviderWithDependencies<T>
815         implements ProviderWithExtensionVisitor<T>, MapBinderBinding<T> {
RealMapWithExtensionProvider(Object equality)816       public RealMapWithExtensionProvider(Object equality) {
817         super(equality);
818       }
819     }
820 
821     /**
822      * A base class for ProviderWithDependencies that need equality
823      * based on a specific object.
824      */
825     private static abstract class RealMapBinderProviderWithDependencies<T> implements ProviderWithDependencies<T> {
826       private final Object equality;
827 
RealMapBinderProviderWithDependencies(Object equality)828       public RealMapBinderProviderWithDependencies(Object equality) {
829         this.equality = equality;
830       }
831 
832       @Override
equals(Object obj)833       public boolean equals(Object obj) {
834         return this.getClass() == obj.getClass() &&
835           equality.equals(((RealMapBinderProviderWithDependencies<?>)obj).equality);
836       }
837 
838       @Override
hashCode()839       public int hashCode() {
840         return equality.hashCode();
841       }
842     }
843 
newLinkedKeyArrayValueMultimap()844     private Multimap<K, String> newLinkedKeyArrayValueMultimap() {
845       return Multimaps.newListMultimap(
846           new LinkedHashMap<K, Collection<String>>(),
847           new Supplier<List<String>>() {
848             @Override public List<String> get() {
849               return Lists.newArrayList();
850             }
851           });
852     }
853   }
854 }
855