• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.internal.RealMultibinder.newRealSetBinder;
20 
21 import com.google.inject.Binder;
22 import com.google.inject.Key;
23 import com.google.inject.TypeLiteral;
24 import com.google.inject.binder.LinkedBindingBuilder;
25 import com.google.inject.internal.RealMultibinder;
26 import java.lang.annotation.Annotation;
27 import java.util.Collection;
28 import java.util.Set;
29 
30 /**
31  * An API to bind multiple values separately, only to later inject them as a complete collection.
32  * Multibinder is intended for use in your application's module:
33  *
34  * <pre><code>
35  * public class SnacksModule extends AbstractModule {
36  *   protected void configure() {
37  *     Multibinder&lt;Snack&gt; multibinder
38  *         = Multibinder.newSetBinder(binder(), Snack.class);
39  *     multibinder.addBinding().toInstance(new Twix());
40  *     multibinder.addBinding().toProvider(SnickersProvider.class);
41  *     multibinder.addBinding().to(Skittles.class);
42  *   }
43  * }</code></pre>
44  *
45  * <p>With this binding, a {@link Set}{@code <Snack>} can now be injected:
46  *
47  * <pre><code>
48  * class SnackMachine {
49  *   {@literal @}Inject
50  *   public SnackMachine(Set&lt;Snack&gt; snacks) { ... }
51  * }</code></pre>
52  *
53  * If desired, {@link Collection}{@code <Provider<Snack>>} can also be injected.
54  *
55  * <p>Contributing multibindings from different modules is supported. For example, it is okay for
56  * both {@code CandyModule} and {@code ChipsModule} to create their own {@code Multibinder<Snack>},
57  * and to each contribute bindings to the set of snacks. When that set is injected, it will contain
58  * elements from both modules.
59  *
60  * <p>The set's iteration order is consistent with the binding order. This is convenient when
61  * multiple elements are contributed by the same module because that module can order its bindings
62  * appropriately. Avoid relying on the iteration order of elements contributed by different modules,
63  * since there is no equivalent mechanism to order modules.
64  *
65  * <p>The set is unmodifiable. Elements can only be added to the set by configuring the multibinder.
66  * Elements can never be removed from the set.
67  *
68  * <p>Elements are resolved at set injection time. If an element is bound to a provider, that
69  * provider's get method will be called each time the set is injected (unless the binding is also
70  * scoped).
71  *
72  * <p>Annotations are be used to create different sets of the same element type. Each distinct
73  * annotation gets its own independent collection of elements.
74  *
75  * <p><strong>Elements must be distinct.</strong> If multiple bound elements have the same value,
76  * set injection will fail.
77  *
78  * <p><strong>Elements must be non-null.</strong> If any set element is null, set injection will
79  * fail.
80  *
81  * @author jessewilson@google.com (Jesse Wilson)
82  */
83 public class Multibinder<T> {
84   // This class is non-final due to users mocking this in tests :(
85 
86   /**
87    * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
88    * itself bound with no binding annotation.
89    */
newSetBinder(Binder binder, TypeLiteral<T> type)90   public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type) {
91     return newSetBinder(binder, Key.get(type));
92   }
93 
94   /**
95    * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
96    * itself bound with no binding annotation.
97    */
newSetBinder(Binder binder, Class<T> type)98   public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type) {
99     return newSetBinder(binder, Key.get(type));
100   }
101 
102   /**
103    * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
104    * itself bound with {@code annotation}.
105    */
newSetBinder( Binder binder, TypeLiteral<T> type, Annotation annotation)106   public static <T> Multibinder<T> newSetBinder(
107       Binder binder, TypeLiteral<T> type, Annotation annotation) {
108     return newSetBinder(binder, Key.get(type, annotation));
109   }
110 
111   /**
112    * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
113    * itself bound with {@code annotation}.
114    */
newSetBinder( Binder binder, Class<T> type, Annotation annotation)115   public static <T> Multibinder<T> newSetBinder(
116       Binder binder, Class<T> type, Annotation annotation) {
117     return newSetBinder(binder, Key.get(type, annotation));
118   }
119 
120   /**
121    * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
122    * itself bound with {@code annotationType}.
123    */
newSetBinder( Binder binder, TypeLiteral<T> type, Class<? extends Annotation> annotationType)124   public static <T> Multibinder<T> newSetBinder(
125       Binder binder, TypeLiteral<T> type, Class<? extends Annotation> annotationType) {
126     return newSetBinder(binder, Key.get(type, annotationType));
127   }
128 
129   /**
130    * Returns a new multibinder that collects instances of the key's type in a {@link Set} that is
131    * itself bound with the annotation (if any) of the key.
132    *
133    * @since 4.0
134    */
newSetBinder(Binder binder, Key<T> key)135   public static <T> Multibinder<T> newSetBinder(Binder binder, Key<T> key) {
136     return new Multibinder<T>(newRealSetBinder(binder.skipSources(Multibinder.class), key));
137   }
138 
139   /**
140    * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
141    * itself bound with {@code annotationType}.
142    */
newSetBinder( Binder binder, Class<T> type, Class<? extends Annotation> annotationType)143   public static <T> Multibinder<T> newSetBinder(
144       Binder binder, Class<T> type, Class<? extends Annotation> annotationType) {
145     return newSetBinder(binder, Key.get(type, annotationType));
146   }
147 
148   private final RealMultibinder<T> delegate;
149 
Multibinder(RealMultibinder<T> delegate)150   private Multibinder(RealMultibinder<T> delegate) {
151     this.delegate = delegate;
152   }
153 
154   /**
155    * Configures the bound set to silently discard duplicate elements. When multiple equal values are
156    * bound, the one that gets included is arbitrary. When multiple modules contribute elements to
157    * the set, this configuration option impacts all of them.
158    *
159    * @return this multibinder
160    * @since 3.0
161    */
permitDuplicates()162   public Multibinder<T> permitDuplicates() {
163     delegate.permitDuplicates();
164     return this;
165   }
166 
167   /**
168    * Returns a binding builder used to add a new element in the set. Each bound element must have a
169    * distinct value. Bound providers will be evaluated each time the set is injected.
170    *
171    * <p>It is an error to call this method without also calling one of the {@code to} methods on the
172    * returned binding builder.
173    *
174    * <p>Scoping elements independently is supported. Use the {@code in} method to specify a binding
175    * scope.
176    */
addBinding()177   public LinkedBindingBuilder<T> addBinding() {
178     return delegate.addBinding();
179   }
180 
181   // Some tests rely on Multibinder implementing equals/hashCode
182 
183   @Override
equals(Object obj)184   public boolean equals(Object obj) {
185     if (obj instanceof Multibinder) {
186       return delegate.equals(((Multibinder<?>) obj).delegate);
187     }
188     return false;
189   }
190 
191   @Override
hashCode()192   public int hashCode() {
193     return delegate.hashCode();
194   }
195 }
196