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