KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > inject > InjectorImpl


1 /**
2  * Copyright (C) 2006 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;
18
19 import com.google.inject.spi.SourceProviders;
20 import com.google.inject.util.GuiceFastClass;
21 import com.google.inject.util.Objects;
22 import com.google.inject.util.ReferenceCache;
23 import com.google.inject.util.StackTraceElements;
24 import com.google.inject.util.Strings;
25 import com.google.inject.util.ToStringBuilder;
26 import java.lang.annotation.Annotation JavaDoc;
27 import java.lang.reflect.AccessibleObject JavaDoc;
28 import java.lang.reflect.AnnotatedElement JavaDoc;
29 import java.lang.reflect.Constructor JavaDoc;
30 import java.lang.reflect.Field JavaDoc;
31 import java.lang.reflect.InvocationTargetException JavaDoc;
32 import java.lang.reflect.Member JavaDoc;
33 import java.lang.reflect.Method JavaDoc;
34 import java.lang.reflect.Modifier JavaDoc;
35 import java.lang.reflect.ParameterizedType JavaDoc;
36 import java.lang.reflect.Type JavaDoc;
37 import java.util.ArrayList JavaDoc;
38 import java.util.Arrays JavaDoc;
39 import java.util.Collections JavaDoc;
40 import java.util.HashMap JavaDoc;
41 import java.util.Iterator JavaDoc;
42 import java.util.List JavaDoc;
43 import java.util.Map JavaDoc;
44 import net.sf.cglib.reflect.FastClass;
45 import net.sf.cglib.reflect.FastMethod;
46
47 /**
48  * Default {@link Injector} implementation.
49  *
50  * @author crazybob@google.com (Bob Lee)
51  * @see BinderImpl
52  */

53 class InjectorImpl implements Injector {
54
55   /**
56    * Maps between primitive types and their wrappers and vice versa.
57    */

58   private static final Map JavaDoc<Class JavaDoc<?>, Class JavaDoc<?>> PRIMITIVE_COUNTERPARTS;
59   static {
60     Map JavaDoc<Class JavaDoc<?>, Class JavaDoc<?>> primitiveToWrapper =
61         new HashMap JavaDoc<Class JavaDoc<?>, Class JavaDoc<?>>() {{
62           put(int.class, Integer JavaDoc.class);
63           put(long.class, Long JavaDoc.class);
64           put(boolean.class, Boolean JavaDoc.class);
65           put(byte.class, Byte JavaDoc.class);
66           put(short.class, Short JavaDoc.class);
67           put(float.class, Float JavaDoc.class);
68           put(double.class, Double JavaDoc.class);
69           put(char.class, Character JavaDoc.class);
70         }};
71
72     Map JavaDoc<Class JavaDoc<?>, Class JavaDoc<?>> counterparts = new HashMap JavaDoc<Class JavaDoc<?>, Class JavaDoc<?>>();
73     for (Map.Entry JavaDoc<Class JavaDoc<?>, Class JavaDoc<?>> entry : primitiveToWrapper.entrySet()) {
74       Class JavaDoc<?> key = entry.getKey();
75       Class JavaDoc<?> value = entry.getValue();
76       counterparts.put(key, value);
77       counterparts.put(value, key);
78     }
79
80     PRIMITIVE_COUNTERPARTS = Collections.unmodifiableMap(counterparts);
81   }
82
83   private static final Map JavaDoc<Class JavaDoc<?>, Converter<?>> PRIMITIVE_CONVERTERS
84       = new PrimitiveConverters();
85
86   final ConstructionProxyFactory constructionProxyFactory;
87   final Map JavaDoc<Key<?>, BindingImpl<?>> bindings;
88   final BindingsMultimap bindingsMultimap = new BindingsMultimap();
89   final Map JavaDoc<Class JavaDoc<? extends Annotation JavaDoc>, Scope> scopes;
90
91   ErrorHandler errorHandler = new InvalidErrorHandler();
92   Object JavaDoc defaultSource = SourceProviders.UNKNOWN_SOURCE;
93
94   InjectorImpl(ConstructionProxyFactory constructionProxyFactory,
95       Map JavaDoc<Key<?>, BindingImpl<?>> bindings,
96       Map JavaDoc<Class JavaDoc<? extends Annotation JavaDoc>, Scope> scopes) {
97     this.constructionProxyFactory = constructionProxyFactory;
98     this.bindings = bindings;
99     this.scopes = scopes;
100   }
101
102   /**
103    * Indexes bindings by type.
104    */

105   void index() {
106     for (BindingImpl<?> binding : bindings.values()) {
107       index(binding);
108     }
109   }
110
111   <T> void index(BindingImpl<T> binding) {
112     bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
113   }
114
115   // not test-covered
116
public <T> List JavaDoc<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
117     return Collections.<Binding<T>>unmodifiableList(
118         bindingsMultimap.getAll(type));
119   }
120
121   // not test-covered
122
<T> List JavaDoc<String JavaDoc> getNamesOfBindingAnnotations(TypeLiteral<T> type) {
123     List JavaDoc<String JavaDoc> names = new ArrayList JavaDoc<String JavaDoc>();
124     for (Binding<T> binding : findBindingsByType(type)) {
125       Key<T> key = binding.getKey();
126       if (!key.hasAnnotationType()) {
127         names.add("[no annotation]");
128       } else {
129         names.add(key.getAnnotationName());
130       }
131     }
132     return names;
133   }
134
135   /**
136    * This is only used during Injector building.
137    */

