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<String, Snack> 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<String, Snack> 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<String, Provider<Snack>> 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<K, V>, 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