package com.google.inject.internal;
import static com.google.inject.internal.Element.Type.MAPBINDER;
import static com.google.inject.internal.Errors.checkConfiguration;
import static com.google.inject.internal.Errors.checkNotNull;
import static com.google.inject.internal.RealMultibinder.setOf;
import static com.google.inject.util.Types.newParameterizedType;
import static com.google.inject.util.Types.newParameterizedTypeWithOwner;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.internal.InternalProviderInstanceBindingImpl.InitializationTiming;
import com.google.inject.multibindings.MapBinderBinding;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.multibindings.MultibindingsTargetVisitor;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.Element;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderWithExtensionVisitor;
import com.google.inject.util.Types;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* The actual mapbinder plays several roles:
*
* As a MapBinder, it acts as a factory for LinkedBindingBuilders for each of the map's values.
* It delegates to a {@link Multibinder} of entries (keys to value providers).
*
*
As a Module, it installs the binding to the map itself, as well as to a corresponding map
* whose values are providers.
*
*
As a module, this implements equals() and hashcode() in order to trick Guice into executing
* its configure() method only once. That makes it so that multiple mapbinders can be created for
* the same target map, but only one is bound. Since the list of bindings is retrieved from the
* injector itself (and not the mapbinder), each mapbinder has access to all contributions from all
* equivalent mapbinders.
*
*
Rather than binding a single Map.Entry<K, V>, the map binder binds keys and values
* independently. This allows the values to be properly scoped.
*/
public final class RealMapBinder implements Module {
/**
* Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
* Map} that is itself bound with no binding annotation.
*/
public static RealMapBinder newMapRealBinder(
Binder binder, TypeLiteral keyType, TypeLiteral valueType) {
binder = binder.skipSources(RealMapBinder.class);
return newRealMapBinder(
binder,
keyType,
valueType,
Key.get(mapOf(keyType, valueType)),
RealMultibinder.newRealSetBinder(binder, Key.get(entryOfProviderOf(keyType, valueType))));
}
/**
* Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
* Map} that is itself bound with {@code annotation}.
*/
public static RealMapBinder newRealMapBinder(
Binder binder, TypeLiteral keyType, TypeLiteral valueType, Annotation annotation) {
binder = binder.skipSources(RealMapBinder.class);
return newRealMapBinder(
binder,
keyType,
valueType,
Key.get(mapOf(keyType, valueType), annotation),
RealMultibinder.newRealSetBinder(
binder, Key.get(entryOfProviderOf(keyType, valueType), annotation)));
}
/**
* Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
* Map} that is itself bound with {@code annotationType}.
*/
public static RealMapBinder newRealMapBinder(
Binder binder,
TypeLiteral keyType,
TypeLiteral valueType,
Class extends Annotation> annotationType) {
binder = binder.skipSources(RealMapBinder.class);
return newRealMapBinder(
binder,
keyType,
valueType,
Key.get(mapOf(keyType, valueType), annotationType),
RealMultibinder.newRealSetBinder(
binder, Key.get(entryOfProviderOf(keyType, valueType), annotationType)));
}
@SuppressWarnings("unchecked") // a map of is safely a Map
static TypeLiteral