138   void withDefaultSource(Object JavaDoc defaultSource, Runnable JavaDoc runnable) {
139     Object JavaDoc previous = this.defaultSource;
140     this.defaultSource = defaultSource;
141     try {
142       runnable.run();
143     }
144     finally {
145       this.defaultSource = previous;
146     }
147   }
148
149   void setErrorHandler(ErrorHandler errorHandler) {
150     this.errorHandler = errorHandler;
151   }
152
153   <T> InternalFactory<? extends T> getInternalFactory(
154       final Member JavaDoc member, Key<T> key) {
155     // TODO: Clean up unchecked type warnings.
156

157     // Do we have a factory for the specified type and name?
158
BindingImpl<T> binding = getBinding(key);
159     if (binding != null) {
160       return binding.getInternalFactory();
161     }
162
163     Class JavaDoc<? super T> rawType = key.getTypeLiteral().getRawType();
164
165     // Handle cases where T is a Provider<?>.
166
if (rawType.equals(Provider.class)) {
167       Type JavaDoc providerType = key.getTypeLiteral().getType();
168       if (!(providerType instanceof ParameterizedType JavaDoc)) {
169         // Raw Provider.
170
return null;
171       }
172       Type JavaDoc entryType
173           = ((ParameterizedType JavaDoc) providerType).getActualTypeArguments()[0];
174
175       try {
176         final Provider<?> provider = getProvider(key.ofType(entryType));
177         return new InternalFactory<T>() {
178           @SuppressWarnings JavaDoc("unchecked")
179           public T get(InternalContext context) {
180             return (T) provider;
181           }
182         };
183       }
184       catch (ConfigurationException e) {
185         // Look for a factory bound to a key without annotation attributes if
186
// necessary.
187
if (key.hasAttributes()) {
188           return getInternalFactory(member, key.withoutAttributes());
189         }
190
191         // End of the road.
192
ErrorMessages.handleMissingBinding(errorHandler, member, key,
193             getNamesOfBindingAnnotations(key.getTypeLiteral()));
194         return invalidFactory();
195       }
196     }
197
198     // Auto[un]box primitives.
199
Class JavaDoc<?> primitiveCounterpart
200         = PRIMITIVE_COUNTERPARTS.get(rawType);
201     if (primitiveCounterpart != null) {
202       BindingImpl<?> counterpartBinding
203           = getBinding(key.ofType(primitiveCounterpart));
204       if (counterpartBinding != null) {
205         return (InternalFactory<? extends T>)
206             counterpartBinding.getInternalFactory();
207       }
208     }
209
210     // TODO: Should we try to convert from a String first, or should we look
211
// for a binding to the annotation type sans attributes? Right now, we
212
// convert from a String.
213

214     // Can we convert from a String constant?
215
Key<String JavaDoc> stringKey = key.ofType(String JavaDoc.class);
216     BindingImpl<String JavaDoc> stringBinding = getBinding(stringKey);
217     if (stringBinding != null && stringBinding.isConstant()) {
218       // We don't need do pass in an InternalContext because we know this is
219
// a ConstantFactory which will not use it.
220
String JavaDoc value = stringBinding.getInternalFactory().get(null);
221
222       // TODO: Generalize everything below here and enable users to plug in
223
// their own converters.
224

225       // Do we need a primitive?
226
Converter<T> converter = (Converter<T>) PRIMITIVE_CONVERTERS.get(rawType);
227       if (converter != null) {
228         try {
229           T t = converter.convert(member, key, value);
230           return new ConstantFactory<T>(t);
231         }
232         catch (ConstantConversionException e) {
233           return handleConstantConversionError(
234               member, stringBinding, rawType, e);
235         }
236       }
237
238       // Do we need an enum?
239
if (Enum JavaDoc.class.isAssignableFrom(rawType)) {
240         T t;
241         try {
242           t = (T) Enum.valueOf((Class JavaDoc) rawType, value);
243         }
244         catch (IllegalArgumentException JavaDoc e) {
245           return handleConstantConversionError(
246               member, stringBinding, rawType, e);
247         }
248         return new ConstantFactory<T>(t);
249       }
250
251       // Do we need a class?
252
if (rawType == Class JavaDoc.class) {
253         try {
254           // TODO: Make sure we use the right classloader.
255
return new ConstantFactory<T>((T) Class.forName(value));
256         }
257         catch (ClassNotFoundException JavaDoc e) {
258           return handleConstantConversionError(
259               member, stringBinding, rawType, e);
260         }
261       }
262     }
263
264     // Don't try to inject primitives, arrays, or enums.
265
int modifiers = rawType.getModifiers();
266     if (rawType.isArray() || rawType.isEnum() || rawType.isPrimitive()) {
267       // Look for a factory bound to a key without annotation attributes if
268
// necessary.
269
if (key.hasAttributes()) {
270         return getInternalFactory(member, key.withoutAttributes());
271       }
272
273       return null;
274     }
275
276     // We don't want to implicitly inject a member if we have a binding
277
// annotation.
278
if (key.hasAnnotationType()) {
279       // Look for a factory bound to a key without annotation attributes if
280
// necessary.
281
if (key.hasAttributes()) {
282         return getInternalFactory(member, key.withoutAttributes());
283       }
284
285       return null;
286     }
287
288     // Last resort: inject the type itself.
289
if (member != null) {
290       // If we're injecting into a member, include it in the error messages.
291
final ErrorHandler previous = this.errorHandler;
292       this.errorHandler = new AbstractErrorHandler() {
293         public void handle(Object JavaDoc source, String JavaDoc message) {
294           previous.handle(source, "Error while injecting at "
295               + StackTraceElements.forMember(member) + ": " + message);
296         }
297       };
298       try {
299         // note: intelliJ thinks this cast is superfluous, but is it?
300
return (InternalFactory<? extends T>) getImplicitBinding(member,
301             rawType, null);
302       }
303       finally {
304         this.errorHandler = previous;
305       }
306     }
307     // note: intelliJ thinks this cast is superfluous, but is it?
308
return (InternalFactory<? extends T>) getImplicitBinding(member, rawType,
309         null);
310   }
311
312   private <T> InternalFactory<T> handleConstantConversionError(
313       Member JavaDoc member, Binding<String JavaDoc> stringBinding, Class JavaDoc<?> rawType,
314       Exception JavaDoc e) {
315     errorHandler.handle(
316         StackTraceElements.forMember(member),
317         ErrorMessages.CONSTANT_CONVERSION_ERROR,
318         stringBinding.getSource(),
319         rawType,
320         e.getMessage());
321     return invalidFactory();
322   }
323
324   /**
325    * Field and method injectors.
326    */

