All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.inject.multibindings.MapBinder Maven / Gradle / Ivy

package com.google.inject.multibindings;

import static com.google.inject.internal.RealMapBinder.newMapRealBinder;
import static com.google.inject.internal.RealMapBinder.newRealMapBinder;

import com.google.inject.Binder;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.internal.RealMapBinder;
import java.lang.annotation.Annotation;
import java.util.Map;

/**
 * An API to bind multiple map entries separately, only to later inject them as
 * a complete map. MapBinder is intended for use in your application's module:
 * 

 * public class SnacksModule extends AbstractModule {
 *   protected void configure() {
 *     MapBinder<String, Snack> mapbinder
 *         = MapBinder.newMapBinder(binder(), String.class, Snack.class);
 *     mapbinder.addBinding("twix").toInstance(new Twix());
 *     mapbinder.addBinding("snickers").toProvider(SnickersProvider.class);
 *     mapbinder.addBinding("skittles").to(Skittles.class);
 *   }
 * }
* *

With this binding, a {@link Map}{@code } can now be * injected: *


 * class SnackMachine {
 *   {@literal @}Inject
 *   public SnackMachine(Map<String, Snack> snacks) { ... }
 * }
* *

In addition to binding {@code Map}, a mapbinder will also bind * {@code Map>} for lazy value provision: *


 * class SnackMachine {
 *   {@literal @}Inject
 *   public SnackMachine(Map<String, Provider<Snack>> snackProviders) { ... }
 * }
* *

Contributing mapbindings from different modules is supported. For example, * it is okay to have both {@code CandyModule} and {@code ChipsModule} both * create their own {@code MapBinder}, and to each contribute * bindings to the snacks map. When that map is injected, it will contain * entries from both modules. * *

The map's iteration order is consistent with the binding order. This is * convenient when multiple elements are contributed by the same module because * that module can order its bindings appropriately. Avoid relying on the * iteration order of elements contributed by different modules, since there is * no equivalent mechanism to order modules. * *

The map is unmodifiable. Elements can only be added to the map by * configuring the MapBinder. Elements can never be removed from the map. * *

Values are resolved at map injection time. If a value is bound to a * provider, that provider's get method will be called each time the map is * injected (unless the binding is also scoped, or a map of providers is injected). * *

Annotations are used to create different maps of the same key/value * type. Each distinct annotation gets its own independent map. * *

Keys must be distinct. If the same key is bound more than * once, map injection will fail. However, use {@link #permitDuplicates()} in * order to allow duplicate keys; extra bindings to {@code Map>} and * {@code Map>} will be added. * *

Keys must be non-null. {@code addBinding(null)} will * throw an unchecked exception. * *

Values must be non-null to use map injection. If any * value is null, map injection will fail (although injecting a map of providers * will not). */ public class MapBinder { /** * 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 MapBinder newMapBinder(Binder binder, TypeLiteral keyType, TypeLiteral valueType) { return new MapBinder( newMapRealBinder(binder.skipSources(MapBinder.class), keyType, valueType)); } /** * 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 MapBinder newMapBinder(Binder binder, Class keyType, Class valueType) { return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(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 MapBinder newMapBinder(Binder binder, TypeLiteral keyType, TypeLiteral valueType, Annotation annotation) { return new MapBinder( newRealMapBinder(binder.skipSources(MapBinder.class), 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 annotation}. */ public static MapBinder newMapBinder(Binder binder, Class keyType, Class valueType, Annotation annotation) { return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(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 MapBinder newMapBinder(Binder binder, TypeLiteral keyType, TypeLiteral valueType, Class annotationType) { return new MapBinder( newRealMapBinder(binder.skipSources(MapBinder.class), keyType, valueType, annotationType)); } /** * 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 MapBinder newMapBinder(Binder binder, Class keyType, Class valueType, Class annotationType) { return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotationType); } private final RealMapBinder delegate; private MapBinder(RealMapBinder delegate) { this.delegate = delegate; } /** * Configures the {@code MapBinder} to handle duplicate entries. *

When multiple equal keys are bound, the value that gets included in the map is * arbitrary. *

In addition to the {@code Map} and {@code Map>} * maps that are normally bound, a {@code Map>} and * {@code Map>>} are also bound, which contain * all values bound to each key. *

* When multiple modules contribute elements to the map, this configuration * option impacts all of them. * * @return this map binder */ public MapBinder permitDuplicates() { delegate.permitDuplicates(); return this; } /** * Returns a binding builder used to add a new entry in the map. Each * key must be distinct (and non-null). Bound providers will be evaluated each * time the map is injected. * *

It is an error to call this method without also calling one of the * {@code to} methods on the returned binding builder. * *

Scoping elements independently is supported. Use the {@code in} method * to specify a binding scope. */ public LinkedBindingBuilder addBinding(K key) { return delegate.addBinding(key); } // Some tests rely on MapBinder implementing equals/hashCode @Override public boolean equals(Object obj) { if (obj instanceof MapBinder) { return delegate.equals(((MapBinder) obj).delegate); } return false; } @Override public int hashCode() { return delegate.hashCode(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy