1 /* 2 * Copyright (C) 2009 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.assistedinject; 18 19 import com.google.inject.AbstractModule; 20 import com.google.inject.Key; 21 import com.google.inject.Module; 22 import com.google.inject.Provider; 23 import com.google.inject.TypeLiteral; 24 import java.lang.annotation.Annotation; 25 26 /** 27 * Provides a factory that combines the caller's arguments with injector-supplied values to 28 * construct objects. 29 * 30 * <h3>Defining a factory</h3> 31 * 32 * Create an interface whose methods return the constructed type, or any of its supertypes. The 33 * method's parameters are the arguments required to build the constructed type. 34 * 35 * <pre>public interface PaymentFactory { 36 * Payment create(Date startDate, Money amount); 37 * }</pre> 38 * 39 * You can name your factory methods whatever you like, such as <i>create</i>, <i>createPayment</i> 40 * or <i>newPayment</i>. 41 * 42 * <h3>Creating a type that accepts factory parameters</h3> 43 * 44 * {@code constructedType} is a concrete class with an {@literal @}{@link com.google.inject.Inject 45 * Inject}-annotated constructor. In addition to injector-supplied parameters, the constructor 46 * should have parameters that match each of the factory method's parameters. Each factory-supplied 47 * parameter requires an {@literal @}{@link Assisted} annotation. This serves to document that the 48 * parameter is not bound by your application's modules. 49 * 50 * <pre>public class RealPayment implements Payment { 51 * {@literal @}Inject 52 * public RealPayment( 53 * CreditService creditService, 54 * AuthService authService, 55 * <strong>{@literal @}Assisted Date startDate</strong>, 56 * <strong>{@literal @}Assisted Money amount</strong>) { 57 * ... 58 * } 59 * }</pre> 60 * 61 * <h3>Multiple factory methods for the same type</h3> 62 * 63 * If the factory contains many methods that return the same type, you can create multiple 64 * constructors in your concrete class, each constructor marked with with {@literal @}{@link 65 * AssistedInject}, in order to match the different parameters types of the factory methods. 66 * 67 * <pre>public interface PaymentFactory { 68 * Payment create(Date startDate, Money amount); 69 * Payment createWithoutDate(Money amount); 70 * } 71 * 72 * public class RealPayment implements Payment { 73 * {@literal @}AssistedInject 74 * public RealPayment( 75 * CreditService creditService, 76 * AuthService authService, 77 * <strong>{@literal @}Assisted Date startDate</strong>, 78 * <strong>{@literal @}Assisted Money amount</strong>) { 79 * ... 80 * } 81 * 82 * {@literal @}AssistedInject 83 * public RealPayment( 84 * CreditService creditService, 85 * AuthService authService, 86 * <strong>{@literal @}Assisted Money amount</strong>) { 87 * ... 88 * } 89 * }</pre> 90 * 91 * <h3>Configuring simple factories</h3> 92 * 93 * In your {@link Module module}, install a {@code FactoryModuleBuilder} that creates the factory: 94 * 95 * <pre>install(new FactoryModuleBuilder() 96 * .implement(Payment.class, RealPayment.class) 97 * .build(PaymentFactory.class));</pre> 98 * 99 * As a side-effect of this binding, Guice will inject the factory to initialize it for use. The 100 * factory cannot be used until the injector has been initialized. 101 * 102 * <h3>Configuring complex factories</h3> 103 * 104 * Factories can create an arbitrary number of objects, one per each method. Each factory method can 105 * be configured using <code>.implement</code>. 106 * 107 * <pre>public interface OrderFactory { 108 * Payment create(Date startDate, Money amount); 109 * Shipment create(Customer customer, Item item); 110 * Receipt create(Payment payment, Shipment shipment); 111 * } 112 * 113 * [...] 114 * 115 * install(new FactoryModuleBuilder() 116 * .implement(Payment.class, RealPayment.class) 117 * // excluding .implement for Shipment means the implementation class 118 * // will be 'Shipment' itself, which is legal if it's not an interface. 119 * .implement(Receipt.class, RealReceipt.class) 120 * .build(OrderFactory.class));</pre> 121 * 122 * </pre> 123 * 124 * <h3>Using the factory</h3> 125 * 126 * Inject your factory into your application classes. When you use the factory, your arguments will 127 * be combined with values from the injector to construct an instance. 128 * 129 * <pre>public class PaymentAction { 130 * {@literal @}Inject private PaymentFactory paymentFactory; 131 * 132 * public void doPayment(Money amount) { 133 * Payment payment = paymentFactory.create(new Date(), amount); 134 * payment.apply(); 135 * } 136 * }</pre> 137 * 138 * <h3>Making parameter types distinct</h3> 139 * 140 * The types of the factory method's parameters must be distinct. To use multiple parameters of the 141 * same type, use a named {@literal @}{@link Assisted} annotation to disambiguate the parameters. 142 * The names must be applied to the factory method's parameters: 143 * 144 * <pre>public interface PaymentFactory { 145 * Payment create( 146 * <strong>{@literal @}Assisted("startDate")</strong> Date startDate, 147 * <strong>{@literal @}Assisted("dueDate")</strong> Date dueDate, 148 * Money amount); 149 * } </pre> 150 * 151 * ...and to the concrete type's constructor parameters: 152 * 153 * <pre>public class RealPayment implements Payment { 154 * {@literal @}Inject 155 * public RealPayment( 156 * CreditService creditService, 157 * AuthService authService, 158 * <strong>{@literal @}Assisted("startDate")</strong> Date startDate, 159 * <strong>{@literal @}Assisted("dueDate")</strong> Date dueDate, 160 * <strong>{@literal @}Assisted</strong> Money amount) { 161 * ... 162 * } 163 * }</pre> 164 * 165 * <h3>Values are created by Guice</h3> 166 * 167 * Returned factories use child injectors to create values. The values are eligible for method 168 * interception. In addition, {@literal @}{@literal Inject} members will be injected before they are 169 * returned. 170 * 171 * <h3>More configuration options</h3> 172 * 173 * In addition to simply specifying an implementation class for any returned type, factories' return 174 * values can be automatic or can be configured to use annotations: 175 * 176 * <p>If you just want to return the types specified in the factory, do not configure any 177 * implementations: 178 * 179 * <pre>public interface FruitFactory { 180 * Apple getApple(Color color); 181 * } 182 * ... 183 * protected void configure() { 184 * install(new FactoryModuleBuilder().build(FruitFactory.class)); 185 * }</pre> 186 * 187 * Note that any type returned by the factory in this manner needs to be an implementation class. 188 * 189 * <p>To return two different implementations for the same interface from your factory, use binding 190 * annotations on your return types: 191 * 192 * <pre>interface CarFactory { 193 * {@literal @}Named("fast") Car getFastCar(Color color); 194 * {@literal @}Named("clean") Car getCleanCar(Color color); 195 * } 196 * ... 197 * protected void configure() { 198 * install(new FactoryModuleBuilder() 199 * .implement(Car.class, Names.named("fast"), Porsche.class) 200 * .implement(Car.class, Names.named("clean"), Prius.class) 201 * .build(CarFactory.class)); 202 * }</pre> 203 * 204 * <h3>Implementation limitations</h3> 205 * 206 * As a limitation of the implementation, it is prohibited to declare a factory method that accepts 207 * a {@code Provider} as one of its arguments. 208 * 209 * @since 3.0 210 * @author schmitt@google.com (Peter Schmitt) 211 */ 212 public final class FactoryModuleBuilder { 213 214 private final BindingCollector bindings = new BindingCollector(); 215 216 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement(Class<T> source, Class<? extends T> target)217 public <T> FactoryModuleBuilder implement(Class<T> source, Class<? extends T> target) { 218 return implement(source, TypeLiteral.get(target)); 219 } 220 221 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement(Class<T> source, TypeLiteral<? extends T> target)222 public <T> FactoryModuleBuilder implement(Class<T> source, TypeLiteral<? extends T> target) { 223 return implement(TypeLiteral.get(source), target); 224 } 225 226 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement(TypeLiteral<T> source, Class<? extends T> target)227 public <T> FactoryModuleBuilder implement(TypeLiteral<T> source, Class<? extends T> target) { 228 return implement(source, TypeLiteral.get(target)); 229 } 230 231 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement( TypeLiteral<T> source, TypeLiteral<? extends T> target)232 public <T> FactoryModuleBuilder implement( 233 TypeLiteral<T> source, TypeLiteral<? extends T> target) { 234 return implement(Key.get(source), target); 235 } 236 237 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement( Class<T> source, Annotation annotation, Class<? extends T> target)238 public <T> FactoryModuleBuilder implement( 239 Class<T> source, Annotation annotation, Class<? extends T> target) { 240 return implement(source, annotation, TypeLiteral.get(target)); 241 } 242 243 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement( Class<T> source, Annotation annotation, TypeLiteral<? extends T> target)244 public <T> FactoryModuleBuilder implement( 245 Class<T> source, Annotation annotation, TypeLiteral<? extends T> target) { 246 return implement(TypeLiteral.get(source), annotation, target); 247 } 248 249 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement( TypeLiteral<T> source, Annotation annotation, Class<? extends T> target)250 public <T> FactoryModuleBuilder implement( 251 TypeLiteral<T> source, Annotation annotation, Class<? extends T> target) { 252 return implement(source, annotation, TypeLiteral.get(target)); 253 } 254 255 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement( TypeLiteral<T> source, Annotation annotation, TypeLiteral<? extends T> target)256 public <T> FactoryModuleBuilder implement( 257 TypeLiteral<T> source, Annotation annotation, TypeLiteral<? extends T> target) { 258 return implement(Key.get(source, annotation), target); 259 } 260 261 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement( Class<T> source, Class<? extends Annotation> annotationType, Class<? extends T> target)262 public <T> FactoryModuleBuilder implement( 263 Class<T> source, Class<? extends Annotation> annotationType, Class<? extends T> target) { 264 return implement(source, annotationType, TypeLiteral.get(target)); 265 } 266 267 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement( Class<T> source, Class<? extends Annotation> annotationType, TypeLiteral<? extends T> target)268 public <T> FactoryModuleBuilder implement( 269 Class<T> source, 270 Class<? extends Annotation> annotationType, 271 TypeLiteral<? extends T> target) { 272 return implement(TypeLiteral.get(source), annotationType, target); 273 } 274 275 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement( TypeLiteral<T> source, Class<? extends Annotation> annotationType, Class<? extends T> target)276 public <T> FactoryModuleBuilder implement( 277 TypeLiteral<T> source, 278 Class<? extends Annotation> annotationType, 279 Class<? extends T> target) { 280 return implement(source, annotationType, TypeLiteral.get(target)); 281 } 282 283 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement( TypeLiteral<T> source, Class<? extends Annotation> annotationType, TypeLiteral<? extends T> target)284 public <T> FactoryModuleBuilder implement( 285 TypeLiteral<T> source, 286 Class<? extends Annotation> annotationType, 287 TypeLiteral<? extends T> target) { 288 return implement(Key.get(source, annotationType), target); 289 } 290 291 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement(Key<T> source, Class<? extends T> target)292 public <T> FactoryModuleBuilder implement(Key<T> source, Class<? extends T> target) { 293 return implement(source, TypeLiteral.get(target)); 294 } 295 296 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ implement(Key<T> source, TypeLiteral<? extends T> target)297 public <T> FactoryModuleBuilder implement(Key<T> source, TypeLiteral<? extends T> target) { 298 bindings.addBinding(source, target); 299 return this; 300 } 301 302 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ build(Class<F> factoryInterface)303 public <F> Module build(Class<F> factoryInterface) { 304 return build(TypeLiteral.get(factoryInterface)); 305 } 306 307 /** See the factory configuration examples at {@link FactoryModuleBuilder}. */ build(TypeLiteral<F> factoryInterface)308 public <F> Module build(TypeLiteral<F> factoryInterface) { 309 return build(Key.get(factoryInterface)); 310 } 311 build(final Key<F> factoryInterface)312 public <F> Module build(final Key<F> factoryInterface) { 313 return new AbstractModule() { 314 @Override 315 protected void configure() { 316 Provider<F> provider = new FactoryProvider2<>(factoryInterface, bindings); 317 bind(factoryInterface).toProvider(provider); 318 } 319 }; 320 } 321 } 322