327   final Map JavaDoc<Class JavaDoc<?>, List JavaDoc<SingleMemberInjector>> injectors
328       = new ReferenceCache<Class JavaDoc<?>, List JavaDoc<SingleMemberInjector>>() {
329     protected List JavaDoc<SingleMemberInjector> create(Class JavaDoc<?> key) {
330       List JavaDoc<SingleMemberInjector> injectors
331           = new ArrayList JavaDoc<SingleMemberInjector>();
332       addInjectors(key, injectors);
333       return injectors;
334     }
335   };
336
337   /**
338    * Recursively adds injectors for fields and methods from the given class to
339    * the given list. Injects parent classes before sub classes.
340    */

341   void addInjectors(Class JavaDoc clazz, List JavaDoc<SingleMemberInjector> injectors) {
342     if (clazz == Object JavaDoc.class) {
343       return;
344     }
345
346     // Add injectors for superclass first.
347
addInjectors(clazz.getSuperclass(), injectors);
348
349     // TODO (crazybob): Filter out overridden members.
350
addSingleInjectorsForFields(clazz.getDeclaredFields(), false, injectors);
351     addSingleInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors);
352   }
353
354   void addSingleInjectorsForMethods(Method JavaDoc[] methods, boolean statics,
355       List JavaDoc<SingleMemberInjector> injectors) {
356     addInjectorsForMembers(Arrays.asList(methods), statics, injectors,
357         new SingleInjectorFactory<Method JavaDoc>() {
358           public SingleMemberInjector create(InjectorImpl injector,
359               Method JavaDoc method) throws MissingDependencyException {
360             return new SingleMethodInjector(injector, method);
361           }
362         });
363   }
364
365   void addSingleInjectorsForFields(Field JavaDoc[] fields, boolean statics,
366       List JavaDoc<SingleMemberInjector> injectors) {
367     addInjectorsForMembers(Arrays.asList(fields), statics, injectors,
368         new SingleInjectorFactory<Field JavaDoc>() {
369           public SingleMemberInjector create(InjectorImpl injector,
370               Field JavaDoc field) throws MissingDependencyException {
371             return new SingleFieldInjector(injector, field);
372           }
373         });
374   }
375
376   <M extends Member JavaDoc & AnnotatedElement JavaDoc> void addInjectorsForMembers(
377       List JavaDoc<M> members, boolean statics, List JavaDoc<SingleMemberInjector> injectors,
378       SingleInjectorFactory<M> injectorFactory) {
379     for (M member : members) {
380       if (isStatic(member) == statics) {
381         Inject inject = member.getAnnotation(Inject.class);
382         if (inject != null) {
383           try {
384             injectors.add(injectorFactory.create(this, member));
385           }
386           catch (MissingDependencyException e) {
387             if (!inject.optional()) {
388               // TODO: Report errors for more than one parameter per member.
389
e.handle(errorHandler);
390             }
391           }
392         }
393       }
394     }
395   }
396
397   Map JavaDoc<Key<?>, BindingImpl<?>> internalBindings() {
398     return bindings;
399   }
400
401   // not test-covered
402
public Map JavaDoc<Key<?>, Binding<?>> getBindings() {
403     return Collections.<Key<?>, Binding<?>>unmodifiableMap(bindings);
404   }
405
406   @SuppressWarnings JavaDoc("unchecked")
407   public <T> BindingImpl<T> getBinding(Key<T> key) {
408     return (BindingImpl<T>) bindings.get(key);
409   }
410
411   interface SingleInjectorFactory<M extends Member JavaDoc & AnnotatedElement JavaDoc> {
412     SingleMemberInjector create(InjectorImpl injector, M member)
413         throws MissingDependencyException;
414   }
415
416   private boolean isStatic(Member JavaDoc member) {
417     return Modifier.isStatic(member.getModifiers());
418   }
419
420   private static class BindingsMultimap {
421     private final Map JavaDoc<TypeLiteral<?>, List JavaDoc<? extends BindingImpl<?>>> map
422         = new HashMap JavaDoc<TypeLiteral<?>, List JavaDoc<? extends BindingImpl<?>>>();
423
424     public <T> void put(TypeLiteral<T> type, BindingImpl<T> binding) {
425       List JavaDoc<BindingImpl<T>> bindingsForThisType = getFromMap(type);
426       if (bindingsForThisType == null) {
427         bindingsForThisType = new ArrayList JavaDoc<BindingImpl<T>>();
428         // We only put matching entries into the map
429
map.put(type, bindingsForThisType);
430       }
431       bindingsForThisType.add(binding);
432     }
433
434     public <T> List JavaDoc<BindingImpl<T>> getAll(TypeLiteral<T> type) {
435       List JavaDoc<BindingImpl<T>> list = getFromMap(type);
436       return list == null ? Collections.<BindingImpl<T>>emptyList() : list;
437     }
438
439     // safe because we only put matching entries into the map
440
@SuppressWarnings JavaDoc("unchecked")
441     private <T> List JavaDoc<BindingImpl<T>> getFromMap(TypeLiteral<T> type) {
442       return (List JavaDoc<BindingImpl<T>>) map.get(type);
443     }
444   }
445
446   class SingleFieldInjector implements SingleMemberInjector {
447
448     final Field JavaDoc field;
449     final InternalFactory<?> factory;
450     final ExternalContext<?> externalContext;
451
452     public SingleFieldInjector(InjectorImpl injector, Field JavaDoc field)
453         throws MissingDependencyException {
454       this.field = field;
455
456       // Ewwwww...
457
field.setAccessible(true);
458
459       Key<?> key = Key.get(
460           field.getGenericType(), field, field.getAnnotations(), errorHandler);
461       factory = injector.getInternalFactory(field, key);
462       if (factory == null) {
463         throw new MissingDependencyException(key, field);
464       }
465
466       this.externalContext = ExternalContext.newInstance(field, key, injector);
467     }
468
469     public void inject(InternalContext context, Object JavaDoc o) {
470       ExternalContext<?> previous = context.getExternalContext();
471       context.setExternalContext(externalContext);
472       try {
473         Object JavaDoc value = factory.get(context);
474         if (value == null) {
475           throw new AssertionError JavaDoc(); // we should have prevented this
476
}
477         field.set(o, value);
478       }
479       catch (IllegalAccessException JavaDoc e) {
480         throw new AssertionError JavaDoc(e);
481       }
482       catch (ConfigurationException e) {
483         throw e;
484       }
485       catch (Throwable JavaDoc throwable) {
486         throw new ProvisionException(externalContext, throwable);
487       }
488       finally {
489         context.setExternalContext(previous);
490       }
491     }
492   }
493
494   /**
495    * Gets parameter injectors.
496    *
497    * @param member to which the parameters belong
498    * @param annotations on the parameters
499    * @param parameterTypes parameter types
500    * @return injections
501    */

502   <M extends AccessibleObject JavaDoc & Member JavaDoc>
503   SingleParameterInjector<?>[] getParametersInjectors(M member,
504       Annotation JavaDoc[][] annotations, Type JavaDoc[] parameterTypes)
505       throws MissingDependencyException {
506     SingleParameterInjector<?>[] parameterInjectors
507         = new SingleParameterInjector<?>[parameterTypes.length];
508     Iterator JavaDoc<Annotation JavaDoc[]> annotationsIterator
509         = Arrays.asList(annotations).iterator();
510     int index = 0;
511     for (Type JavaDoc parameterType : parameterTypes) {
512       Annotation JavaDoc[] parameterAnnotations = annotationsIterator.next();
513       Key<?> key = Key.get(
514           parameterType, member, parameterAnnotations, errorHandler);
515       parameterInjectors[index] = createParameterInjector(key, member, index);
516       index++;
517     }
518
519     return parameterInjectors;
520   }
521
522   <T> SingleParameterInjector<T> createParameterInjector(
523       Key<T> key, Member JavaDoc member, int index) throws MissingDependencyException {
524     InternalFactory<? extends T> factory = getInternalFactory(member, key);
525     if (factory == null) {
526       throw new MissingDependencyException(key, member);
527     }
528
529     ExternalContext<T> externalContext
530         = ExternalContext.newInstance(member, index, key, this);
531     return new SingleParameterInjector<T>(externalContext, factory);
532   }
533
534   static class SingleMethodInjector implements SingleMemberInjector {
535
536     final MethodInvoker methodInvoker;
537     final SingleParameterInjector<?>[] parameterInjectors;
538
539     public SingleMethodInjector(InjectorImpl injector, final Method JavaDoc method)
540         throws MissingDependencyException {
541       // We can't use FastMethod if the method is private.
542
if (Modifier.isPrivate(method.getModifiers())
543           || Modifier.isProtected(method.getModifiers())) {
544         method.setAccessible(true);
545         this.methodInvoker = new MethodInvoker() {
546           public Object JavaDoc invoke(Object JavaDoc target, Object JavaDoc... parameters) throws
547               IllegalAccessException JavaDoc, InvocationTargetException JavaDoc {
548             Objects.assertNoNulls(parameters);
549             return method.invoke(target, parameters);
550           }
551         };
552       }
553       else {
554         FastClass fastClass = GuiceFastClass.create(method.getDeclaringClass());
555         final FastMethod fastMethod = fastClass.getMethod(method);
556
557         this.methodInvoker = new MethodInvoker() {
558           public Object JavaDoc invoke(Object JavaDoc target, Object JavaDoc... parameters)
559           throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc {
560             Objects.assertNoNulls(parameters);
561             return fastMethod.invoke(target, parameters);
562           }
563         };
564       }
565
566       Type JavaDoc[] parameterTypes = method.getGenericParameterTypes();
567       parameterInjectors = parameterTypes.length > 0
568           ? injector.getParametersInjectors(
569               method, method.getParameterAnnotations(), parameterTypes)
570           : null;
571     }
572
573     public void inject(InternalContext context, Object JavaDoc o) {
574       try {
575         methodInvoker.invoke(o, getParameters(context, parameterInjectors));
576       }
577       catch (Exception JavaDoc e) {
578         throw new RuntimeException JavaDoc(e);
579       }
580     }
581   }
582
583   /**
584    * Invokes a method.
585    */

