blob: 89df771377aec45d4b1d1fdf4117cd77a17b0c4e [file] [log] [blame]
limpbizkitc75363a2008-05-13 07:16:26 +00001/**
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
17package com.google.inject.multibindings;
18
Sam Berlin21a19672012-01-21 11:06:49 -050019import static com.google.inject.multibindings.Element.Type.MAPBINDER;
sberlinb7a02b02011-07-08 00:34:16 +000020import static com.google.inject.multibindings.Multibinder.checkConfiguration;
21import static com.google.inject.multibindings.Multibinder.checkNotNull;
22import static com.google.inject.multibindings.Multibinder.setOf;
Sam Berlin3338a482013-12-06 17:07:34 -050023import static com.google.inject.util.Types.newParameterizedType;
sberlinb7a02b02011-07-08 00:34:16 +000024import static com.google.inject.util.Types.newParameterizedTypeWithOwner;
25
Sam Berlin88594562014-03-10 13:58:41 -040026import com.google.common.base.Joiner;
Sam Berlinc34e0182014-08-06 11:56:26 -040027import com.google.common.base.Objects;
28import com.google.common.base.Supplier;
29import com.google.common.collect.HashMultimap;
sberlinb7a02b02011-07-08 00:34:16 +000030import com.google.common.collect.ImmutableList;
31import com.google.common.collect.ImmutableMap;
32import com.google.common.collect.ImmutableSet;
33import com.google.common.collect.Lists;
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -070034import com.google.common.collect.Maps;
Sam Berlin88594562014-03-10 13:58:41 -040035import com.google.common.collect.Multimap;
Christian Edward Gruberd1d7ef32014-04-01 15:10:51 -070036import com.google.common.collect.Multimaps;
Christian Edward Grubercade8972014-04-01 15:07:02 -070037import com.google.common.collect.Sets;
limpbizkit9532e622008-06-18 08:20:54 +000038import com.google.inject.Binder;
sberlin75fcf6f2010-09-20 00:42:24 +000039import com.google.inject.Binding;
limpbizkit9532e622008-06-18 08:20:54 +000040import com.google.inject.Inject;
limpbizkit398017a2009-06-23 06:30:37 +000041import com.google.inject.Injector;
limpbizkit9532e622008-06-18 08:20:54 +000042import com.google.inject.Key;
43import com.google.inject.Module;
44import com.google.inject.Provider;
45import com.google.inject.TypeLiteral;
limpbizkitc75363a2008-05-13 07:16:26 +000046import com.google.inject.binder.LinkedBindingBuilder;
Christian Edward Grubercade8972014-04-01 15:07:02 -070047import com.google.inject.internal.Errors;
Sam Berlinc34e0182014-08-06 11:56:26 -040048import com.google.inject.multibindings.Indexer.IndexedBinding;
limpbizkitc75363a2008-05-13 07:16:26 +000049import com.google.inject.multibindings.Multibinder.RealMultibinder;
sberlin75fcf6f2010-09-20 00:42:24 +000050import com.google.inject.spi.BindingTargetVisitor;
limpbizkitddb38622008-12-29 05:21:16 +000051import com.google.inject.spi.Dependency;
Sam Berlinc34e0182014-08-06 11:56:26 -040052import com.google.inject.spi.Element;
Christian Edward Grubercade8972014-04-01 15:07:02 -070053import com.google.inject.spi.HasDependencies;
sberlin75fcf6f2010-09-20 00:42:24 +000054import com.google.inject.spi.ProviderInstanceBinding;
55import com.google.inject.spi.ProviderLookup;
limpbizkitddb38622008-12-29 05:21:16 +000056import com.google.inject.spi.ProviderWithDependencies;
sberlin75fcf6f2010-09-20 00:42:24 +000057import com.google.inject.spi.ProviderWithExtensionVisitor;
58import com.google.inject.spi.Toolable;
limpbizkit9532e622008-06-18 08:20:54 +000059import com.google.inject.util.Types;
sberlinb7a02b02011-07-08 00:34:16 +000060
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -070061import java.lang.annotation.Annotation;
Christian Edward Gruberd1d7ef32014-04-01 15:10:51 -070062import java.util.Collection;
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -070063import java.util.Collections;
64import java.util.LinkedHashMap;
65import java.util.List;
66import java.util.Map;
67import java.util.Map.Entry;
68import java.util.Set;
69
limpbizkitc75363a2008-05-13 07:16:26 +000070/**
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 *
netdpb0efcc6c2009-07-07 20:13:32 +000084 * <p>With this binding, a {@link Map}{@code <String, Snack>} can now be
limpbizkitc75363a2008-05-13 07:16:26 +000085 * injected:
86 * <pre><code>
87 * class SnackMachine {
88 * {@literal @}Inject
89 * public SnackMachine(Map&lt;String, Snack&gt; snacks) { ... }
90 * }</code></pre>
netdpb0efcc6c2009-07-07 20:13:32 +000091 *
limpbizkitc75363a2008-05-13 07:16:26 +000092 * <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 *
limpbizkit0e23eb02009-10-12 16:17:34 +0000100 * <p>Contributing mapbindings from different modules is supported. For example,
101 * it is okay to have both {@code CandyModule} and {@code ChipsModule} both
netdpb0efcc6c2009-07-07 20:13:32 +0000102 * 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
limpbizkitc75363a2008-05-13 07:16:26 +0000104 * entries from both modules.
105 *
limpbizkit0e23eb02009-10-12 16:17:34 +0000106 * <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.
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700111 *
sberlin6542fdb2010-10-25 03:47:17 +0000112 * <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.
limpbizkit0e23eb02009-10-12 16:17:34 +0000114 *
limpbizkitc75363a2008-05-13 07:16:26 +0000115 * <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
limpbizkit4994bf62008-12-27 02:54:59 +0000117 * injected (unless the binding is also scoped, or a map of providers is injected).
limpbizkitc75363a2008-05-13 07:16:26 +0000118 *
limpbizkit4994bf62008-12-27 02:54:59 +0000119 * <p>Annotations are used to create different maps of the same key/value
limpbizkitc75363a2008-05-13 07:16:26 +0000120 * 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
netdpb0efcc6c2009-07-07 20:13:32 +0000123 * 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.
limpbizkitc75363a2008-05-13 07:16:26 +0000126 *
netdpb0efcc6c2009-07-07 20:13:32 +0000127 * <p><strong>Keys must be non-null.</strong> {@code addBinding(null)} will
limpbizkitc75363a2008-05-13 07:16:26 +0000128 * 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)
limpbizkitc75363a2008-05-13 07:16:26 +0000135 */
136public abstract class MapBinder<K, V> {
137 private MapBinder() {}
limpbizkit9532e622008-06-18 08:20:54 +0000138
limpbizkitc75363a2008-05-13 07:16:26 +0000139 /**
limpbizkitcfa95ae2008-11-30 19:52:02 +0000140 * 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.
limpbizkitc75363a2008-05-13 07:16:26 +0000142 */
netdpb0efcc6c2009-07-07 20:13:32 +0000143 public static <K, V> MapBinder<K, V> newMapBinder(Binder binder,
limpbizkitcfa95ae2008-11-30 19:52:02 +0000144 TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
limpbizkit6663d022008-06-19 07:57:55 +0000145 binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
flanf6189602014-11-04 07:32:47 -0800146 return newMapBinder(binder, keyType, valueType, Key.get(mapOf(keyType, valueType)),
limpbizkitcfa95ae2008-11-30 19:52:02 +0000147 Multibinder.newSetBinder(binder, entryOfProviderOf(keyType, valueType)));
limpbizkitc75363a2008-05-13 07:16:26 +0000148 }
149
150 /**
limpbizkitcfa95ae2008-11-30 19:52:02 +0000151 * 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.
limpbizkitc75363a2008-05-13 07:16:26 +0000153 */
limpbizkitcfa95ae2008-11-30 19:52:02 +0000154 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));
limpbizkitc75363a2008-05-13 07:16:26 +0000157 }
158
159 /**
limpbizkitcfa95ae2008-11-30 19:52:02 +0000160 * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a
161 * {@link Map} that is itself bound with {@code annotation}.
limpbizkitc75363a2008-05-13 07:16:26 +0000162 */
netdpb0efcc6c2009-07-07 20:13:32 +0000163 public static <K, V> MapBinder<K, V> newMapBinder(Binder binder,
limpbizkitcfa95ae2008-11-30 19:52:02 +0000164 TypeLiteral<K> keyType, TypeLiteral<V> valueType, Annotation annotation) {
limpbizkit6663d022008-06-19 07:57:55 +0000165 binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
sberlin75fcf6f2010-09-20 00:42:24 +0000166 return newMapBinder(binder, keyType, valueType,
limpbizkitcfa95ae2008-11-30 19:52:02 +0000167 Key.get(mapOf(keyType, valueType), annotation),
limpbizkitcfa95ae2008-11-30 19:52:02 +0000168 Multibinder.newSetBinder(binder, entryOfProviderOf(keyType, valueType), annotation));
limpbizkitc75363a2008-05-13 07:16:26 +0000169 }
170
limpbizkitcfa95ae2008-11-30 19:52:02 +0000171 /**
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 */
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);
limpbizkitc75363a2008-05-13 07:16:26 +0000178 }
179
limpbizkitcfa95ae2008-11-30 19:52:02 +0000180 /**
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 */
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);
sberlin75fcf6f2010-09-20 00:42:24 +0000187 return newMapBinder(binder, keyType, valueType,
limpbizkitcfa95ae2008-11-30 19:52:02 +0000188 Key.get(mapOf(keyType, valueType), annotationType),
limpbizkitcfa95ae2008-11-30 19:52:02 +0000189 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 */
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>
sberlin75fcf6f2010-09-20 00:42:24 +0000203 static <K, V> TypeLiteral<Map<K, V>> mapOf(
limpbizkitcfa95ae2008-11-30 19:52:02 +0000204 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>>
sberlin75fcf6f2010-09-20 00:42:24 +0000210 static <K, V> TypeLiteral<Map<K, Provider<V>>> mapOfProviderOf(
limpbizkitcfa95ae2008-11-30 19:52:02 +0000211 TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
212 return (TypeLiteral<Map<K, Provider<V>>>) TypeLiteral.get(
netdpbfb3a8962009-07-08 19:49:54 +0000213 Types.mapOf(keyType.getType(), Types.providerOf(valueType.getType())));
limpbizkitc75363a2008-05-13 07:16:26 +0000214 }
Sam Berlin3338a482013-12-06 17:07:34 -0500215
216 // provider map <K, V> is safely a Map<K, javax.inject.Provider<V>>>
217 @SuppressWarnings("unchecked")
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 }
netdpb0efcc6c2009-07-07 20:13:32 +0000224
225 @SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
sberlin75fcf6f2010-09-20 00:42:24 +0000226 static <K, V> TypeLiteral<Map<K, Set<Provider<V>>>> mapOfSetOfProviderOf(
netdpb0efcc6c2009-07-07 20:13:32 +0000227 TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
228 return (TypeLiteral<Map<K, Set<Provider<V>>>>) TypeLiteral.get(
netdpbfb3a8962009-07-08 19:49:54 +0000229 Types.mapOf(keyType.getType(), Types.setOf(Types.providerOf(valueType.getType()))));
netdpb0efcc6c2009-07-07 20:13:32 +0000230 }
231
limpbizkitcfa95ae2008-11-30 19:52:02 +0000232 @SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
sberlin75fcf6f2010-09-20 00:42:24 +0000233 static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfProviderOf(
limpbizkitcfa95ae2008-11-30 19:52:02 +0000234 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())));
limpbizkite97e15b2008-05-16 14:53:49 +0000237 }
limpbizkitc75363a2008-05-13 07:16:26 +0000238
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700239 private static <K, V> MapBinder<K, V> newMapBinder(Binder binder,
flanf6189602014-11-04 07:32:47 -0800240 TypeLiteral<K> keyType, TypeLiteral<V> valueType, Key<Map<K, V>> mapKey,
limpbizkite97e15b2008-05-16 14:53:49 +0000241 Multibinder<Entry<K, Provider<V>>> entrySetBinder) {
flanf6189602014-11-04 07:32:47 -0800242 RealMapBinder<K, V> mapBinder =
243 new RealMapBinder<K, V>(binder, keyType, valueType, mapKey, entrySetBinder);
limpbizkit6663d022008-06-19 07:57:55 +0000244 binder.install(mapBinder);
limpbizkite97e15b2008-05-16 14:53:49 +0000245 return mapBinder;
limpbizkitc75363a2008-05-13 07:16:26 +0000246 }
247
248 /**
netdpb0efcc6c2009-07-07 20:13:32 +0000249 * Configures the {@code MapBinder} to handle duplicate entries.
netdpbfb3a8962009-07-08 19:49:54 +0000250 * <p>When multiple equal keys are bound, the value that gets included in the map is
251 * arbitrary.
252 * <p>In addition to the {@code Map<K, V>} and {@code Map<K, Provider<V>>}
netdpb0efcc6c2009-07-07 20:13:32 +0000253 * maps that are normally bound, a {@code Map<K, Set<V>>} and
254 * {@code Map<K, Set<Provider<V>>>} are <em>also</em> bound, which contain
netdpbfb3a8962009-07-08 19:49:54 +0000255 * all values bound to each key.
netdpb0efcc6c2009-07-07 20:13:32 +0000256 * <p>
257 * When multiple modules contribute elements to the map, this configuration
258 * option impacts all of them.
limpbizkit398017a2009-06-23 06:30:37 +0000259 *
260 * @return this map binder
sberlinc13b5452010-10-31 18:38:24 +0000261 * @since 3.0
limpbizkit398017a2009-06-23 06:30:37 +0000262 */
263 public abstract MapBinder<K, V> permitDuplicates();
264
265 /**
limpbizkitc75363a2008-05-13 07:16:26 +0000266 * Returns a binding builder used to add a new entry in the map. Each
267 * key must be distinct (and non-null). Bound providers will be evaluated each
268 * time the map is injected.
269 *
270 * <p>It is an error to call this method without also calling one of the
271 * {@code to} methods on the returned binding builder.
272 *
273 * <p>Scoping elements independently is supported. Use the {@code in} method
274 * to specify a binding scope.
275 */
276 public abstract LinkedBindingBuilder<V> addBinding(K key);
277
278 /**
279 * The actual mapbinder plays several roles:
280 *
281 * <p>As a MapBinder, it acts as a factory for LinkedBindingBuilders for
282 * each of the map's values. It delegates to a {@link Multibinder} of
283 * entries (keys to value providers).
284 *
285 * <p>As a Module, it installs the binding to the map itself, as well as to
netdpb0efcc6c2009-07-07 20:13:32 +0000286 * a corresponding map whose values are providers. It uses the entry set
limpbizkitc75363a2008-05-13 07:16:26 +0000287 * multibinder to construct the map and the provider map.
netdpb0efcc6c2009-07-07 20:13:32 +0000288 *
289 * <p>As a module, this implements equals() and hashcode() in order to trick
290 * Guice into executing its configure() method only once. That makes it so
limpbizkitc75363a2008-05-13 07:16:26 +0000291 * that multiple mapbinders can be created for the same target map, but
292 * only one is bound. Since the list of bindings is retrieved from the
293 * injector itself (and not the mapbinder), each mapbinder has access to
294 * all contributions from all equivalent mapbinders.
295 *
296 * <p>Rather than binding a single Map.Entry&lt;K, V&gt;, the map binder
297 * binds keys and values independently. This allows the values to be properly
298 * scoped.
299 *
300 * <p>We use a subclass to hide 'implements Module' from the public API.
301 */
Sam Berlin88594562014-03-10 13:58:41 -0400302 static final class RealMapBinder<K, V> extends MapBinder<K, V> implements Module {
sberlin75fcf6f2010-09-20 00:42:24 +0000303 private final TypeLiteral<K> keyType;
limpbizkitcfa95ae2008-11-30 19:52:02 +0000304 private final TypeLiteral<V> valueType;
limpbizkitc75363a2008-05-13 07:16:26 +0000305 private final Key<Map<K, V>> mapKey;
Sam Berlin3338a482013-12-06 17:07:34 -0500306 private final Key<Map<K, javax.inject.Provider<V>>> javaxProviderMapKey;
limpbizkitc75363a2008-05-13 07:16:26 +0000307 private final Key<Map<K, Provider<V>>> providerMapKey;
netdpb0efcc6c2009-07-07 20:13:32 +0000308 private final Key<Map<K, Set<V>>> multimapKey;
309 private final Key<Map<K, Set<Provider<V>>>> providerMultimapKey;
limpbizkite97e15b2008-05-16 14:53:49 +0000310 private final RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder;
Christian Edward Grubercade8972014-04-01 15:07:02 -0700311 private final Map<K, String> duplicateKeyErrorMessages;
limpbizkit9532e622008-06-18 08:20:54 +0000312
limpbizkite97e15b2008-05-16 14:53:49 +0000313 /* the target injector's binder. non-null until initialization, null afterwards */
314 private Binder binder;
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700315
sberlin75fcf6f2010-09-20 00:42:24 +0000316 private boolean permitDuplicates;
317 private ImmutableList<Map.Entry<K, Binding<V>>> mapBindings;
limpbizkitc75363a2008-05-13 07:16:26 +0000318
sberlin75fcf6f2010-09-20 00:42:24 +0000319 private RealMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType,
flanf6189602014-11-04 07:32:47 -0800320 Key<Map<K, V>> mapKey, Multibinder<Map.Entry<K, Provider<V>>> entrySetBinder) {
sberlin75fcf6f2010-09-20 00:42:24 +0000321 this.keyType = keyType;
limpbizkite97e15b2008-05-16 14:53:49 +0000322 this.valueType = valueType;
limpbizkitc75363a2008-05-13 07:16:26 +0000323 this.mapKey = mapKey;
flanf6189602014-11-04 07:32:47 -0800324 this.providerMapKey = mapKey.ofType(mapOfProviderOf(keyType, valueType));
325 this.javaxProviderMapKey = mapKey.ofType(mapOfJavaxProviderOf(keyType, valueType));
326 this.multimapKey = mapKey.ofType(mapOf(keyType, setOf(valueType)));
327 this.providerMultimapKey = mapKey.ofType(mapOfSetOfProviderOf(keyType, valueType));
limpbizkite97e15b2008-05-16 14:53:49 +0000328 this.entrySetBinder = (RealMultibinder<Entry<K, Provider<V>>>) entrySetBinder;
329 this.binder = binder;
Christian Edward Grubercade8972014-04-01 15:07:02 -0700330 this.duplicateKeyErrorMessages = Maps.newHashMap();
331 }
332
333 /** Sets the error message to be shown if the key had duplicate non-equal bindings. */
334 void updateDuplicateKeyMessage(K k, String errMsg) {
335 duplicateKeyErrorMessages.put(k, errMsg);
limpbizkitc75363a2008-05-13 07:16:26 +0000336 }
337
netdpb0efcc6c2009-07-07 20:13:32 +0000338 @Override
limpbizkit398017a2009-06-23 06:30:37 +0000339 public MapBinder<K, V> permitDuplicates() {
340 entrySetBinder.permitDuplicates();
netdpbfb3a8962009-07-08 19:49:54 +0000341 binder.install(new MultimapBinder<K, V>(
342 multimapKey, providerMultimapKey, entrySetBinder.getSetKey()));
limpbizkit398017a2009-06-23 06:30:37 +0000343 return this;
344 }
345
limpbizkite97e15b2008-05-16 14:53:49 +0000346 /**
347 * This creates two bindings. One for the {@code Map.Entry<K, Provider<V>>}
348 * and another for {@code V}.
349 */
350 @Override public LinkedBindingBuilder<V> addBinding(K key) {
kevinb9n1601ae52008-06-03 22:21:04 +0000351 checkNotNull(key, "key");
limpbizkit72d11dd2008-11-02 07:59:13 +0000352 checkConfiguration(!isInitialized(), "MapBinder was already initialized");
limpbizkite97e15b2008-05-16 14:53:49 +0000353
Sam Berlinc34e0182014-08-06 11:56:26 -0400354 Key<V> valueKey = Key.get(valueType,
355 new RealElement(entrySetBinder.getSetName(), MAPBINDER, keyType.toString()));
Christian Edward Grubercade8972014-04-01 15:07:02 -0700356 entrySetBinder.addBinding().toProvider(new ProviderMapEntry<K, V>(
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -0700357 key, binder.getProvider(valueKey), valueKey));
Sam Berlinc34e0182014-08-06 11:56:26 -0400358 return binder.bind(valueKey);
limpbizkitc75363a2008-05-13 07:16:26 +0000359 }
360
Sam Berlinc34e0182014-08-06 11:56:26 -0400361 @Override public void configure(Binder binder) {
limpbizkit72d11dd2008-11-02 07:59:13 +0000362 checkConfiguration(!isInitialized(), "MapBinder was already initialized");
limpbizkite97e15b2008-05-16 14:53:49 +0000363
Sam Berlinca0cc182014-08-06 11:57:22 -0400364 ImmutableSet<Dependency<?>> dependencies
limpbizkitddb38622008-12-29 05:21:16 +0000365 = ImmutableSet.<Dependency<?>>of(Dependency.get(entrySetBinder.getSetKey()));
366
sberlin75fcf6f2010-09-20 00:42:24 +0000367 // Binds a Map<K, Provider<V>> from a collection of Set<Entry<K, Provider<V>>.
Sam Berlinca0cc182014-08-06 11:57:22 -0400368 Provider<Set<Entry<K, Provider<V>>>> entrySetProvider = binder
limpbizkit9532e622008-06-18 08:20:54 +0000369 .getProvider(entrySetBinder.getSetKey());
Sam Berlinca0cc182014-08-06 11:57:22 -0400370
Sam Berlin3338a482013-12-06 17:07:34 -0500371 binder.bind(providerMapKey).toProvider(
Sam Berlinca0cc182014-08-06 11:57:22 -0400372 new RealProviderMapProvider(dependencies, entrySetProvider));
limpbizkit9532e622008-06-18 08:20:54 +0000373
Sam Berlin3338a482013-12-06 17:07:34 -0500374 // The map this exposes is internally an ImmutableMap, so it's OK to massage
375 // the guice Provider to javax Provider in the value (since Guice provider
376 // implements javax Provider).
377 @SuppressWarnings("unchecked")
378 Key massagedProviderMapKey = (Key)providerMapKey;
379 binder.bind(javaxProviderMapKey).to(massagedProviderMapKey);
limpbizkitc75363a2008-05-13 07:16:26 +0000380
Sam Berlinca0cc182014-08-06 11:57:22 -0400381 Provider<Map<K, Provider<V>>> mapProvider = binder.getProvider(providerMapKey);
382 binder.bind(mapKey).toProvider(new RealMapProvider(dependencies, mapProvider));
limpbizkitc75363a2008-05-13 07:16:26 +0000383 }
384
Sam Berlinc34e0182014-08-06 11:56:26 -0400385 boolean containsElement(Element element) {
Christian Edward Grubercade8972014-04-01 15:07:02 -0700386 if (entrySetBinder.containsElement(element)) {
387 return true;
388 } else {
389 Key<?> key;
390 if (element instanceof Binding) {
391 key = ((Binding<?>)element).getKey();
392 } else if (element instanceof ProviderLookup) {
393 key = ((ProviderLookup<?>)element).getKey();
394 } else {
395 return false; // cannot match;
396 }
397
398 return key.equals(mapKey)
399 || key.equals(providerMapKey)
400 || key.equals(javaxProviderMapKey)
401 || key.equals(multimapKey)
402 || key.equals(providerMultimapKey)
403 || key.equals(entrySetBinder.getSetKey())
404 || matchesValueKey(key);
405 }
406 }
407
sberlin75fcf6f2010-09-20 00:42:24 +0000408 /** Returns true if the key indicates this is a value in the map. */
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -0700409 private boolean matchesValueKey(Key<?> key) {
Christian Edward Grubercade8972014-04-01 15:07:02 -0700410 return key.getAnnotation() instanceof RealElement
411 && ((RealElement) key.getAnnotation()).setName().equals(entrySetBinder.getSetName())
412 && ((RealElement) key.getAnnotation()).type() == MAPBINDER
Sam Berlinc34e0182014-08-06 11:56:26 -0400413 && ((RealElement) key.getAnnotation()).keyType().equals(keyType.toString())
sberlin75fcf6f2010-09-20 00:42:24 +0000414 && key.getTypeLiteral().equals(valueType);
415 }
416
limpbizkite97e15b2008-05-16 14:53:49 +0000417 private boolean isInitialized() {
418 return binder == null;
419 }
420
limpbizkitc75363a2008-05-13 07:16:26 +0000421 @Override public boolean equals(Object o) {
422 return o instanceof RealMapBinder
limpbizkite97e15b2008-05-16 14:53:49 +0000423 && ((RealMapBinder<?, ?>) o).mapKey.equals(mapKey);
limpbizkitc75363a2008-05-13 07:16:26 +0000424 }
425
426 @Override public int hashCode() {
427 return mapKey.hashCode();
428 }
limpbizkite97e15b2008-05-16 14:53:49 +0000429
Sam Berlinca0cc182014-08-06 11:57:22 -0400430 final class RealProviderMapProvider
431 extends RealMapBinderProviderWithDependencies<Map<K, Provider<V>>> {
432 private final ImmutableSet<Dependency<?>> dependencies;
433 private final Provider<Set<Entry<K, Provider<V>>>> entrySetProvider;
434 private Map<K, Provider<V>> providerMap;
435
436 private RealProviderMapProvider(
437 ImmutableSet<Dependency<?>> dependencies,
438 Provider<Set<Entry<K, Provider<V>>>> entrySetProvider) {
439 super(mapKey);
440 this.dependencies = dependencies;
441 this.entrySetProvider = entrySetProvider;
442 }
443
444 @Toolable @Inject void initialize(Injector injector) {
445 RealMapBinder.this.binder = null;
446 permitDuplicates = entrySetBinder.permitsDuplicates(injector);
447
448 Map<K, Provider<V>> providerMapMutable = new LinkedHashMap<K, Provider<V>>();
449 List<Map.Entry<K, Binding<V>>> bindingsMutable = Lists.newArrayList();
450 Indexer indexer = new Indexer(injector);
451 Multimap<K, IndexedBinding> index = HashMultimap.create();
452 Set<K> duplicateKeys = null;
453 for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
454 ProviderMapEntry<K, V> providerEntry = (ProviderMapEntry<K, V>) entry;
455 Key<V> valueKey = providerEntry.getValueKey();
456 Binding<V> valueBinding = injector.getBinding(valueKey);
457 // If this isn't a dup due to an exact same binding, add it.
sameb1bf1e9e2014-12-18 14:44:16 -0800458 if (index.put(providerEntry.getKey(), valueBinding.acceptTargetVisitor(indexer))) {
459 Provider<V> previous = providerMapMutable.put(providerEntry.getKey(),
460 new ValueProvider<V>(providerEntry.getValue(), valueBinding));
Sam Berlinca0cc182014-08-06 11:57:22 -0400461 if (previous != null && !permitDuplicates) {
462 if (duplicateKeys == null) {
463 duplicateKeys = Sets.newHashSet();
464 }
sameb1bf1e9e2014-12-18 14:44:16 -0800465 duplicateKeys.add(providerEntry.getKey());
Sam Berlinca0cc182014-08-06 11:57:22 -0400466 }
sameb1bf1e9e2014-12-18 14:44:16 -0800467 bindingsMutable.add(Maps.immutableEntry(providerEntry.getKey(), valueBinding));
Sam Berlinca0cc182014-08-06 11:57:22 -0400468 }
469 }
470 if (duplicateKeys != null) {
471 // Must use a ListMultimap in case more than one binding has the same source
472 // and is listed multiple times.
473 Multimap<K, String> dups = newLinkedKeyArrayValueMultimap();
474 for (Map.Entry<K, Binding<V>> entry : bindingsMutable) {
475 if (duplicateKeys.contains(entry.getKey())) {
476 dups.put(entry.getKey(), "\t at " + Errors.convert(entry.getValue().getSource()));
477 }
478 }
479 StringBuilder sb = new StringBuilder("Map injection failed due to duplicated key ");
480 boolean first = true;
481 for (K key : dups.keySet()) {
482 if (first) {
483 first = false;
484 if (duplicateKeyErrorMessages.containsKey(key)) {
485 sb.setLength(0);
486 sb.append(duplicateKeyErrorMessages.get(key));
487 } else {
488 sb.append("\"" + key + "\", from bindings:\n");
489 }
490 } else {
491 if (duplicateKeyErrorMessages.containsKey(key)) {
492 sb.append("\n and " + duplicateKeyErrorMessages.get(key));
493 } else {
494 sb.append("\n and key: \"" + key + "\", from bindings:\n");
495 }
496 }
497 Joiner.on('\n').appendTo(sb, dups.get(key)).append("\n");
498 }
499 checkConfiguration(false, sb.toString());
500 }
501
502 providerMap = ImmutableMap.copyOf(providerMapMutable);
503 mapBindings = ImmutableList.copyOf(bindingsMutable);
504 }
505
506 @Override public Map<K, Provider<V>> get() {
507 return providerMap;
508 }
509
510 @Override public Set<Dependency<?>> getDependencies() {
511 return dependencies;
512 }
513 }
514
515 final class RealMapProvider extends RealMapWithExtensionProvider<Map<K, V>> {
516 private final ImmutableSet<Dependency<?>> dependencies;
517 private final Provider<Map<K, Provider<V>>> mapProvider;
518
519 private RealMapProvider(
520 ImmutableSet<Dependency<?>> dependencies,
521 Provider<Map<K, Provider<V>>> mapProvider) {
522 super(mapKey);
523 this.dependencies = dependencies;
524 this.mapProvider = mapProvider;
525 }
526
527 @Override public Map<K, V> get() {
lukesb159fc52014-09-12 11:38:41 -0700528 // We can initialize the internal table efficiently this way and then swap the values
529 // one by one.
530 Map<K, Object> map = new LinkedHashMap<K, Object>(mapProvider.get());
531 for (Entry<K, Object> entry : map.entrySet()) {
532 @SuppressWarnings("unchecked") // we initialized the entries with providers
sameb1bf1e9e2014-12-18 14:44:16 -0800533 ValueProvider<V> provider = (ValueProvider<V>)entry.getValue();
534 V value = provider.get();
Sam Berlinca0cc182014-08-06 11:57:22 -0400535 checkConfiguration(value != null,
sameb1bf1e9e2014-12-18 14:44:16 -0800536 "Map injection failed due to null value for key \"%s\", bound at: %s",
537 entry.getKey(),
538 provider.getValueBinding().getSource());
lukesb159fc52014-09-12 11:38:41 -0700539 entry.setValue(value);
Sam Berlinca0cc182014-08-06 11:57:22 -0400540 }
lukesb159fc52014-09-12 11:38:41 -0700541 @SuppressWarnings("unchecked") // if we exited the loop then we replaced all Providers
542 Map<K, V> typedMap = (Map<K, V>) map;
543 return Collections.unmodifiableMap(typedMap);
Sam Berlinca0cc182014-08-06 11:57:22 -0400544 }
545
546 @Override public Set<Dependency<?>> getDependencies() {
547 return dependencies;
548 }
549
550 @SuppressWarnings("unchecked")
551 @Override
552 public <B, R> R acceptExtensionVisitor(BindingTargetVisitor<B, R> visitor,
553 ProviderInstanceBinding<? extends B> binding) {
554 if (visitor instanceof MultibindingsTargetVisitor) {
555 return ((MultibindingsTargetVisitor<Map<K, V>, R>)visitor).visit(this);
556 } else {
557 return visitor.visit(binding);
558 }
559 }
560
561 @Override public Key<Map<K, V>> getMapKey() {
562 return mapKey;
563 }
564
565 @Override public TypeLiteral<?> getKeyTypeLiteral() {
566 return keyType;
567 }
568
569 @Override public TypeLiteral<?> getValueTypeLiteral() {
570 return valueType;
571 }
572
573 @SuppressWarnings("unchecked")
574 @Override
575 public List<Entry<?, Binding<?>>> getEntries() {
576 if (isInitialized()) {
577 return (List)mapBindings; // safe because mapBindings is immutable
578 } else {
579 throw new UnsupportedOperationException(
580 "getElements() not supported for module bindings");
581 }
582 }
583
584 @Override public boolean permitsDuplicates() {
585 if (isInitialized()) {
586 return permitDuplicates;
587 } else {
588 throw new UnsupportedOperationException(
589 "permitsDuplicates() not supported for module bindings");
590 }
591 }
592
593 @Override public boolean containsElement(Element element) {
594 return RealMapBinder.this.containsElement(element);
595 }
596 }
597
netdpbfb3a8962009-07-08 19:49:54 +0000598 /**
599 * Binds {@code Map<K, Set<V>>} and {{@code Map<K, Set<Provider<V>>>}.
600 */
Sam Berlin6dec4412014-08-11 13:23:04 -0400601 static final class MultimapBinder<K, V> implements Module {
netdpbfb3a8962009-07-08 19:49:54 +0000602
603 private final Key<Map<K, Set<V>>> multimapKey;
604 private final Key<Map<K, Set<Provider<V>>>> providerMultimapKey;
605 private final Key<Set<Entry<K,Provider<V>>>> entrySetKey;
606
607 public MultimapBinder(
608 Key<Map<K, Set<V>>> multimapKey,
609 Key<Map<K, Set<Provider<V>>>> providerMultimapKey,
610 Key<Set<Entry<K,Provider<V>>>> entrySetKey) {
611 this.multimapKey = multimapKey;
612 this.providerMultimapKey = providerMultimapKey;
613 this.entrySetKey = entrySetKey;
614 }
615
Sam Berlinc34e0182014-08-06 11:56:26 -0400616 @Override public void configure(Binder binder) {
Sam Berlinca0cc182014-08-06 11:57:22 -0400617 ImmutableSet<Dependency<?>> dependencies
netdpbfb3a8962009-07-08 19:49:54 +0000618 = ImmutableSet.<Dependency<?>>of(Dependency.get(entrySetKey));
619
Sam Berlinca0cc182014-08-06 11:57:22 -0400620 Provider<Set<Entry<K, Provider<V>>>> entrySetProvider =
netdpbfb3a8962009-07-08 19:49:54 +0000621 binder.getProvider(entrySetKey);
622 // Binds a Map<K, Set<Provider<V>>> from a collection of Map<Entry<K, Provider<V>> if
623 // permitDuplicates was called.
624 binder.bind(providerMultimapKey).toProvider(
Sam Berlinca0cc182014-08-06 11:57:22 -0400625 new RealProviderMultimapProvider(dependencies, entrySetProvider));
netdpbfb3a8962009-07-08 19:49:54 +0000626
Sam Berlinca0cc182014-08-06 11:57:22 -0400627 Provider<Map<K, Set<Provider<V>>>> multimapProvider =
netdpbfb3a8962009-07-08 19:49:54 +0000628 binder.getProvider(providerMultimapKey);
Sam Berlinca0cc182014-08-06 11:57:22 -0400629 binder.bind(multimapKey).toProvider(
630 new RealMultimapProvider(dependencies, multimapProvider));
netdpbfb3a8962009-07-08 19:49:54 +0000631 }
drew.mclaughlin895fa392011-06-16 20:00:26 +0000632
633 @Override public int hashCode() {
634 return multimapKey.hashCode();
635 }
636
637 @Override public boolean equals(Object o) {
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700638 return o instanceof MultimapBinder
drew.mclaughlin895fa392011-06-16 20:00:26 +0000639 && ((MultimapBinder<?, ?>) o).multimapKey.equals(multimapKey);
640 }
Sam Berlinca0cc182014-08-06 11:57:22 -0400641
642 final class RealProviderMultimapProvider
643 extends RealMapBinderProviderWithDependencies<Map<K, Set<Provider<V>>>> {
644 private final ImmutableSet<Dependency<?>> dependencies;
645 private final Provider<Set<Entry<K, Provider<V>>>> entrySetProvider;
646 private Map<K, Set<Provider<V>>> providerMultimap;
647
648 private RealProviderMultimapProvider(ImmutableSet<Dependency<?>> dependencies,
649 Provider<Set<Entry<K, Provider<V>>>> entrySetProvider) {
650 super(multimapKey);
651 this.dependencies = dependencies;
652 this.entrySetProvider = entrySetProvider;
653 }
654
655 @SuppressWarnings("unused")
656 @Inject void initialize(Injector injector) {
657 Map<K, ImmutableSet.Builder<Provider<V>>> providerMultimapMutable =
658 new LinkedHashMap<K, ImmutableSet.Builder<Provider<V>>>();
659 for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
660 if (!providerMultimapMutable.containsKey(entry.getKey())) {
661 providerMultimapMutable.put(
662 entry.getKey(), ImmutableSet.<Provider<V>>builder());
663 }
664 providerMultimapMutable.get(entry.getKey()).add(entry.getValue());
665 }
666
667 ImmutableMap.Builder<K, Set<Provider<V>>> providerMultimapBuilder =
668 ImmutableMap.builder();
669 for (Entry<K, ImmutableSet.Builder<Provider<V>>> entry
670 : providerMultimapMutable.entrySet()) {
671 providerMultimapBuilder.put(entry.getKey(), entry.getValue().build());
672 }
673 providerMultimap = providerMultimapBuilder.build();
674 }
675
676 @Override public Map<K, Set<Provider<V>>> get() {
677 return providerMultimap;
678 }
679
680 @Override public Set<Dependency<?>> getDependencies() {
681 return dependencies;
682 }
683 }
684
685 final class RealMultimapProvider
686 extends RealMapBinderProviderWithDependencies<Map<K, Set<V>>> {
687 private final ImmutableSet<Dependency<?>> dependencies;
688 private final Provider<Map<K, Set<Provider<V>>>> multimapProvider;
689
690 RealMultimapProvider(
691 ImmutableSet<Dependency<?>> dependencies,
692 Provider<Map<K, Set<Provider<V>>>> multimapProvider) {
693 super(multimapKey);
694 this.dependencies = dependencies;
695 this.multimapProvider = multimapProvider;
696 }
697
698 @Override public Map<K, Set<V>> get() {
699 ImmutableMap.Builder<K, Set<V>> multimapBuilder = ImmutableMap.builder();
700 for (Entry<K, Set<Provider<V>>> entry : multimapProvider.get().entrySet()) {
701 K key = entry.getKey();
702 ImmutableSet.Builder<V> valuesBuilder = ImmutableSet.builder();
703 for (Provider<V> valueProvider : entry.getValue()) {
704 V value = valueProvider.get();
705 checkConfiguration(value != null,
706 "Multimap injection failed due to null value for key \"%s\"", key);
707 valuesBuilder.add(value);
708 }
709 multimapBuilder.put(key, valuesBuilder.build());
710 }
711 return multimapBuilder.build();
712 }
713
714 @Override public Set<Dependency<?>> getDependencies() {
715 return dependencies;
716 }
717 }
netdpbfb3a8962009-07-08 19:49:54 +0000718 }
719
sameb1bf1e9e2014-12-18 14:44:16 -0800720 static final class ValueProvider<V> implements Provider<V> {
721 private final Provider<V> delegate;
722 private final Binding<V> binding;
723
724 ValueProvider(Provider<V> delegate, Binding<V> binding) {
725 this.delegate = delegate;
726 this.binding = binding;
727 }
728
729 @Override public V get() {
730 return delegate.get();
731 }
732
733 public Binding<V> getValueBinding() {
734 return binding;
735 }
736 }
737
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -0700738 /**
Sam Berlinc34e0182014-08-06 11:56:26 -0400739 * A Provider that Map.Entry that is also a Provider. The key is the entry in the
740 * map this corresponds to and the value is the provider of the user's binding.
741 * This returns itself as the Provider.get value.
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -0700742 */
Sam Berlinc34e0182014-08-06 11:56:26 -0400743 static final class ProviderMapEntry<K, V> implements
Christian Edward Grubercade8972014-04-01 15:07:02 -0700744 ProviderWithDependencies<Map.Entry<K, Provider<V>>>, Map.Entry<K, Provider<V>> {
limpbizkite97e15b2008-05-16 14:53:49 +0000745 private final K key;
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -0700746 private final Provider<V> provider;
Sam Berlinc34e0182014-08-06 11:56:26 -0400747 private final Key<V> valueKey;
limpbizkite97e15b2008-05-16 14:53:49 +0000748
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -0700749 private ProviderMapEntry(K key, Provider<V> provider, Key<V> valueKey) {
limpbizkite97e15b2008-05-16 14:53:49 +0000750 this.key = key;
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -0700751 this.provider = provider;
sberlin75fcf6f2010-09-20 00:42:24 +0000752 this.valueKey = valueKey;
753 }
Sam Berlinc34e0182014-08-06 11:56:26 -0400754
755 @Override public Entry<K, Provider<V>> get() {
Christian Edward Grubercade8972014-04-01 15:07:02 -0700756 return this;
757 }
Sam Berlinc34e0182014-08-06 11:56:26 -0400758
759 @Override public Set<Dependency<?>> getDependencies() {
Christian Edward Grubercade8972014-04-01 15:07:02 -0700760 return ((HasDependencies) provider).getDependencies();
761 }
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700762
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -0700763 public Key<V> getValueKey() {
Sam Berlinc34e0182014-08-06 11:56:26 -0400764 return valueKey;
limpbizkite97e15b2008-05-16 14:53:49 +0000765 }
766
Sam Berlinc34e0182014-08-06 11:56:26 -0400767 @Override public K getKey() {
limpbizkite97e15b2008-05-16 14:53:49 +0000768 return key;
769 }
770
Sam Berlinc34e0182014-08-06 11:56:26 -0400771 @Override public Provider<V> getValue() {
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -0700772 return provider;
limpbizkite97e15b2008-05-16 14:53:49 +0000773 }
774
Sam Berlinc34e0182014-08-06 11:56:26 -0400775 @Override public Provider<V> setValue(Provider<V> value) {
limpbizkite97e15b2008-05-16 14:53:49 +0000776 throw new UnsupportedOperationException();
777 }
778
Sam Berlinc34e0182014-08-06 11:56:26 -0400779 @Override public boolean equals(Object obj) {
780 if (obj instanceof Map.Entry) {
781 Map.Entry o = (Map.Entry)obj;
782 return Objects.equal(key, o.getKey())
783 && Objects.equal(provider, o.getValue());
784 }
785 return false;
limpbizkite97e15b2008-05-16 14:53:49 +0000786 }
787
788 @Override public int hashCode() {
Sam Berlinc34e0182014-08-06 11:56:26 -0400789 return key.hashCode() ^ provider.hashCode();
limpbizkite97e15b2008-05-16 14:53:49 +0000790 }
791
792 @Override public String toString() {
Sam Berlinc34e0182014-08-06 11:56:26 -0400793 return "ProviderMapEntry(" + key + ", " + provider + ")";
limpbizkite97e15b2008-05-16 14:53:49 +0000794 }
795 }
sberlin75fcf6f2010-09-20 00:42:24 +0000796
797 private static abstract class RealMapWithExtensionProvider<T>
798 extends RealMapBinderProviderWithDependencies<T>
799 implements ProviderWithExtensionVisitor<T>, MapBinderBinding<T> {
800 public RealMapWithExtensionProvider(Object equality) {
801 super(equality);
802 }
803 }
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700804
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000805 /**
806 * A base class for ProviderWithDependencies that need equality
807 * based on a specific object.
808 */
809 private static abstract class RealMapBinderProviderWithDependencies<T> implements ProviderWithDependencies<T> {
810 private final Object equality;
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700811
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000812 public RealMapBinderProviderWithDependencies(Object equality) {
813 this.equality = equality;
814 }
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700815
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000816 @Override
817 public boolean equals(Object obj) {
818 return this.getClass() == obj.getClass() &&
819 equality.equals(((RealMapBinderProviderWithDependencies<?>)obj).equality);
820 }
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700821
Christian Edward Gruber6c69bcf2013-09-18 10:55:21 -0700822 @Override
823 public int hashCode() {
824 return equality.hashCode();
825 }
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000826 }
Christian Edward Gruberd1d7ef32014-04-01 15:10:51 -0700827
828 private Multimap<K, String> newLinkedKeyArrayValueMultimap() {
829 return Multimaps.newListMultimap(
830 new LinkedHashMap<K, Collection<String>>(),
831 new Supplier<List<String>>() {
832 @Override public List<String> get() {
833 return Lists.newArrayList();
834 }
835 });
836 }
limpbizkitc75363a2008-05-13 07:16:26 +0000837 }
838}