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<Snack> 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<Snack> 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