586   interface MethodInvoker {
587     Object JavaDoc invoke(Object JavaDoc target, Object JavaDoc... parameters) throws
588         IllegalAccessException JavaDoc, InvocationTargetException JavaDoc;
589   }
590
591   final Map JavaDoc<Class JavaDoc<?>, ConstructorInjector> constructors
592       = new ReferenceCache<Class JavaDoc<?>, ConstructorInjector>() {
593     @SuppressWarnings JavaDoc("unchecked")
594     protected ConstructorInjector<?> create(Class JavaDoc<?> implementation) {
595       if (implementation.isInterface()) {
596         errorHandler.handle(defaultSource,
597             ErrorMessages.CANNOT_INJECT_ABSTRACT_TYPE, implementation);
598         return ConstructorInjector.invalidConstructor();
599       }
600
601       return new ConstructorInjector(InjectorImpl.this, implementation);
602     }
603   };
604
605   /**
606    * A placeholder. This enables us to continue processing and gather more
607    * errors but blows up if you actually try to use it.
608    */

609   static class InvalidConstructor {
610     InvalidConstructor() {
611       throw new AssertionError JavaDoc();
612     }
613   }
614
615   @SuppressWarnings JavaDoc("unchecked")
616   static <T> Constructor JavaDoc<T> invalidConstructor() {
617     try {
618       return (Constructor JavaDoc<T>) InvalidConstructor.class.getDeclaredConstructor();
619     }
620     catch (NoSuchMethodException JavaDoc e) {
621       throw new AssertionError JavaDoc(e);
622     }
623   }
624
625   static class SingleParameterInjector<T> {
626
627     final ExternalContext<T> externalContext;
628     final InternalFactory<? extends T> factory;
629
630     public SingleParameterInjector(ExternalContext<T> externalContext,
631         InternalFactory<? extends T> factory) {
632       this.externalContext = externalContext;
633       this.factory = factory;
634     }
635
636     T inject(InternalContext context) {
637       ExternalContext<?> previous = context.getExternalContext();
638       context.setExternalContext(externalContext);
639       try {
640         return factory.get(context);
641       }
642       catch (ConfigurationException e) {
643         throw e;
644       }
645       catch (Throwable JavaDoc throwable) {
646         throw new ProvisionException(externalContext, throwable);
647       }
648       finally {
649         context.setExternalContext(previous);
650       }
651     }
652   }
653
654   /**
655    * Iterates over parameter injectors and creates an array of parameter
656    * values.
657    */

