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