blob: 498cb1b9797693bcf2c7021bd28f59255cb06a94 [file] [log] [blame]
crazyboblee66b415a2006-08-25 02:01:19 +00001/**
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
17package com.google.inject;
18
limpbizkit916f5482008-04-16 20:51:14 +000019import com.google.inject.internal.*;
limpbizkit3b1cd582008-04-28 00:06:01 +000020import com.google.inject.spi.*;
crazyboblee712705c2007-09-07 03:20:30 +000021import com.google.inject.util.Providers;
kevinb9n225310e2007-02-20 04:12:01 +000022import net.sf.cglib.reflect.FastClass;
23import net.sf.cglib.reflect.FastMethod;
crazyboblee66b415a2006-08-25 02:01:19 +000024
limpbizkit3b1cd582008-04-28 00:06:01 +000025import java.lang.annotation.Annotation;
26import java.lang.reflect.*;
27import java.util.*;
28
crazyboblee66b415a2006-08-25 02:01:19 +000029/**
kevinb9na2915a92007-02-28 06:20:30 +000030 * Default {@link Injector} implementation.
crazyboblee66b415a2006-08-25 02:01:19 +000031 *
crazyboblee66b415a2006-08-25 02:01:19 +000032 * @author crazybob@google.com (Bob Lee)
limpbizkit3d58d6b2008-03-08 16:11:47 +000033 * @see InjectorBuilder
crazyboblee66b415a2006-08-25 02:01:19 +000034 */
kevinb9na2915a92007-02-28 06:20:30 +000035class InjectorImpl implements Injector {
crazyboblee66b415a2006-08-25 02:01:19 +000036
crazybobleefc9337f2007-01-26 00:51:34 +000037 /**
38 * Maps between primitive types and their wrappers and vice versa.
39 */
40 private static final Map<Class<?>, Class<?>> PRIMITIVE_COUNTERPARTS;
41 static {
42 Map<Class<?>, Class<?>> primitiveToWrapper =
43 new HashMap<Class<?>, Class<?>>() {{
44 put(int.class, Integer.class);
45 put(long.class, Long.class);
46 put(boolean.class, Boolean.class);
47 put(byte.class, Byte.class);
48 put(short.class, Short.class);
49 put(float.class, Float.class);
50 put(double.class, Double.class);
51 put(char.class, Character.class);
52 }};
53
54 Map<Class<?>, Class<?>> counterparts = new HashMap<Class<?>, Class<?>>();
55 for (Map.Entry<Class<?>, Class<?>> entry : primitiveToWrapper.entrySet()) {
56 Class<?> key = entry.getKey();
57 Class<?> value = entry.getValue();
58 counterparts.put(key, value);
59 counterparts.put(value, key);
60 }
61
62 PRIMITIVE_COUNTERPARTS = Collections.unmodifiableMap(counterparts);
63 }
64
dan.halem5d187432008-02-22 22:52:28 +000065 final Injector parentInjector;
limpbizkit3d58d6b2008-03-08 16:11:47 +000066 final Map<Key<?>, BindingImpl<?>> explicitBindings
67 = new HashMap<Key<?>, BindingImpl<?>>();
68 final BindingsMultimap bindingsMultimap = new BindingsMultimap();
69 final Map<Class<? extends Annotation>, Scope> scopes
70 = new HashMap<Class<? extends Annotation>, Scope>();
71 final List<MatcherAndConverter<?>> converters
72 = new ArrayList<MatcherAndConverter<?>>();
dan.halem5d187432008-02-22 22:52:28 +000073 final Map<Key<?>, BindingImpl<?>> parentBindings
74 = new HashMap<Key<?>, BindingImpl<?>>();
limpbizkit51515b52008-03-11 03:46:25 +000075 final Map<Object, Void> outstandingInjections
76 = new IdentityHashMap<Object, Void>();
crazyboblee66b415a2006-08-25 02:01:19 +000077
limpbizkitb1d8ab42008-04-27 08:11:37 +000078 final ErrorHandler errorHandler;
limpbizkit916f5482008-04-16 20:51:14 +000079 Reflection reflection;
crazyboblee4727ee22007-01-30 03:13:38 +000080
limpbizkitb1d8ab42008-04-27 08:11:37 +000081 InjectorImpl(Injector parentInjector, ErrorHandler errorHandler) {
dan.halem5d187432008-02-22 22:52:28 +000082 this.parentInjector = parentInjector;
limpbizkitb1d8ab42008-04-27 08:11:37 +000083 this.errorHandler = errorHandler;
crazyboblee66b415a2006-08-25 02:01:19 +000084 }
85
limpbizkit51515b52008-03-11 03:46:25 +000086 void validateOustandingInjections() {
87 for (Object toInject : outstandingInjections.keySet()) {
88 injectors.get(toInject.getClass());
89 }
90 }
91
92 /**
93 * Performs creation-time injections on all objects that require it. Whenever
94 * fulfilling an injection depends on another object that requires injection,
95 * we use {@link InternalContext#ensureMemberInjected} to inject that member
96 * first.
97 *
98 * <p>If the two objects are codependent (directly or transitively), ordering
99 * of injection is arbitrary.
100 */
101 void fulfillOutstandingInjections() {
102 callInContext(new ContextualCallable<Void>() {
103 public Void call(InternalContext context) {
104 // loop over a defensive copy, since ensureMemberInjected() mutates the
105 // outstandingInjections set
106 for (Object toInject : new ArrayList<Object>(outstandingInjections.keySet())) {
107 context.ensureMemberInjected(toInject);
108 }
109 return null;
110 }
111 });
112
113 if (!outstandingInjections.isEmpty()) {
114 throw new IllegalStateException("failed to satisfy " + outstandingInjections);
115 }
116 }
117
crazyboblee62fcdde2007-02-03 02:10:13 +0000118 /**
119 * Indexes bindings by type.
120 */
121 void index() {
crazyboblee712705c2007-09-07 03:20:30 +0000122 for (BindingImpl<?> binding : explicitBindings.values()) {
crazyboblee62fcdde2007-02-03 02:10:13 +0000123 index(binding);
124 }
125 }
126
crazyboblee1fc49782007-02-25 21:02:47 +0000127 <T> void index(BindingImpl<T> binding) {
crazybobleec3e88492007-02-25 22:36:58 +0000128 bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
crazyboblee62fcdde2007-02-03 02:10:13 +0000129 }
130
kevinb9n225310e2007-02-20 04:12:01 +0000131 // not test-covered
crazyboblee62fcdde2007-02-03 02:10:13 +0000132 public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
crazyboblee1fc49782007-02-25 21:02:47 +0000133 return Collections.<Binding<T>>unmodifiableList(
134 bindingsMultimap.getAll(type));
crazyboblee62fcdde2007-02-03 02:10:13 +0000135 }
136
kevinb9n225310e2007-02-20 04:12:01 +0000137 // not test-covered
crazyboblee4602a6f2007-02-15 02:45:18 +0000138 <T> List<String> getNamesOfBindingAnnotations(TypeLiteral<T> type) {
crazyboblee62fcdde2007-02-03 02:10:13 +0000139 List<String> names = new ArrayList<String>();
140 for (Binding<T> binding : findBindingsByType(type)) {
crazybobleeb1f2e682007-02-15 05:14:32 +0000141 Key<T> key = binding.getKey();
142 if (!key.hasAnnotationType()) {
143 names.add("[no annotation]");
144 } else {
145 names.add(key.getAnnotationName());
146 }
crazyboblee62fcdde2007-02-03 02:10:13 +0000147 }
148 return names;
149 }
150
crazyboblee9a3861b2007-02-20 03:37:31 +0000151 /**
kevinb9na2915a92007-02-28 06:20:30 +0000152 * This is only used during Injector building.
crazyboblee9a3861b2007-02-20 03:37:31 +0000153 */
154 void withDefaultSource(Object defaultSource, Runnable runnable) {
crazyboblee712705c2007-09-07 03:20:30 +0000155 SourceProviders.withDefault(defaultSource, runnable);
crazyboblee4727ee22007-01-30 03:13:38 +0000156 }
157
crazyboblee712705c2007-09-07 03:20:30 +0000158 /**
limpbizkit3b1cd582008-04-28 00:06:01 +0000159 * Returns the binding for {@code key}, or {@code null} if that binding
160 * cannot be resolved.
161 */
162 public <T> BindingImpl<T> getBinding(Key<T> key) {
163 try {
164 return getBindingOrThrow(key);
165 } catch(ResolveFailedException e) {
166 return null;
167 }
168 }
169
170 /**
dan.halem5d187432008-02-22 22:52:28 +0000171 * Gets a binding implementation. First, it check to see if the parent has
172 * a binding. If the parent has a binding and the binding is scoped, it
173 * will use that binding. Otherwise, this checks for an explicit binding.
crazyboblee712705c2007-09-07 03:20:30 +0000174 * If no explicit binding is found, it looks for a just-in-time binding.
175 */
limpbizkit3b1cd582008-04-28 00:06:01 +0000176 public <T> BindingImpl<T> getBindingOrThrow(Key<T> key) throws ResolveFailedException {
dan.halem5d187432008-02-22 22:52:28 +0000177 if (parentInjector != null) {
178 BindingImpl<T> bindingImpl = getParentBinding(key);
179 if (bindingImpl != null) {
180 return bindingImpl;
181 }
182 }
183
crazyboblee712705c2007-09-07 03:20:30 +0000184 // Check explicit bindings, i.e. bindings created by modules.
185 BindingImpl<T> binding = getExplicitBindingImpl(key);
crazybobleea6e73982007-02-02 00:21:07 +0000186 if (binding != null) {
crazyboblee712705c2007-09-07 03:20:30 +0000187 return binding;
crazyboblee07e41822006-11-21 01:27:08 +0000188 }
189
crazyboblee712705c2007-09-07 03:20:30 +0000190 // Look for an on-demand binding.
191 return getJitBindingImpl(key);
192 }
crazybobleef33d23e2007-02-12 04:17:48 +0000193
limpbizkit3b1cd582008-04-28 00:06:01 +0000194
dan.halem5d187432008-02-22 22:52:28 +0000195 /**
196 * Checks the parent injector for a scoped binding, and if available, creates
197 * an appropriate binding local to this injector and remembers it.
198 */
199 @SuppressWarnings("unchecked")
200 private <T> BindingImpl<T> getParentBinding(Key<T> key) {
201 BindingImpl<T> bindingImpl;
202 synchronized(parentBindings) {
203 // null values will mean that the parent doesn't have this binding
204 if (!parentBindings.containsKey(key)) {
205 Binding<T> binding = null;
206 try {
207 binding = parentInjector.getBinding(key);
208 } catch (ConfigurationException e) {
209 // if this happens, the parent can't create this key, and we ignore it
210 }
211 if (binding != null
212 && binding.getScope() != null
213 && !binding.getScope().equals(Scopes.NO_SCOPE)) {
214 bindingImpl = new ProviderInstanceBindingImpl(
215 this,
216 key,
217 binding.getSource(),
218 new InternalFactoryToProviderAdapter(binding.getProvider(),
219 binding.getSource()),
220 Scopes.NO_SCOPE,
221 binding.getProvider());
222 } else {
223 bindingImpl = null;
224 }
225 parentBindings.put(key, bindingImpl);
226 } else {
227 bindingImpl = (BindingImpl<T>) parentBindings.get(key);
228 }
229 }
230 return bindingImpl;
231 }
232
crazyboblee552472f2007-09-07 16:52:39 +0000233 public <T> Binding<T> getBinding(Class<T> type) {
234 return getBinding(Key.get(type));
235 }
236
crazyboblee712705c2007-09-07 03:20:30 +0000237 /**
238 * Gets a binding which was specified explicitly in a module.
239 */
240 @SuppressWarnings("unchecked")
241 <T> BindingImpl<T> getExplicitBindingImpl(Key<T> key) {
242 return (BindingImpl<T>) explicitBindings.get(key);
243 }
244
245 /**
246 * Gets a just-in-time binding. This could be an injectable class (including
247 * those with @ImplementedBy), an automatically converted constant, a
248 * Provider<X> binding, etc.
249 */
250 @SuppressWarnings("unchecked")
limpbizkit3b1cd582008-04-28 00:06:01 +0000251 <T> BindingImpl<T> getJitBindingImpl(Key<T> key) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000252 synchronized (jitBindings) {
253 // Support null values.
254 if (!jitBindings.containsKey(key)) {
255 BindingImpl<T> binding = createBindingJustInTime(key);
256 jitBindings.put(key, binding);
257 return binding;
258 } else {
259 return (BindingImpl<T>) jitBindings.get(key);
crazyboblee63b592b2007-01-25 02:45:24 +0000260 }
limpbizkitc808df02007-08-25 03:25:13 +0000261 }
crazyboblee07e41822006-11-21 01:27:08 +0000262 }
263
crazyboblee712705c2007-09-07 03:20:30 +0000264 /** Just-in-time binding cache. */
265 final Map<Key<?>, BindingImpl<?>> jitBindings
266 = new HashMap<Key<?>, BindingImpl<?>>();
267
268 /**
269 * Returns true if the key type is Provider<?> (but not a subclass of
270 * Provider<?>).
271 */
272 static boolean isProvider(Key<?> key) {
273 return key.getTypeLiteral().getRawType().equals(Provider.class);
274 }
275
276 /**
277 * Creates a synthetic binding to Provider<T>, i.e. a binding to the provider
278 * from Binding<T>.
279 */
280 private <T> BindingImpl<Provider<T>> createProviderBinding(
limpbizkit3b1cd582008-04-28 00:06:01 +0000281 Key<Provider<T>> key) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000282 Type providerType = key.getTypeLiteral().getType();
283
284 // If the Provider has no type parameter (raw Provider)...
285 if (!(providerType instanceof ParameterizedType)) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000286 throw new ResolveFailedException(ErrorMessages.CANNOT_INJECT_RAW_PROVIDER);
crazyboblee712705c2007-09-07 03:20:30 +0000287 }
288
289 Type entryType
290 = ((ParameterizedType) providerType).getActualTypeArguments()[0];
291
292 // This cast is safe.
293 @SuppressWarnings("unchecked")
294 Key<T> providedKey = (Key<T>) key.ofType(entryType);
295
limpbizkit3b1cd582008-04-28 00:06:01 +0000296 return new ProviderBindingImpl<T>(this, key, getBindingOrThrow(providedKey));
crazyboblee712705c2007-09-07 03:20:30 +0000297 }
298
limpbizkit916f5482008-04-16 20:51:14 +0000299 void handleMissingBinding(Object source, Key<?> key) {
300 List<String> otherNames = getNamesOfBindingAnnotations(key.getTypeLiteral());
301
302 if (source instanceof Member) {
303 source = StackTraceElements.forMember((Member) source);
304 }
305
306 if (otherNames.isEmpty()) {
307 errorHandler.handle(source, ErrorMessages.MISSING_BINDING, key);
308 }
309 else {
310 errorHandler.handle(source,
311 ErrorMessages.MISSING_BINDING_BUT_OTHERS_EXIST, key, otherNames);
312 }
313 }
314
crazyboblee712705c2007-09-07 03:20:30 +0000315 static class ProviderBindingImpl<T> extends BindingImpl<Provider<T>>
316 implements ProviderBinding<T> {
317
318 final Binding<T> providedBinding;
319
320 ProviderBindingImpl(InjectorImpl injector, Key<Provider<T>> key,
321 Binding<T> providedBinding) {
322 super(injector, key, SourceProviders.UNKNOWN_SOURCE,
323 createInternalFactory(providedBinding), Scopes.NO_SCOPE);
324 this.providedBinding = providedBinding;
325 }
326
327 static <T> InternalFactory<Provider<T>> createInternalFactory(
328 Binding<T> providedBinding) {
329 final Provider<T> provider = providedBinding.getProvider();
330 return new InternalFactory<Provider<T>>() {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000331 public Provider<T> get(InternalContext context,
332 InjectionPoint injectionPoint) {
crazyboblee712705c2007-09-07 03:20:30 +0000333 return provider;
334 }
335 };
336 }
337
338 public void accept(BindingVisitor<? super Provider<T>> bindingVisitor) {
339 bindingVisitor.visit(this);
340 }
341
342 public Binding<T> getTarget() {
343 return providedBinding;
344 }
345 }
346
347 <T> BindingImpl<T> invalidBinding(Class<T> clazz) {
348 return invalidBinding(Key.get(clazz));
349 }
350
351 <T> BindingImpl<T> invalidBinding(Key<T> key) {
352 return new InvalidBindingImpl<T>(
353 this, key, SourceProviders.defaultSource());
354 }
355
356 /**
357 * Gets the binding corresponding to a primitives wrapper type or a wrapper
358 * type's primitive. The compiler treats them interchangeably, so we do, too.
359 */
360 <T> BindingImpl<T> getBoxedOrUnboxedBinding(Key<T> key) {
361 // This is a safe cast, just as this is safe: Class<Integer> c = int.class;
362 @SuppressWarnings("unchecked")
363 Class<T> primitiveCounterpart
364 = (Class<T>) PRIMITIVE_COUNTERPARTS.get(key.getRawType());
365 if (primitiveCounterpart != null) {
366 // Do we need to search more than explicit bindings? I don't think so.
367 // Constant type conversion already supports both primitives and their
368 // wrappers, and limiting this to explicit bindings means we don't have
369 // to worry about recursion.
370 return getExplicitBindingImpl(key.ofType(primitiveCounterpart));
371 }
372
373 return null;
374 }
375
376 /**
crazyboblee712705c2007-09-07 03:20:30 +0000377 * Converts a constant string binding to the required type.
378 *
379 * <p>If the required type is elligible for conversion and a constant string
380 * binding is found but the actual conversion fails, an error is generated.
381 *
382 * <p>If the type is not elligible for conversion or a constant string
383 * binding is not found, this method returns null.
384 */
limpbizkit3b1cd582008-04-28 00:06:01 +0000385 private <T> BindingImpl<T> convertConstantStringBinding(Key<T> key)
386 throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000387 // Find a constant string binding.
388 Key<String> stringKey = key.ofType(String.class);
389 BindingImpl<String> stringBinding = getExplicitBindingImpl(stringKey);
390 if (stringBinding == null || !stringBinding.isConstant()) {
391 // No constant string binding found.
392 return null;
393 }
394
crazyboblee7c9d7792007-09-09 03:41:05 +0000395 String stringValue = stringBinding.getProvider().get();
crazyboblee712705c2007-09-07 03:20:30 +0000396
crazyboblee7c9d7792007-09-09 03:41:05 +0000397 // Find a matching type converter.
398 TypeLiteral<T> type = key.getTypeLiteral();
399 MatcherAndConverter<?> matchingConverter = null;
400 for (MatcherAndConverter<?> converter : converters) {
limpbizkit916f5482008-04-16 20:51:14 +0000401 if (converter.getTypeMatcher().matches(type)) {
crazyboblee7c9d7792007-09-09 03:41:05 +0000402 if (matchingConverter != null) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000403 throw new ResolveFailedException(ErrorMessages.AMBIGUOUS_TYPE_CONVERSION,
404 stringValue, type, matchingConverter, converter);
crazyboblee7c9d7792007-09-09 03:41:05 +0000405 }
406
407 matchingConverter = converter;
408 }
crazyboblee712705c2007-09-07 03:20:30 +0000409 }
410
crazyboblee7c9d7792007-09-09 03:41:05 +0000411 if (matchingConverter == null) {
412 // No converter can handle the given type.
413 return null;
crazyboblee712705c2007-09-07 03:20:30 +0000414 }
415
crazyboblee7c9d7792007-09-09 03:41:05 +0000416 // Try to convert the string. A failed conversion results in an error.
crazyboblee712705c2007-09-07 03:20:30 +0000417 try {
crazyboblee7c9d7792007-09-09 03:41:05 +0000418 // This cast is safe because we double check below.
crazyboblee712705c2007-09-07 03:20:30 +0000419 @SuppressWarnings("unchecked")
limpbizkit916f5482008-04-16 20:51:14 +0000420 T converted = (T) matchingConverter.getTypeConverter()
421 .convert(stringValue, key.getTypeLiteral());
crazyboblee7c9d7792007-09-09 03:41:05 +0000422
423 if (converted == null) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000424 throw new ResolveFailedException(ErrorMessages.CONVERTER_RETURNED_NULL);
crazyboblee7c9d7792007-09-09 03:41:05 +0000425 }
426
427 // We have to filter out primitive types because an Integer is not an
428 // instance of int, and we provide converters for all the primitive types
429 // and know that they work anyway.
430 if (!type.rawType.isPrimitive()
431 && !type.getRawType().isInstance(converted)) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000432 throw new ResolveFailedException(ErrorMessages.CONVERSION_TYPE_ERROR, converted, type);
crazyboblee7c9d7792007-09-09 03:41:05 +0000433 }
434
crazyboblee712705c2007-09-07 03:20:30 +0000435 return new ConvertedConstantBindingImpl<T>(
crazyboblee7c9d7792007-09-09 03:41:05 +0000436 this, key, converted, stringBinding);
limpbizkit3b1cd582008-04-28 00:06:01 +0000437 } catch (ResolveFailedException e) {
438 throw e;
crazyboblee7c9d7792007-09-09 03:41:05 +0000439 } catch (Exception e) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000440 throw new ResolveFailedException(ErrorMessages.CONVERSION_ERROR, stringValue,
crazyboblee7c9d7792007-09-09 03:41:05 +0000441 stringBinding.getSource(), type, matchingConverter, e.getMessage());
crazyboblee712705c2007-09-07 03:20:30 +0000442 }
443 }
444
445 private static class ConvertedConstantBindingImpl<T> extends BindingImpl<T>
446 implements ConvertedConstantBinding<T> {
447
448 final T value;
449 final Provider<T> provider;
450 final Binding<String> originalBinding;
451
452 ConvertedConstantBindingImpl(InjectorImpl injector, Key<T> key, T value,
453 Binding<String> originalBinding) {
454 super(injector, key, SourceProviders.UNKNOWN_SOURCE,
455 new ConstantFactory<T>(value), Scopes.NO_SCOPE);
456 this.value = value;
457 this.provider = Providers.of(value);
458 this.originalBinding = originalBinding;
459 }
460
461 @Override
462 public Provider<T> getProvider() {
463 return this.provider;
464 }
465
466 public void accept(BindingVisitor<? super T> bindingVisitor) {
467 bindingVisitor.visit(this);
468 }
469
470 public T getValue() {
471 return this.value;
472 }
473
474 public Binding<String> getOriginal() {
475 return this.originalBinding;
476 }
477
478 @Override
479 public String toString() {
480 return new ToStringBuilder(ConvertedConstantBinding.class)
481 .add("key", key)
482 .add("value", value)
483 .add("original", originalBinding)
484 .toString();
485 }
486 }
487
limpbizkit3b1cd582008-04-28 00:06:01 +0000488 <T> BindingImpl<T> createBindingFromType(Class<T> type)
489 throws ResolveFailedException {
crazybobleed71c19e2007-09-08 01:55:10 +0000490 return createBindingFromType(type, null, SourceProviders.defaultSource());
491 }
492
493 <T> BindingImpl<T> createBindingFromType(Class<T> type, Scope scope,
limpbizkit3b1cd582008-04-28 00:06:01 +0000494 Object source) throws ResolveFailedException {
limpbizkit51411872008-05-13 22:15:29 +0000495 BindingImpl<T> binding = createUnitializedBinding(type, scope, source);
496 initializeBinding(binding);
497 return binding;
498 }
499
500 <T> void initializeBinding(BindingImpl<T> binding) throws ResolveFailedException {
501 // Put the partially constructed binding in the map a little early. This
502 // enables us to handle circular dependencies.
503 // Example: FooImpl -> BarImpl -> FooImpl.
504 // Note: We don't need to synchronize on jitBindings during injector
505 // creation.
506 if (binding instanceof ClassBindingImpl<?>) {
507 Key<T> key = binding.getKey();
508 jitBindings.put(key, binding);
509 boolean successful = false;
510 try {
511 binding.initialize(this);
512 successful = true;
513 } finally {
514 if (!successful) {
515 jitBindings.remove(key);
516 }
517 }
518 }
519 }
520
521 /**
522 * Creates a binding for an injectable type with the given scope. Looks for
523 * a scope on the type if none is specified.
524 */
525 <T> BindingImpl<T> createUnitializedBinding(Class<T> type,
526 Scope scope, Object source) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000527 // Don't try to inject primitives, arrays, or enums.
528 if (type.isArray() || type.isEnum() || type.isPrimitive()) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000529 throw new ResolveFailedException(ErrorMessages.MISSING_BINDING, type);
crazyboblee712705c2007-09-07 03:20:30 +0000530 }
531
532 // Handle @ImplementedBy
533 ImplementedBy implementedBy = type.getAnnotation(ImplementedBy.class);
534 if (implementedBy != null) {
crazybobleed71c19e2007-09-08 01:55:10 +0000535 // TODO: Scope internal factory.
crazyboblee712705c2007-09-07 03:20:30 +0000536 return createImplementedByBinding(type, implementedBy);
537 }
538
539 // Handle @ProvidedBy.
540 ProvidedBy providedBy = type.getAnnotation(ProvidedBy.class);
541 if (providedBy != null) {
crazybobleed71c19e2007-09-08 01:55:10 +0000542 // TODO: Scope internal factory.
crazyboblee712705c2007-09-07 03:20:30 +0000543 return createProvidedByBinding(type, providedBy);
544 }
545
crazyboblee712705c2007-09-07 03:20:30 +0000546 // We can't inject abstract classes.
547 // TODO: Method interceptors could actually enable us to implement
548 // abstract types. Should we remove this restriction?
549 if (Modifier.isAbstract(type.getModifiers())) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000550 throw new ResolveFailedException(ErrorMessages.CANNOT_INJECT_ABSTRACT_TYPE, type);
crazyboblee712705c2007-09-07 03:20:30 +0000551 }
552
553 // Error: Inner class.
554 if (Classes.isInnerClass(type)) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000555 throw new ResolveFailedException(ErrorMessages.CANNOT_INJECT_INNER_CLASS, type);
crazyboblee712705c2007-09-07 03:20:30 +0000556 }
557
558 if (scope == null) {
559 scope = Scopes.getScopeForType(type, scopes, errorHandler);
560 }
561
562 Key<T> key = Key.get(type);
563
564 LateBoundConstructor<T> lateBoundConstructor
565 = new LateBoundConstructor<T>();
566 InternalFactory<? extends T> scopedFactory
567 = Scopes.scope(key, this, lateBoundConstructor, scope);
568
limpbizkit51411872008-05-13 22:15:29 +0000569 return new ClassBindingImpl<T>(this, key, source, scopedFactory, scope, lateBoundConstructor);
crazyboblee712705c2007-09-07 03:20:30 +0000570 }
571
572 static class LateBoundConstructor<T> implements InternalFactory<T> {
573
574 ConstructorInjector<T> constructorInjector;
575
limpbizkit3b1cd582008-04-28 00:06:01 +0000576 void bind(InjectorImpl injector, Class<T> implementation)
577 throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000578 this.constructorInjector = injector.getConstructor(implementation);
579 }
580
581 @SuppressWarnings("unchecked")
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000582 public T get(InternalContext context, InjectionPoint<?> injectionPoint) {
limpbizkit00d513f2008-05-17 07:51:07 +0000583 if (constructorInjector == null) {
584 throw new IllegalStateException("Construct before bind, " + constructorInjector);
585 }
586
crazyboblee552472f2007-09-07 16:52:39 +0000587 // This may not actually be safe because it could return a super type
588 // of T (if that's all the client needs), but it should be OK in
589 // practice thanks to the wonders of erasure.
crazyboblee712705c2007-09-07 03:20:30 +0000590 return (T) constructorInjector.construct(
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000591 context, injectionPoint.getKey().getRawType());
crazyboblee712705c2007-09-07 03:20:30 +0000592 }
593 }
594
595 /**
limpbizkit3b1cd582008-04-28 00:06:01 +0000596 * Creates a binding for a type annotated with @ProvidedBy.
crazyboblee712705c2007-09-07 03:20:30 +0000597 */
598 <T> BindingImpl<T> createProvidedByBinding(final Class<T> type,
limpbizkit3b1cd582008-04-28 00:06:01 +0000599 ProvidedBy providedBy) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000600 final Class<? extends Provider<?>> providerType = providedBy.value();
601
602 // Make sure it's not the same type. TODO: Can we check for deeper loops?
603 if (providerType == type) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000604 throw new ResolveFailedException(ErrorMessages.RECURSIVE_PROVIDER_TYPE);
crazyboblee712705c2007-09-07 03:20:30 +0000605 }
606
607 // TODO: Make sure the provided type extends type. We at least check
608 // the type at runtime below.
609
610 // Assume the provider provides an appropriate type. We double check at
611 // runtime.
612 @SuppressWarnings("unchecked")
613 Key<? extends Provider<T>> providerKey
614 = (Key<? extends Provider<T>>) Key.get(providerType);
615 final BindingImpl<? extends Provider<?>> providerBinding
limpbizkit3b1cd582008-04-28 00:06:01 +0000616 = getBindingOrThrow(providerKey);
crazyboblee712705c2007-09-07 03:20:30 +0000617
618 InternalFactory<T> internalFactory = new InternalFactory<T>() {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000619 public T get(InternalContext context, InjectionPoint injectionPoint) {
620 Provider<?> provider
621 = providerBinding.internalFactory.get(context, injectionPoint);
crazyboblee712705c2007-09-07 03:20:30 +0000622 Object o = provider.get();
623 try {
624 return type.cast(o);
625 } catch (ClassCastException e) {
626 errorHandler.handle(StackTraceElements.forType(type),
627 ErrorMessages.SUBTYPE_NOT_PROVIDED, providerType, type);
628 throw new AssertionError();
629 }
630 }
631 };
632
633 return new LinkedProviderBindingImpl<T>(this, Key.get(type),
634 StackTraceElements.forType(type), internalFactory, Scopes.NO_SCOPE,
635 providerKey);
636 }
637
638 /**
639 * Creates a binding for a type annotated with @ImplementedBy.
640 */
641 <T> BindingImpl<T> createImplementedByBinding(Class<T> type,
limpbizkit3b1cd582008-04-28 00:06:01 +0000642 ImplementedBy implementedBy) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000643 // TODO: Use scope annotation on type if present. Right now, we always
644 // use NO_SCOPE.
645
646 Class<?> implementationType = implementedBy.value();
647
648 // Make sure it's not the same type. TODO: Can we check for deeper cycles?
649 if (implementationType == type) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000650 throw new ResolveFailedException(ErrorMessages.RECURSIVE_IMPLEMENTATION_TYPE);
crazyboblee712705c2007-09-07 03:20:30 +0000651 }
652
653 // Make sure implementationType extends type.
654 if (!type.isAssignableFrom(implementationType)) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000655 throw new ResolveFailedException(ErrorMessages.NOT_A_SUBTYPE, implementationType, type);
crazyboblee712705c2007-09-07 03:20:30 +0000656 }
657
658 // After the preceding check, this cast is safe.
659 @SuppressWarnings("unchecked")
660 Class<? extends T> subclass = (Class<? extends T>) implementationType;
661
662 // Look up the target binding.
663 final BindingImpl<? extends T> targetBinding
limpbizkit3b1cd582008-04-28 00:06:01 +0000664 = getBindingOrThrow(Key.get(subclass));
crazyboblee712705c2007-09-07 03:20:30 +0000665
666 InternalFactory<T> internalFactory = new InternalFactory<T>() {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000667 public T get(InternalContext context, InjectionPoint<?> injectionPoint) {
668 return targetBinding.internalFactory.get(context, injectionPoint);
crazyboblee712705c2007-09-07 03:20:30 +0000669 }
670 };
671
672 return new LinkedBindingImpl<T>(this, Key.get(type),
673 StackTraceElements.forType(type), internalFactory, Scopes.NO_SCOPE,
674 Key.get(subclass));
675 }
676
limpbizkit3b1cd582008-04-28 00:06:01 +0000677 <T> BindingImpl<T> createBindingJustInTime(Key<T> key) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000678 // Handle cases where T is a Provider<?>.
679 if (isProvider(key)) {
crazyboblee5d575692007-09-07 17:42:28 +0000680 // These casts are safe. We know T extends Provider<X> and that given
681 // Key<Provider<X>>, createProviderBinding() will return
682 // BindingImpl<Provider<X>>.
683 @SuppressWarnings({ "UnnecessaryLocalVariable", "unchecked" })
684 BindingImpl<T> binding
685 = (BindingImpl<T>) createProviderBinding((Key) key);
686 return binding;
crazyboblee712705c2007-09-07 03:20:30 +0000687 }
688
689 // Treat primitive types and their wrappers interchangeably.
690 BindingImpl<T> boxedOrUnboxed = getBoxedOrUnboxedBinding(key);
691 if (boxedOrUnboxed != null) {
692 return boxedOrUnboxed;
693 }
694
695 // Try to convert a constant string binding to the requested type.
696 BindingImpl<T> convertedBinding = convertConstantStringBinding(key);
697 if (convertedBinding != null) {
698 return convertedBinding;
699 }
700
701 // If the key has an annotation...
702 if (key.hasAnnotationType()) {
703 // Look for a binding without annotation attributes or return null.
limpbizkit3b1cd582008-04-28 00:06:01 +0000704 if (key.hasAttributes()) {
705 try {
706 return getBindingOrThrow(key.withoutAttributes());
707 } catch (ResolveFailedException ignored) {
708 // throw with a more appropriate message below
709 }
710 }
711 throw new ResolveFailedException(ErrorMessages.MISSING_BINDING, key);
crazyboblee712705c2007-09-07 03:20:30 +0000712 }
713
limpbizkit9b0be9f2008-03-28 06:12:41 +0000714 // Create a binding based on the raw type.
crazyboblee712705c2007-09-07 03:20:30 +0000715 @SuppressWarnings("unchecked")
limpbizkit9b0be9f2008-03-28 06:12:41 +0000716 Class<T> clazz = (Class<T>) key.getTypeLiteral().getRawType();
crazyboblee712705c2007-09-07 03:20:30 +0000717 return createBindingFromType(clazz);
718 }
719
limpbizkit3b1cd582008-04-28 00:06:01 +0000720 <T> InternalFactory<? extends T> getInternalFactory(Key<T> key)
721 throws ResolveFailedException {
722 return getBindingOrThrow(key).internalFactory;
crazyboblee712705c2007-09-07 03:20:30 +0000723 }
724
crazyboblee66b415a2006-08-25 02:01:19 +0000725 /**
726 * Field and method injectors.
727 */
kevinb9na2915a92007-02-28 06:20:30 +0000728 final Map<Class<?>, List<SingleMemberInjector>> injectors
729 = new ReferenceCache<Class<?>, List<SingleMemberInjector>>() {
730 protected List<SingleMemberInjector> create(Class<?> key) {
731 List<SingleMemberInjector> injectors
732 = new ArrayList<SingleMemberInjector>();
kevinb9na99dca72007-02-11 04:48:57 +0000733 addInjectors(key, injectors);
734 return injectors;
735 }
736 };
crazyboblee66b415a2006-08-25 02:01:19 +0000737
738 /**
739 * Recursively adds injectors for fields and methods from the given class to
740 * the given list. Injects parent classes before sub classes.
741 */
kevinb9na2915a92007-02-28 06:20:30 +0000742 void addInjectors(Class clazz, List<SingleMemberInjector> injectors) {
crazyboblee66b415a2006-08-25 02:01:19 +0000743 if (clazz == Object.class) {
744 return;
745 }
746
747 // Add injectors for superclass first.
748 addInjectors(clazz.getSuperclass(), injectors);
749
750 // TODO (crazybob): Filter out overridden members.
kevinb9na2915a92007-02-28 06:20:30 +0000751 addSingleInjectorsForFields(clazz.getDeclaredFields(), false, injectors);
752 addSingleInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors);
crazyboblee66b415a2006-08-25 02:01:19 +0000753 }
754
kevinb9na2915a92007-02-28 06:20:30 +0000755 void addSingleInjectorsForMethods(Method[] methods, boolean statics,
756 List<SingleMemberInjector> injectors) {
crazyboblee66b415a2006-08-25 02:01:19 +0000757 addInjectorsForMembers(Arrays.asList(methods), statics, injectors,
kevinb9na2915a92007-02-28 06:20:30 +0000758 new SingleInjectorFactory<Method>() {
759 public SingleMemberInjector create(InjectorImpl injector,
limpbizkit3b1cd582008-04-28 00:06:01 +0000760 Method method) throws ResolveFailedException {
kevinb9na2915a92007-02-28 06:20:30 +0000761 return new SingleMethodInjector(injector, method);
crazyboblee66b415a2006-08-25 02:01:19 +0000762 }
763 });
764 }
765
kevinb9na2915a92007-02-28 06:20:30 +0000766 void addSingleInjectorsForFields(Field[] fields, boolean statics,
767 List<SingleMemberInjector> injectors) {
crazyboblee66b415a2006-08-25 02:01:19 +0000768 addInjectorsForMembers(Arrays.asList(fields), statics, injectors,
kevinb9na2915a92007-02-28 06:20:30 +0000769 new SingleInjectorFactory<Field>() {
770 public SingleMemberInjector create(InjectorImpl injector,
limpbizkit3b1cd582008-04-28 00:06:01 +0000771 Field field) throws ResolveFailedException {
kevinb9na2915a92007-02-28 06:20:30 +0000772 return new SingleFieldInjector(injector, field);
crazyboblee66b415a2006-08-25 02:01:19 +0000773 }
774 });
775 }
776
777 <M extends Member & AnnotatedElement> void addInjectorsForMembers(
kevinb9na2915a92007-02-28 06:20:30 +0000778 List<M> members, boolean statics, List<SingleMemberInjector> injectors,
779 SingleInjectorFactory<M> injectorFactory) {
crazyboblee66b415a2006-08-25 02:01:19 +0000780 for (M member : members) {
781 if (isStatic(member) == statics) {
crazyboblee9a3861b2007-02-20 03:37:31 +0000782 Inject inject = member.getAnnotation(Inject.class);
crazyboblee66b415a2006-08-25 02:01:19 +0000783 if (inject != null) {
784 try {
crazyboblee4602a6f2007-02-15 02:45:18 +0000785 injectors.add(injectorFactory.create(this, member));
kevinb9na99dca72007-02-11 04:48:57 +0000786 }
limpbizkit3b1cd582008-04-28 00:06:01 +0000787 catch (ResolveFailedException e) {
crazyboblee4602a6f2007-02-15 02:45:18 +0000788 if (!inject.optional()) {
crazyboblee4727ee22007-01-30 03:13:38 +0000789 // TODO: Report errors for more than one parameter per member.
limpbizkit3b1cd582008-04-28 00:06:01 +0000790 errorHandler.handle(member, e.getMessage());
crazyboblee66b415a2006-08-25 02:01:19 +0000791 }
792 }
793 }
794 }
795 }
796 }
797
crazyboblee1fc49782007-02-25 21:02:47 +0000798 Map<Key<?>, BindingImpl<?>> internalBindings() {
crazyboblee712705c2007-09-07 03:20:30 +0000799 return explicitBindings;
crazybobleea6e73982007-02-02 00:21:07 +0000800 }
801
kevinb9n225310e2007-02-20 04:12:01 +0000802 // not test-covered
crazybobleea6e73982007-02-02 00:21:07 +0000803 public Map<Key<?>, Binding<?>> getBindings() {
crazyboblee712705c2007-09-07 03:20:30 +0000804 return Collections.<Key<?>, Binding<?>>unmodifiableMap(explicitBindings);
crazybobleea6e73982007-02-02 00:21:07 +0000805 }
806
kevinb9na2915a92007-02-28 06:20:30 +0000807 interface SingleInjectorFactory<M extends Member & AnnotatedElement> {
808 SingleMemberInjector create(InjectorImpl injector, M member)
limpbizkit3b1cd582008-04-28 00:06:01 +0000809 throws ResolveFailedException;
crazyboblee66b415a2006-08-25 02:01:19 +0000810 }
811
812 private boolean isStatic(Member member) {
813 return Modifier.isStatic(member.getModifiers());
814 }
815
kevinb9n48d13072007-02-12 18:21:26 +0000816 private static class BindingsMultimap {
crazyboblee1fc49782007-02-25 21:02:47 +0000817 private final Map<TypeLiteral<?>, List<? extends BindingImpl<?>>> map
818 = new HashMap<TypeLiteral<?>, List<? extends BindingImpl<?>>>();
kevinb9n48d13072007-02-12 18:21:26 +0000819
crazyboblee1fc49782007-02-25 21:02:47 +0000820 public <T> void put(TypeLiteral<T> type, BindingImpl<T> binding) {
821 List<BindingImpl<T>> bindingsForThisType = getFromMap(type);
kevinb9n48d13072007-02-12 18:21:26 +0000822 if (bindingsForThisType == null) {
crazyboblee1fc49782007-02-25 21:02:47 +0000823 bindingsForThisType = new ArrayList<BindingImpl<T>>();
kevinb9n48d13072007-02-12 18:21:26 +0000824 // We only put matching entries into the map
825 map.put(type, bindingsForThisType);
826 }
827 bindingsForThisType.add(binding);
828 }
829
crazyboblee1fc49782007-02-25 21:02:47 +0000830 public <T> List<BindingImpl<T>> getAll(TypeLiteral<T> type) {
831 List<BindingImpl<T>> list = getFromMap(type);
832 return list == null ? Collections.<BindingImpl<T>>emptyList() : list;
kevinb9n48d13072007-02-12 18:21:26 +0000833 }
834
835 // safe because we only put matching entries into the map
836 @SuppressWarnings("unchecked")
crazyboblee1fc49782007-02-25 21:02:47 +0000837 private <T> List<BindingImpl<T>> getFromMap(TypeLiteral<T> type) {
838 return (List<BindingImpl<T>>) map.get(type);
kevinb9n48d13072007-02-12 18:21:26 +0000839 }
840 }
841
kevinb9na2915a92007-02-28 06:20:30 +0000842 class SingleFieldInjector implements SingleMemberInjector {
crazyboblee66b415a2006-08-25 02:01:19 +0000843
844 final Field field;
845 final InternalFactory<?> factory;
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000846 final InjectionPoint<?> injectionPoint;
crazyboblee66b415a2006-08-25 02:01:19 +0000847
crazyboblee712705c2007-09-07 03:20:30 +0000848 public SingleFieldInjector(final InjectorImpl injector, Field field)
limpbizkit3b1cd582008-04-28 00:06:01 +0000849 throws ResolveFailedException {
crazyboblee66b415a2006-08-25 02:01:19 +0000850 this.field = field;
crazyboblee4727ee22007-01-30 03:13:38 +0000851
852 // Ewwwww...
crazyboblee66b415a2006-08-25 02:01:19 +0000853 field.setAccessible(true);
854
limpbizkit916f5482008-04-16 20:51:14 +0000855 final Key<?> key = Keys.get(
crazyboblee4602a6f2007-02-15 02:45:18 +0000856 field.getGenericType(), field, field.getAnnotations(), errorHandler);
limpbizkit3b1cd582008-04-28 00:06:01 +0000857 factory = new ResolvingCallable<InternalFactory<?>>() {
858 public InternalFactory<?> call() throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000859 return injector.getInternalFactory(key);
860 }
limpbizkit3b1cd582008-04-28 00:06:01 +0000861 }.runWithDefaultSource(StackTraceElements.forMember(field));
crazyboblee66b415a2006-08-25 02:01:19 +0000862
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000863 this.injectionPoint = InjectionPoint.newInstance(field,
limpbizkitc808df02007-08-25 03:25:13 +0000864 Nullability.forAnnotations(field.getAnnotations()), key, injector);
crazyboblee66b415a2006-08-25 02:01:19 +0000865 }
866
crazybobleed71c19e2007-09-08 01:55:10 +0000867 public Collection<Dependency<?>> getDependencies() {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000868 return Collections.<Dependency<?>>singleton(injectionPoint);
crazybobleed71c19e2007-09-08 01:55:10 +0000869 }
870
crazyboblee66b415a2006-08-25 02:01:19 +0000871 public void inject(InternalContext context, Object o) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000872 context.setInjectionPoint(injectionPoint);
crazyboblee66b415a2006-08-25 02:01:19 +0000873 try {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000874 Object value = factory.get(context, injectionPoint);
crazyboblee4602a6f2007-02-15 02:45:18 +0000875 field.set(o, value);
kevinb9na99dca72007-02-11 04:48:57 +0000876 }
877 catch (IllegalAccessException e) {
crazyboblee66b415a2006-08-25 02:01:19 +0000878 throw new AssertionError(e);
kevinb9na99dca72007-02-11 04:48:57 +0000879 }
kevinb9n9119a632007-02-22 01:28:24 +0000880 catch (ConfigurationException e) {
881 throw e;
882 }
limpbizkit1dabcfd2007-08-25 08:06:30 +0000883 catch (ProvisionException provisionException) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000884 provisionException.addContext(injectionPoint);
limpbizkit1dabcfd2007-08-25 08:06:30 +0000885 throw provisionException;
886 }
887 catch (RuntimeException runtimeException) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000888 throw new ProvisionException(runtimeException,
889 ErrorMessages.ERROR_INJECTING_FIELD);
kevinb9n9119a632007-02-22 01:28:24 +0000890 }
kevinb9na99dca72007-02-11 04:48:57 +0000891 finally {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000892 context.setInjectionPoint(null);
crazyboblee66b415a2006-08-25 02:01:19 +0000893 }
894 }
895 }
896
897 /**
898 * Gets parameter injectors.
899 *
900 * @param member to which the parameters belong
crazyboblee66b415a2006-08-25 02:01:19 +0000901 * @return injections
902 */
kevinb9nf73ca5d2007-03-13 02:39:45 +0000903 SingleParameterInjector<?>[] getParametersInjectors(Member member,
limpbizkit916f5482008-04-16 20:51:14 +0000904 List<Parameter<?>> parameters)
limpbizkit3b1cd582008-04-28 00:06:01 +0000905 throws ResolveFailedException {
kevinb9na2915a92007-02-28 06:20:30 +0000906 SingleParameterInjector<?>[] parameterInjectors
limpbizkit916f5482008-04-16 20:51:14 +0000907 = new SingleParameterInjector<?>[parameters.size()];
crazyboblee15969212007-02-01 02:01:59 +0000908 int index = 0;
limpbizkit916f5482008-04-16 20:51:14 +0000909 for (Parameter<?> parameter : parameters) {
910 parameterInjectors[index] = createParameterInjector(parameter, member);
kevinb9na99dca72007-02-11 04:48:57 +0000911 index++;
crazyboblee66b415a2006-08-25 02:01:19 +0000912 }
kevinb9na99dca72007-02-11 04:48:57 +0000913 return parameterInjectors;
crazyboblee66b415a2006-08-25 02:01:19 +0000914 }
915
kevinb9na2915a92007-02-28 06:20:30 +0000916 <T> SingleParameterInjector<T> createParameterInjector(
limpbizkit916f5482008-04-16 20:51:14 +0000917 final Parameter<T> parameter, Member member)
limpbizkit3b1cd582008-04-28 00:06:01 +0000918 throws ResolveFailedException {
919 InternalFactory<? extends T> factory
920 = new ResolvingCallable<InternalFactory<? extends T>>() {
921 public InternalFactory<? extends T> call() throws ResolveFailedException {
922 return getInternalFactory(parameter.getKey());
923 }
924 }.runWithDefaultSource(StackTraceElements.forMember(member));
crazyboblee66b415a2006-08-25 02:01:19 +0000925
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000926 InjectionPoint<T> injectionPoint = InjectionPoint.newInstance(
limpbizkit916f5482008-04-16 20:51:14 +0000927 member, parameter.getIndex(), parameter.getNullability(), parameter.getKey(), this);
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000928 return new SingleParameterInjector<T>(injectionPoint, factory);
crazyboblee66b415a2006-08-25 02:01:19 +0000929 }
930
kevinb9na2915a92007-02-28 06:20:30 +0000931 static class SingleMethodInjector implements SingleMemberInjector {
crazyboblee66b415a2006-08-25 02:01:19 +0000932
crazyboblee0b3189c2007-02-24 00:14:51 +0000933 final MethodInvoker methodInvoker;
kevinb9na2915a92007-02-28 06:20:30 +0000934 final SingleParameterInjector<?>[] parameterInjectors;
crazyboblee66b415a2006-08-25 02:01:19 +0000935
kevinb9na2915a92007-02-28 06:20:30 +0000936 public SingleMethodInjector(InjectorImpl injector, final Method method)
limpbizkit3b1cd582008-04-28 00:06:01 +0000937 throws ResolveFailedException {
crazyboblee0b3189c2007-02-24 00:14:51 +0000938 // We can't use FastMethod if the method is private.
crazyboblee77bf3b22007-02-25 21:37:02 +0000939 if (Modifier.isPrivate(method.getModifiers())
940 || Modifier.isProtected(method.getModifiers())) {
crazyboblee0b3189c2007-02-24 00:14:51 +0000941 method.setAccessible(true);
942 this.methodInvoker = new MethodInvoker() {
943 public Object invoke(Object target, Object... parameters) throws
944 IllegalAccessException, InvocationTargetException {
945 return method.invoke(target, parameters);
946 }
947 };
948 }
949 else {
950 FastClass fastClass = GuiceFastClass.create(method.getDeclaringClass());
951 final FastMethod fastMethod = fastClass.getMethod(method);
952
953 this.methodInvoker = new MethodInvoker() {
954 public Object invoke(Object target, Object... parameters)
955 throws IllegalAccessException, InvocationTargetException {
956 return fastMethod.invoke(target, parameters);
957 }
958 };
959 }
960
crazyboblee7c5b2c42007-01-20 02:05:20 +0000961 Type[] parameterTypes = method.getGenericParameterTypes();
crazyboblee4727ee22007-01-30 03:13:38 +0000962 parameterInjectors = parameterTypes.length > 0
limpbizkit916f5482008-04-16 20:51:14 +0000963 ? injector.getParametersInjectors(method,
964 Parameter.forMethod(injector.errorHandler, method))
crazyboblee4727ee22007-01-30 03:13:38 +0000965 : null;
crazyboblee66b415a2006-08-25 02:01:19 +0000966 }
967
968 public void inject(InternalContext context, Object o) {
969 try {
crazyboblee0b3189c2007-02-24 00:14:51 +0000970 methodInvoker.invoke(o, getParameters(context, parameterInjectors));
kevinb9na99dca72007-02-11 04:48:57 +0000971 }
limpbizkit1dabcfd2007-08-25 08:06:30 +0000972 catch (IllegalAccessException e) {
973 throw new AssertionError(e);
974 }
limpbizkitc808df02007-08-25 03:25:13 +0000975 catch (ProvisionException e) {
976 throw e;
977 }
limpbizkitc808df02007-08-25 03:25:13 +0000978 catch (InvocationTargetException e) {
limpbizkit1dabcfd2007-08-25 08:06:30 +0000979 Throwable cause = e.getCause() != null ? e.getCause() : e;
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000980 throw new ProvisionException(cause,
981 ErrorMessages.ERROR_INJECTING_METHOD);
crazyboblee66b415a2006-08-25 02:01:19 +0000982 }
983 }
crazybobleed71c19e2007-09-08 01:55:10 +0000984
985 public Collection<Dependency<?>> getDependencies() {
986 List<Dependency<?>> dependencies = new ArrayList<Dependency<?>>();
987 for (SingleParameterInjector<?> parameterInjector : parameterInjectors) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000988 dependencies.add(parameterInjector.injectionPoint);
crazybobleed71c19e2007-09-08 01:55:10 +0000989 }
990 return Collections.unmodifiableList(dependencies);
991 }
crazyboblee66b415a2006-08-25 02:01:19 +0000992 }
993
crazyboblee0b3189c2007-02-24 00:14:51 +0000994 /**
995 * Invokes a method.
996 */
997 interface MethodInvoker {
998 Object invoke(Object target, Object... parameters) throws
999 IllegalAccessException, InvocationTargetException;
1000 }
1001
limpbizkit3b1cd582008-04-28 00:06:01 +00001002 final Map<Class<?>, Object> constructors
1003 = new ReferenceCache<Class<?>, Object>() {
kevinb9na99dca72007-02-11 04:48:57 +00001004 @SuppressWarnings("unchecked")
limpbizkit3b1cd582008-04-28 00:06:01 +00001005 protected Object create(Class<?> implementation) {
crazybobleed0c4b8b2007-09-06 02:47:04 +00001006 if (!Classes.isConcrete(implementation)) {
limpbizkit3b1cd582008-04-28 00:06:01 +00001007 return new ResolveFailedException(
crazyboblee6c7720d2007-03-01 21:49:19 +00001008 ErrorMessages.CANNOT_INJECT_ABSTRACT_TYPE, implementation);
kevinb9na99dca72007-02-11 04:48:57 +00001009 }
crazybobleed0c4b8b2007-09-06 02:47:04 +00001010 if (Classes.isInnerClass(implementation)) {
limpbizkit3b1cd582008-04-28 00:06:01 +00001011 return new ResolveFailedException(ErrorMessages.CANNOT_INJECT_INNER_CLASS, implementation);
kevinb9n9da90b32007-04-20 15:28:04 +00001012 }
crazyboblee235d0682007-01-31 02:25:21 +00001013
kevinb9na2915a92007-02-28 06:20:30 +00001014 return new ConstructorInjector(InjectorImpl.this, implementation);
kevinb9na99dca72007-02-11 04:48:57 +00001015 }
1016 };
crazyboblee66b415a2006-08-25 02:01:19 +00001017
kevinb9na2915a92007-02-28 06:20:30 +00001018 static class SingleParameterInjector<T> {
crazyboblee66b415a2006-08-25 02:01:19 +00001019
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001020 final InjectionPoint<T> injectionPoint;
crazyboblee66b415a2006-08-25 02:01:19 +00001021 final InternalFactory<? extends T> factory;
1022
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001023 public SingleParameterInjector(InjectionPoint<T> injectionPoint,
crazyboblee66b415a2006-08-25 02:01:19 +00001024 InternalFactory<? extends T> factory) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001025 this.injectionPoint = injectionPoint;
crazyboblee66b415a2006-08-25 02:01:19 +00001026 this.factory = factory;
1027 }
1028
crazyboblee664a82e2007-01-25 23:09:51 +00001029 T inject(InternalContext context) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001030 context.setInjectionPoint(injectionPoint);
crazyboblee66b415a2006-08-25 02:01:19 +00001031 try {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001032 return factory.get(context, injectionPoint);
kevinb9na99dca72007-02-11 04:48:57 +00001033 }
kevinb9n9119a632007-02-22 01:28:24 +00001034 catch (ConfigurationException e) {
1035 throw e;
1036 }
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001037 catch (ProvisionException provisionException) {
1038 provisionException.addContext(injectionPoint);
1039 throw provisionException;
limpbizkit1dabcfd2007-08-25 08:06:30 +00001040 }
1041 catch (RuntimeException runtimeException) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001042 throw new ProvisionException(runtimeException,
1043 ErrorMessages.ERROR_INJECTING_METHOD);
kevinb9n9119a632007-02-22 01:28:24 +00001044 }
kevinb9na99dca72007-02-11 04:48:57 +00001045 finally {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001046 context.setInjectionPoint(injectionPoint);
crazyboblee66b415a2006-08-25 02:01:19 +00001047 }
1048 }
1049 }
1050
crazybobleee3adfd62007-02-02 21:30:08 +00001051 /**
1052 * Iterates over parameter injectors and creates an array of parameter
1053 * values.
1054 */
1055 static Object[] getParameters(InternalContext context,
kevinb9na2915a92007-02-28 06:20:30 +00001056 SingleParameterInjector[] parameterInjectors) {
crazyboblee66b415a2006-08-25 02:01:19 +00001057 if (parameterInjectors == null) {
1058 return null;
1059 }
1060
1061 Object[] parameters = new Object[parameterInjectors.length];
1062 for (int i = 0; i < parameters.length; i++) {
crazyboblee664a82e2007-01-25 23:09:51 +00001063 parameters[i] = parameterInjectors[i].inject(context);
crazyboblee66b415a2006-08-25 02:01:19 +00001064 }
1065 return parameters;
1066 }
1067
crazyboblee63b592b2007-01-25 02:45:24 +00001068 void injectMembers(Object o, InternalContext context) {
limpbizkitc808df02007-08-25 03:25:13 +00001069 if (o == null) {
1070 return;
1071 }
1072
kevinb9na2915a92007-02-28 06:20:30 +00001073 List<SingleMemberInjector> injectorsForClass = injectors.get(o.getClass());
1074 for (SingleMemberInjector injector : injectorsForClass) {
crazyboblee66b415a2006-08-25 02:01:19 +00001075 injector.inject(context, o);
1076 }
1077 }
1078
kevinb9n225310e2007-02-20 04:12:01 +00001079 // Not test-covered
crazyboblee63b592b2007-01-25 02:45:24 +00001080 public void injectMembers(final Object o) {
crazyboblee66b415a2006-08-25 02:01:19 +00001081 callInContext(new ContextualCallable<Void>() {
1082 public Void call(InternalContext context) {
crazyboblee63b592b2007-01-25 02:45:24 +00001083 injectMembers(o, context);
crazyboblee66b415a2006-08-25 02:01:19 +00001084 return null;
1085 }
1086 });
1087 }
1088
crazybobleebd9544e2007-02-25 20:32:11 +00001089 public <T> Provider<T> getProvider(Class<T> type) {
1090 return getProvider(Key.get(type));
crazybobleee5fbbb02007-02-05 07:00:27 +00001091 }
1092
limpbizkit3b1cd582008-04-28 00:06:01 +00001093 <T> Provider<T> getProviderOrThrow(final Key<T> key) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +00001094 final InternalFactory<? extends T> factory = getInternalFactory(key);
crazyboblee66b415a2006-08-25 02:01:19 +00001095
crazybobleebd9544e2007-02-25 20:32:11 +00001096 return new Provider<T>() {
crazyboblee63b592b2007-01-25 02:45:24 +00001097 public T get() {
1098 return callInContext(new ContextualCallable<T>() {
1099 public T call(InternalContext context) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001100 InjectionPoint<T> injectionPoint
1101 = InjectionPoint.newInstance(key, InjectorImpl.this);
1102 context.setInjectionPoint(injectionPoint);
crazyboblee63b592b2007-01-25 02:45:24 +00001103 try {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001104 return factory.get(context, injectionPoint);
1105 }
1106 catch(ProvisionException provisionException) {
1107 provisionException.addContext(injectionPoint);
1108 throw provisionException;
kevinb9na99dca72007-02-11 04:48:57 +00001109 }
1110 finally {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001111 context.setInjectionPoint(null);
crazyboblee63b592b2007-01-25 02:45:24 +00001112 }
1113 }
1114 });
crazyboblee66b415a2006-08-25 02:01:19 +00001115 }
crazybobleed7908e82007-02-16 01:04:53 +00001116
1117 public String toString() {
1118 return factory.toString();
1119 }
crazyboblee63b592b2007-01-25 02:45:24 +00001120 };
crazyboblee66b415a2006-08-25 02:01:19 +00001121 }
1122
crazyboblee712705c2007-09-07 03:20:30 +00001123 public <T> Provider<T> getProvider(final Key<T> key) {
limpbizkit3b1cd582008-04-28 00:06:01 +00001124 try {
1125 return getProviderOrThrow(key);
1126 } catch (ResolveFailedException e) {
crazyboblee712705c2007-09-07 03:20:30 +00001127 throw new ConfigurationException(
limpbizkit3b1cd582008-04-28 00:06:01 +00001128 "Missing binding to " + ErrorMessages.convert(key) + ": " + e.getMessage());
crazyboblee712705c2007-09-07 03:20:30 +00001129 }
crazyboblee712705c2007-09-07 03:20:30 +00001130 }
1131
kevinb9n27f8a582007-02-28 22:54:06 +00001132 public <T> T getInstance(Key<T> key) {
1133 return getProvider(key).get();
1134 }
1135
1136 public <T> T getInstance(Class<T> type) {
1137 return getProvider(type).get();
1138 }
1139
kevinb9na99dca72007-02-11 04:48:57 +00001140 final ThreadLocal<InternalContext[]> localContext
1141 = new ThreadLocal<InternalContext[]>() {
1142 protected InternalContext[] initialValue() {
1143 return new InternalContext[1];
1144 }
1145 };
crazyboblee66b415a2006-08-25 02:01:19 +00001146
1147 /**
1148 * Looks up thread local context. Creates (and removes) a new context if
1149 * necessary.
1150 */
1151 <T> T callInContext(ContextualCallable<T> callable) {
1152 InternalContext[] reference = localContext.get();
1153 if (reference[0] == null) {
crazyboblee63b592b2007-01-25 02:45:24 +00001154 reference[0] = new InternalContext(this);
crazyboblee66b415a2006-08-25 02:01:19 +00001155 try {
1156 return callable.call(reference[0]);
kevinb9na99dca72007-02-11 04:48:57 +00001157 }
1158 finally {
crazyboblee66b415a2006-08-25 02:01:19 +00001159 // Only remove the context if this call created it.
1160 reference[0] = null;
1161 }
kevinb9na99dca72007-02-11 04:48:57 +00001162 }
1163 else {
crazyboblee66b415a2006-08-25 02:01:19 +00001164 // Someone else will clean up this context.
1165 return callable.call(reference[0]);
1166 }
1167 }
1168
crazyboblee66b415a2006-08-25 02:01:19 +00001169 /**
1170 * Gets a constructor function for a given implementation class.
1171 */
1172 @SuppressWarnings("unchecked")
limpbizkit3b1cd582008-04-28 00:06:01 +00001173 <T> ConstructorInjector<T> getConstructor(Class<T> implementation)
1174 throws ResolveFailedException {
1175 Object o = constructors.get(implementation);
1176 if (o instanceof ResolveFailedException) {
1177 throw (ResolveFailedException) o;
1178 } else if (o instanceof ConstructorInjector<?>) {
1179 return (ConstructorInjector<T>) o;
1180 } else {
1181 throw new AssertionError();
1182 }
crazyboblee66b415a2006-08-25 02:01:19 +00001183 }
1184
crazyboblee66b415a2006-08-25 02:01:19 +00001185 /**
1186 * Injects a field or method in a given object.
1187 */
limpbizkit8b237452008-04-22 06:47:36 +00001188 public interface SingleMemberInjector {
crazyboblee66b415a2006-08-25 02:01:19 +00001189 void inject(InternalContext context, Object o);
crazybobleed71c19e2007-09-08 01:55:10 +00001190 Collection<Dependency<?>> getDependencies();
1191 }
1192
1193 List<Dependency<?>> getModifiableFieldAndMethodDependenciesFor(
1194 Class<?> clazz) {
1195 List<SingleMemberInjector> injectors = this.injectors.get(clazz);
1196 List<Dependency<?>> dependencies = new ArrayList<Dependency<?>>();
1197 for (SingleMemberInjector singleMemberInjector : injectors) {
1198 dependencies.addAll(singleMemberInjector.getDependencies());
1199 }
1200 return dependencies;
1201 }
1202
1203 Collection<Dependency<?>> getFieldAndMethodDependenciesFor(Class<?> clazz) {
1204 return Collections.unmodifiableList(
1205 getModifiableFieldAndMethodDependenciesFor(clazz));
crazyboblee66b415a2006-08-25 02:01:19 +00001206 }
1207
crazybobleee3adfd62007-02-02 21:30:08 +00001208 public String toString() {
kevinb9na2915a92007-02-28 06:20:30 +00001209 return new ToStringBuilder(Injector.class)
crazyboblee712705c2007-09-07 03:20:30 +00001210 .add("bindings", explicitBindings)
crazybobleee3adfd62007-02-02 21:30:08 +00001211 .toString();
1212 }
crazyboblee66b415a2006-08-25 02:01:19 +00001213}