658   static Object JavaDoc[] getParameters(InternalContext context,
659       SingleParameterInjector[] parameterInjectors) {
660     if (parameterInjectors == null) {
661       return null;
662     }
663
664     Object JavaDoc[] parameters = new Object JavaDoc[parameterInjectors.length];
665     for (int i = 0; i < parameters.length; i++) {
666       parameters[i] = parameterInjectors[i].inject(context);
667     }
668     return parameters;
669   }
670
671   void injectMembers(Object JavaDoc o, InternalContext context) {
672     List JavaDoc<SingleMemberInjector> injectorsForClass = injectors.get(o.getClass());
673     for (SingleMemberInjector injector : injectorsForClass) {
674       injector.inject(context, o);
675     }
676   }
677
678   // Not test-covered
679
public void injectMembers(final Object JavaDoc o) {
680     callInContext(new ContextualCallable<Void JavaDoc>() {
681       public Void JavaDoc call(InternalContext context) {
682         injectMembers(o, context);
683         return null;
684       }
685     });
686   }
687
688   public <T> Provider<T> getProvider(Class JavaDoc<T> type) {
689     return getProvider(Key.get(type));
690   }
691
692   public <T> Provider<T> getProvider(final Key<T> key) {
693     final InternalFactory<? extends T> factory = getInternalFactory(null, key);
694
695     if (factory == null) {
696       throw new ConfigurationException(
697           "Missing binding to " + ErrorMessages.convert(key) + ".");
698     }
699
700     return new Provider<T>() {
701       public T get() {
702         return callInContext(new ContextualCallable<T>() {
703           public T call(InternalContext context) {
704             ExternalContext<?> previous = context.getExternalContext();
705             context.setExternalContext(
706                 ExternalContext.newInstance(null, key, InjectorImpl.this));
707             try {
708               return factory.get(context);
709             }
710             finally {
711               context.setExternalContext(previous);
712             }
713           }
714         });
715       }
716
717       public String JavaDoc toString() {
718         return factory.toString();
719       }
720     };
721   }
722
723   public <T> T getInstance(Key<T> key) {
724     return getProvider(key).get();
725   }
726
727   public <T> T getInstance(Class JavaDoc<T> type) {
728     return getProvider(type).get();
729   }
730
731   final ThreadLocal JavaDoc<InternalContext[]> localContext
732       = new ThreadLocal JavaDoc<InternalContext[]>() {
733     protected InternalContext[] initialValue() {
734       return new InternalContext[1];
735     }
736   };
737
738   /**
739    * Looks up thread local context. Creates (and removes) a new context if
740    * necessary.
741    */

742   <T> T callInContext(ContextualCallable<T> callable) {
743     InternalContext[] reference = localContext.get();
744     if (reference[0] == null) {
745       reference[0] = new InternalContext(this);
746       try {
747         return callable.call(reference[0]);
748       }
749       finally {
750         // Only remove the context if this call created it.
751
reference[0] = null;
752       }
753     }
754     else {
755       // Someone else will clean up this context.
756
return callable.call(reference[0]);
757     }
758   }
759
760   /**
761    * Gets a constructor function for a given implementation class.
762    */

