001: /*
002: * Copyright 2007 Tim Peierls
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.directwebremoting.guice;
017:
018: import com.google.inject.Binder;
019: import com.google.inject.Inject;
020: import com.google.inject.Injector;
021: import com.google.inject.Key;
022: import com.google.inject.Provider;
023:
024: import java.lang.reflect.Constructor;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.InvocationTargetException;
027: import static java.lang.reflect.Modifier.isStatic;
028:
029: /**
030: * Binding utilities for creating ad hoc providers. These come in two flavors,
031: * constructor and factory method. In both cases, you can specify additional
032: * methods to inject after creation by chaining calls to
033: * {@link BindingProvider#injecting injecting(methodName, paramKeys)}.
034: * Each method has two variants, one with a {@code Binder} parameter and one
035: * without. The former reports construction errors via the binder (so more than
036: * one error can be reported), the latter throws a runtime exception immediately,
037: * preventing further error reporting.
038: *
039: * <p> Some examples:
040: * <pre>
041: * bind(SomeInterface.class)
042: * .toProvider(
043: * .fromConstructor(LegacyImpl.class,
044: * Key.get(String.class, MyAnnotation.class))
045: * .injecting("configure", Key.get(Configuration.class)));
046: * </pre>
047: * This binds {@code SomeInterface} to a provider that uses the
048: * {@code LegacyImpl} constructor with a single String parameter.
049: * That parameter is injected as if it had been marked with {@code @MyAnnotation}.
050: * It also calls the {@code LegacyImpl.configure} method with an injected
051: * instance of {@code Configuration}.
052: * <pre>
053: * bind(SomeInterface.class)
054: * .toProvider(
055: * .fromFactoryMethod(SomeInterface.class,
056: * LegacyFactory.class, "newSomeInterface",
057: * Key.get(String.class, MyAnnotation.class)));
058: * </pre>
059: * This binds {@code SomeInterface} to a provider that calls a factory method
060: * {@code newSomeInterface} of {@code LegacyFactory} with a single string parameter,
061: * which is injected as if it were marked with {@code @MyAnnotation}. If the
062: * method is not static, an instance of {@code LegacyFactory} is created by injection
063: * and used to call the method.
064: * @author Tim Peierls [tim at peierls dot net]
065: */
066: public class BindUtil {
067: /**
068: * For fluent-style decoration with one or more method bindings when
069: * using {@link BindUtil#fromConstructor(Class, Key...)}.
070: */
071: public interface BindingProvider<T> extends Provider<T> {
072: /**
073: * Adds injection of a method defined by the given name and parameter
074: * types (specified as Guice keys) to this provider.
075: */
076: BindingProvider<T> injecting(String methodName,
077: Key<?>... paramKeys);
078: }
079:
080: /**
081: * Creates a chainable provider that constructs an instance of the
082: * given type given a list of constructor parameter types, specified
083: * as Guice keys. Construction errors are thrown immediately.
084: */
085: public static <T> BindingProvider<T> fromConstructor(Class<T> type,
086: final Key<?>... keys) {
087: return new ConstructorBindingProvider<T>(null, type, keys);
088: }
089:
090: /**
091: * Creates a chainable provider that constructs an instance of the
092: * given type given a list of constructor parameter types, specified
093: * as Guice keys. Construction errors are passed to {@code binder}
094: * to be thrown at the end of all binding.
095: */
096: public static <T> BindingProvider<T> fromConstructor(Binder binder,
097: Class<T> type, final Key<?>... keys) {
098: return new ConstructorBindingProvider<T>(binder, type, keys);
099: }
100:
101: /**
102: * Creates a chainable provider that constructs an instance of {@code providedType}
103: * using a factory method defined by {@code factoryType}, {@code methodName},
104: * and a list of method parameter types specified as Guice keys. If the
105: * method is not static an instance of the factory type is created and injected.
106: * Construction errors are thrown immediately.
107: */
108: public static <T> BindingProvider<T> fromFactoryMethod(
109: Class<T> providedType, Class<?> factoryType,
110: String methodName, final Key<?>... keys) {
111: return new FactoryMethodBindingProvider<T>(null, providedType,
112: Key.get(factoryType), methodName, keys);
113: }
114:
115: /**
116: * Creates a chainable provider that constructs an instance of {@code providedType}
117: * using a factory method defined by {@code factoryType}, {@code methodName},
118: * and a list of method parameter types specified as Guice keys. If the
119: * method is not static an instance of the factory type is created and injected.
120: * Construction errors are passed to {@code binder} to be thrown at the end
121: * of all binding.
122: */
123: public static <T> BindingProvider<T> fromFactoryMethod(
124: Binder binder, Class<T> providedType, Class<?> factoryType,
125: String methodName, final Key<?>... keys) {
126: return new FactoryMethodBindingProvider<T>(binder,
127: providedType, Key.get(factoryType), methodName, keys);
128: }
129:
130: /**
131: * Creates a chainable provider that constructs an instance of {@code providedType} by
132: * calling method {@code methodName} of the type in {@code factoryKey} with
133: * method parameter types specified as Guice keys. If the method is not static
134: * an instance is created and injected using the factory key.
135: * Construction errors are thrown immediately.
136: */
137: public static <T> BindingProvider<T> fromFactoryMethod(
138: Class<T> providedType, Key<?> factoryKey,
139: String methodName, final Key<?>... keys) {
140: return new FactoryMethodBindingProvider<T>(null, providedType,
141: factoryKey, methodName, keys);
142: }
143:
144: /**
145: * Creates a chainable provider that constructs an instance of {@code providedType} by
146: * calling method {@code methodName} of the type in {@code factoryKey} with
147: * method parameter types specified as Guice keys. If the method is not static
148: * an instance is created and injected using the factory key.
149: * Construction errors are passed to {@code binder} to be thrown at the end
150: * of all binding.
151: */
152: public static <T> BindingProvider<T> fromFactoryMethod(
153: Binder binder, Class<T> providedType, Key<?> factoryKey,
154: String methodName, final Key<?>... keys) {
155: return new FactoryMethodBindingProvider<T>(binder,
156: providedType, factoryKey, methodName, keys);
157: }
158:
159: //
160: // Implementation classes
161: //
162:
163: private abstract static class AbstractBindingProvider<T> implements
164: BindingProvider<T> {
165: protected AbstractBindingProvider(Binder binder, Class<T> type,
166: Key<?>... keys) {
167: this .binder = binder;
168: this .type = type;
169: this .keys = keys;
170: }
171:
172: public final T get() {
173: return get(theInjector);
174: }
175:
176: protected abstract T get(Injector injector);
177:
178: public final BindingProvider<T> injecting(String methodName,
179: Key<?>... paramKeys) {
180: return new MethodBindingProvider<T>(this , type, methodName,
181: paramKeys);
182: }
183:
184: protected final Class<?>[] getTypes() {
185: Class<?>[] types = new Class[keys.length];
186: int i = 0;
187: for (Key<?> key : keys) {
188: types[i] = (Class<?>) key.getTypeLiteral().getType();
189: i++;
190: }
191: return types;
192: }
193:
194: protected final Object[] getValues(Injector injector) {
195: Object[] values = new Object[keys.length];
196: int i = 0;
197: for (Key<?> key : keys) {
198: Object param = injector.getInstance(key);
199: values[i] = param;
200: i++;
201: }
202: return values;
203: }
204:
205: protected final Binder binder;
206: protected final Class<T> type;
207: protected final Key<?>[] keys;
208:
209: /**
210: * Effectively immutable: Injected at end of bind-time,
211: * read-only thereafter, and there is (or should be) a
212: * happens-before edge between bind-time and subsequent reads.
213: */
214: @Inject
215: private Injector theInjector;
216: }
217:
218: private static class ConstructorBindingProvider<T> extends
219: AbstractBindingProvider<T> {
220: ConstructorBindingProvider(Binder binder, Class<T> type,
221: Key<?>... keys) {
222: super (binder, type, keys);
223:
224: Constructor<T> newConstructor = null;
225: try {
226: newConstructor = type.getConstructor(getTypes());
227: } catch (NoSuchMethodException e) {
228: if (binder == null) {
229: throw new IllegalArgumentException(
230: "no such constructor", e);
231: } else {
232: binder.addError(e);
233: }
234: }
235:
236: this .constructor = newConstructor;
237: }
238:
239: @Override
240: public T get(Injector injector) {
241: try {
242: return constructor.newInstance(getValues(injector));
243: } catch (InstantiationException e) {
244: throw new IllegalStateException(e);
245: } catch (IllegalAccessException e) {
246: throw new IllegalStateException(e);
247: } catch (InvocationTargetException e) {
248: throw new IllegalStateException(e);
249: }
250: }
251:
252: private final Constructor<T> constructor;
253: }
254:
255: private static class MethodBindingProvider<T> extends
256: AbstractBindingProvider<T> {
257:
258: MethodBindingProvider(AbstractBindingProvider<T> prev,
259: Class<T> type, String methodName, Key<?>... keys) {
260: super (prev.binder, type, keys);
261:
262: Method newMethod = null;
263: try {
264: newMethod = type.getMethod(methodName, getTypes());
265: } catch (NoSuchMethodException e) {
266: if (binder == null) {
267: throw new IllegalArgumentException(
268: "no such method", e);
269: } else {
270: binder.addError(e);
271: }
272: }
273:
274: this .prev = prev;
275: this .method = newMethod;
276: }
277:
278: @Override
279: public T get(Injector injector) {
280: T target = prev.get(injector);
281: try {
282: method.invoke(target, getValues(injector));
283: } catch (IllegalAccessException e) {
284: throw new IllegalStateException(e);
285: } catch (InvocationTargetException e) {
286: throw new IllegalStateException(e);
287: }
288: return target;
289: }
290:
291: private final AbstractBindingProvider<T> prev;
292: private final Method method;
293: }
294:
295: private static class FactoryMethodBindingProvider<T> extends
296: AbstractBindingProvider<T> {
297: FactoryMethodBindingProvider(Binder binder,
298: Class<T> providedType, Key<?> factoryKey,
299: String methodName, Key<?>... keys) {
300: super (binder, providedType, keys);
301:
302: Method newMethod = null;
303: try {
304: Class<?> factoryType = (Class<?>) factoryKey
305: .getTypeLiteral().getType();
306: newMethod = factoryType.getMethod(methodName,
307: getTypes());
308: newMethod.getReturnType().asSubclass(providedType);
309: } catch (NoSuchMethodException e) {
310: if (binder == null) {
311: throw new IllegalArgumentException(
312: "no such method", e);
313: } else {
314: binder.addError(e);
315: }
316: } catch (ClassCastException e) {
317: if (binder == null) {
318: throw new IllegalArgumentException(
319: "bad return type", e);
320: } else {
321: binder.addError(e);
322: }
323: }
324:
325: this .method = newMethod;
326: this .factoryKey = factoryKey;
327: }
328:
329: @Override
330: public T get(Injector injector) {
331: try {
332: Object target = null;
333: if (!isStatic(method.getModifiers())) {
334: target = injector.getInstance(factoryKey);
335: }
336: @SuppressWarnings("unchecked")
337: T result = (T) method.invoke(target,
338: getValues(injector));
339: return result;
340: } catch (IllegalAccessException e) {
341: throw new IllegalStateException(e);
342: } catch (InvocationTargetException e) {
343: throw new IllegalStateException(e);
344: }
345: }
346:
347: private final Method method;
348: private final Key<?> factoryKey;
349: }
350: }
|