| /* |
| * Copyright (C) 2008 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.google.inject.multibindings; |
| |
| import static com.google.inject.internal.RealMultibinder.newRealSetBinder; |
| |
| import com.google.inject.Binder; |
| import com.google.inject.Key; |
| import com.google.inject.TypeLiteral; |
| import com.google.inject.binder.LinkedBindingBuilder; |
| import com.google.inject.internal.RealMultibinder; |
| import java.lang.annotation.Annotation; |
| import java.util.Collection; |
| import java.util.Set; |
| |
| /** |
| * An API to bind multiple values separately, only to later inject them as a complete collection. |
| * Multibinder is intended for use in your application's module: |
| * |
| * <pre><code> |
| * public class SnacksModule extends AbstractModule { |
| * protected void configure() { |
| * Multibinder<Snack> multibinder |
| * = Multibinder.newSetBinder(binder(), Snack.class); |
| * multibinder.addBinding().toInstance(new Twix()); |
| * multibinder.addBinding().toProvider(SnickersProvider.class); |
| * multibinder.addBinding().to(Skittles.class); |
| * } |
| * }</code></pre> |
| * |
| * <p>With this binding, a {@link Set}{@code <Snack>} can now be injected: |
| * |
| * <pre><code> |
| * class SnackMachine { |
| * {@literal @}Inject |
| * public SnackMachine(Set<Snack> snacks) { ... } |
| * }</code></pre> |
| * |
| * If desired, {@link Collection}{@code <Provider<Snack>>} can also be injected. |
| * |
| * <p>Contributing multibindings from different modules is supported. For example, it is okay for |
| * both {@code CandyModule} and {@code ChipsModule} to create their own {@code Multibinder<Snack>}, |
| * and to each contribute bindings to the set of snacks. When that set is injected, it will contain |
| * elements from both modules. |
| * |
| * <p>The set'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. |
| * |
| * <p>The set is unmodifiable. Elements can only be added to the set by configuring the multibinder. |
| * Elements can never be removed from the set. |
| * |
| * <p>Elements are resolved at set injection time. If an element is bound to a provider, that |
| * provider's get method will be called each time the set is injected (unless the binding is also |
| * scoped). |
| * |
| * <p>Annotations are be used to create different sets of the same element type. Each distinct |
| * annotation gets its own independent collection of elements. |
| * |
| * <p><strong>Elements must be distinct.</strong> If multiple bound elements have the same value, |
| * set injection will fail. |
| * |
| * <p><strong>Elements must be non-null.</strong> If any set element is null, set injection will |
| * fail. |
| * |
| * @author jessewilson@google.com (Jesse Wilson) |
| */ |
| public class Multibinder<T> { |
| // This class is non-final due to users mocking this in tests :( |
| |
| /** |
| * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is |
| * itself bound with no binding annotation. |
| */ |
| public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type) { |
| return newSetBinder(binder, Key.get(type)); |
| } |
| |
| /** |
| * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is |
| * itself bound with no binding annotation. |
| */ |
| public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type) { |
| return newSetBinder(binder, Key.get(type)); |
| } |
| |
| /** |
| * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is |
| * itself bound with {@code annotation}. |
| */ |
| public static <T> Multibinder<T> newSetBinder( |
| Binder binder, TypeLiteral<T> type, Annotation annotation) { |
| return newSetBinder(binder, Key.get(type, annotation)); |
| } |
| |
| /** |
| * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is |
| * itself bound with {@code annotation}. |
| */ |
| public static <T> Multibinder<T> newSetBinder( |
| Binder binder, Class<T> type, Annotation annotation) { |
| return newSetBinder(binder, Key.get(type, annotation)); |
| } |
| |
| /** |
| * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is |
| * itself bound with {@code annotationType}. |
| */ |
| public static <T> Multibinder<T> newSetBinder( |
| Binder binder, TypeLiteral<T> type, Class<? extends Annotation> annotationType) { |
| return newSetBinder(binder, Key.get(type, annotationType)); |
| } |
| |
| /** |
| * Returns a new multibinder that collects instances of the key's type in a {@link Set} that is |
| * itself bound with the annotation (if any) of the key. |
| * |
| * @since 4.0 |
| */ |
| public static <T> Multibinder<T> newSetBinder(Binder binder, Key<T> key) { |
| return new Multibinder<T>(newRealSetBinder(binder.skipSources(Multibinder.class), key)); |
| } |
| |
| /** |
| * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is |
| * itself bound with {@code annotationType}. |
| */ |
| public static <T> Multibinder<T> newSetBinder( |
| Binder binder, Class<T> type, Class<? extends Annotation> annotationType) { |
| return newSetBinder(binder, Key.get(type, annotationType)); |
| } |
| |
| private final RealMultibinder<T> delegate; |
| |
| private Multibinder(RealMultibinder<T> delegate) { |
| this.delegate = delegate; |
| } |
| |
| /** |
| * Configures the bound set to silently discard duplicate elements. When multiple equal values are |
| * bound, the one that gets included is arbitrary. When multiple modules contribute elements to |
| * the set, this configuration option impacts all of them. |
| * |
| * @return this multibinder |
| * @since 3.0 |
| */ |
| public Multibinder<T> permitDuplicates() { |
| delegate.permitDuplicates(); |
| return this; |
| } |
| |
| /** |
| * Returns a binding builder used to add a new element in the set. Each bound element must have a |
| * distinct value. Bound providers will be evaluated each time the set is injected. |
| * |
| * <p>It is an error to call this method without also calling one of the {@code to} methods on the |
| * returned binding builder. |
| * |
| * <p>Scoping elements independently is supported. Use the {@code in} method to specify a binding |
| * scope. |
| */ |
| public LinkedBindingBuilder<T> addBinding() { |
| return delegate.addBinding(); |
| } |
| |
| // Some tests rely on Multibinder implementing equals/hashCode |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof Multibinder) { |
| return delegate.equals(((Multibinder<?>) obj).delegate); |
| } |
| return false; |
| } |
| |
| @Override |
| public int hashCode() { |
| return delegate.hashCode(); |
| } |
| } |