763   @SuppressWarnings JavaDoc("unchecked")
764   <T> ConstructorInjector<T> getConstructor(Class JavaDoc<T> implementation) {
765     return constructors.get(implementation);
766   }
767
768   @SuppressWarnings JavaDoc("unchecked")
769   <T> ConstructorInjector<T> getConstructor(TypeLiteral<T> implementation) {
770     return constructors.get(implementation.getRawType());
771   }
772
773   /**
774    * Injects a field or method in a given object.
775    */

776   interface SingleMemberInjector {
777     void inject(InternalContext context, Object JavaDoc o);
778   }
779
780   class MissingDependencyException extends Exception JavaDoc {
781
782     final Key<?> key;
783     final Member JavaDoc member;
784
785     MissingDependencyException(Key<?> key, Member JavaDoc member) {
786       this.key = key;
787       this.member = member;
788     }
789
790     void handle(ErrorHandler errorHandler) {
791       ErrorMessages.handleMissingBinding(errorHandler, member, key,
792           getNamesOfBindingAnnotations(key.getTypeLiteral()));
793     }
794   }
795
796   /**
797    * Map of primitive type converters.
798    */

799   static class PrimitiveConverters extends HashMap JavaDoc<Class JavaDoc<?>, Converter<?>> {
800
801     PrimitiveConverters() {
802       putParser(int.class);
803       putParser(long.class);
804       putParser(boolean.class);
805       putParser(byte.class);
806       putParser(short.class);
807       putParser(float.class);
808       putParser(double.class);
809
810       // Character doesn't follow the same pattern.
811
Converter<Character JavaDoc> characterConverter = new Converter<Character JavaDoc>() {
812         public Character JavaDoc convert(Member JavaDoc member, Key<Character JavaDoc> key,
813             String JavaDoc value) throws ConstantConversionException {
814           value = value.trim();
815           if (value.length() != 1) {
816             throw new ConstantConversionException(member, key, value,
817                 "Length != 1.");
818           }
819           return value.charAt(0);
820         }
821       };
822       put(char.class, characterConverter);
823       put(Character JavaDoc.class, characterConverter);
824     }
825
826     <T> void putParser(final Class JavaDoc<T> primitive) {
827       try {
828         Class JavaDoc<?> wrapper = PRIMITIVE_COUNTERPARTS.get(primitive);
829         final Method JavaDoc parser = wrapper.getMethod(
830             "parse" + Strings.capitalize(primitive.getName()), String JavaDoc.class);
831         Converter<T> converter = new Converter<T>() {
832           @SuppressWarnings JavaDoc("unchecked")
833           public T convert(Member JavaDoc member, Key<T> key, String JavaDoc value)
834               throws ConstantConversionException {
835             try {
836               return (T) parser.invoke(null, value);
837             }
838             catch (IllegalAccessException JavaDoc e) {
839               throw new AssertionError JavaDoc(e);
840             }
841             catch (InvocationTargetException JavaDoc e) {
842               throw new ConstantConversionException(member, key, value,
843                   e.getTargetException());
844             }
845           }
846         };
847         put(wrapper, converter);
848         put(primitive, converter);
849       }
850       catch (NoSuchMethodException JavaDoc e) {
851         throw new AssertionError JavaDoc(e);
852       }
853     }
854   }
855
856   /**
857    * Converts a {@code String} to another type.
858    */

859   interface Converter<T> {
860
861     /**
862      * Converts {@code String} value.
863      */

864     T convert(Member JavaDoc member, Key<T> key, String JavaDoc value)
865         throws ConstantConversionException;
866   }
867
868   Map JavaDoc<Class JavaDoc<?>, InternalFactory<?>> implicitBindings =
869       new HashMap JavaDoc<Class JavaDoc<?>, InternalFactory<?>>();
870
871   /**
872    * Gets a factory for the specified type. Used when an explicit binding
873    * was not made. Uses synchronization here so it's not necessary in the
874    * factory itself. Returns {@code null} if the type isn't injectable.
875    */

876   <T> InternalFactory<? extends T> getImplicitBinding(Member JavaDoc member,
877       final Class JavaDoc<T> type, Scope scope) {
878     // Look for @DefaultImplementation.
879
ImplementedBy implementedBy =
880         type.getAnnotation(ImplementedBy.class);
881     if (implementedBy != null) {
882       Class JavaDoc<?> implementationType = implementedBy.value();
883
884       // Make sure it's not the same type. TODO: Can we check for deeper loops?
885
if (implementationType == type) {
886         errorHandler.handle(StackTraceElements.forType(type),
887             ErrorMessages.RECURSIVE_IMPLEMENTATION_TYPE, type);
888         return invalidFactory();
889       }
890
891       // Make sure implementationType extends type.
892
if (!type.isAssignableFrom(implementationType)) {
893         errorHandler.handle(StackTraceElements.forType(type),
894             ErrorMessages.NOT_A_SUBTYPE, implementationType, type);
895         return invalidFactory();
896       }
897
898       return (InternalFactory<T>) getInternalFactory(
899           member, Key.get(implementationType));
900     }
901
902     // Look for @DefaultProvider.
903
ProvidedBy providedBy = type.getAnnotation(ProvidedBy.class);
904     if (providedBy != null) {
905       final Class JavaDoc<? extends Provider<?>> providerType = providedBy.value();
906
907       // Make sure it's not the same type. TODO: Can we check for deeper loops?
908
if (providerType == type) {
909         errorHandler.handle(StackTraceElements.forType(type),
910             ErrorMessages.RECURSIVE_PROVIDER_TYPE, type);
911         return invalidFactory();
912       }
913
914       // TODO: Make sure the provided type extends type. We at least check
915
// the type at runtime below.
916

917       InternalFactory<? extends Provider<?>> providerFactory
918           = getInternalFactory(member, Key.get(providerType));
919       Key<? extends Provider<?>> providerKey = Key.get(providerType);
920       return (InternalFactory<T>) new BoundProviderFactory(
921           providerKey, providerFactory, StackTraceElements.forType(type)) {
922         public Object JavaDoc get(InternalContext context) {
923           Object JavaDoc o = super.get(context);
924           try {
925             return type.cast(o);
926           } catch (ClassCastException JavaDoc e) {
927             errorHandler.handle(StackTraceElements.forType(type),
928                 ErrorMessages.SUBTYPE_NOT_PROVIDED, providerType, type);
929             throw new AssertionError JavaDoc();
930           }
931         }
932       };
933     }
934
935     // TODO: Method interceptors could actually enable us to implement
936
// abstract types. Should we remove this restriction?
937
if (Modifier.isAbstract(type.getModifiers())) {
938       return null;
939     }
940
941     // Inject the class itself.
942
synchronized (implicitBindings) {
943       @SuppressWarnings JavaDoc("unchecked")
944       InternalFactory<T> factory =
945           (InternalFactory<T>) implicitBindings.get(type);
946       if (factory != null) {
947         return factory;
948       }
949
950       // Create the factory.
951
ImplicitBinding<T> implicitBinding = new ImplicitBinding<T>(type);
952
953       // Scope the factory if necessary.
954

955       // If we don't have a scope from the configuration, look for one on
956
// the type.
957
if (scope == null) {
958         scope = Scopes.getScopeForType(type, scopes, errorHandler);
959       }
960
961       InternalFactory<? extends T> scoped;
962       if (scope != null) {
963         scoped = Scopes.scope(Key.get(type), this, implicitBinding, scope);
964       } else {
965         scoped = implicitBinding;
966       }
967
968       implicitBindings.put(type, scoped);
969
970       try {
971         // Look up the constructor. We do this separately from constructions to
972
// support circular dependencies.
973
ConstructorInjector<T> constructor = getConstructor(type);
974         implicitBinding.setConstructorInjector(constructor);
975       }
976       catch (RuntimeException JavaDoc e) {
977         // Clean up state.
978
implicitBindings.remove(type);
979         throw e;
980       }
981       catch (Throwable JavaDoc t) {
982         // Clean up state.
983
implicitBindings.remove(type);
984         throw new AssertionError JavaDoc(t);
985       }
986       
987       return scoped;
988     }
989   }
990
991   static class ImplicitBinding<T> implements InternalFactory<T> {
992
993     final Class JavaDoc<T> implementation;
994     ConstructorInjector<T> constructorInjector;
995
996     ImplicitBinding(Class JavaDoc<T> implementation) {
997       this.implementation = implementation;
998     }
999
1000    void setConstructorInjector(
1001        ConstructorInjector<T> constructorInjector) {
1002      this.constructorInjector = constructorInjector;
1003    }
1004
1005    public T get(InternalContext context) {
1006      return (T) constructorInjector.construct(context,
1007          context.getExpectedType());
1008    }
1009  }
1010
1011  private static final InternalFactory<?> INVALID_FACTORY
1012      = new InternalFactory<Object JavaDoc>() {
1013    public Object JavaDoc get(InternalContext context) {
1014      throw new AssertionError JavaDoc();
1015    }
1016  };
1017
1018  @SuppressWarnings JavaDoc("unchecked")
1019  static <T> InternalFactory<T> invalidFactory() {
1020    return (InternalFactory<T>) INVALID_FACTORY;
1021  }
1022
1023  public String JavaDoc toString() {
1024    return new ToStringBuilder(Injector.class)
1025        .add("bindings", bindings)
1026        .toString();
1027  }
1028}
1029
Popular Tags