blob: 1a68cc7b89bc4b58d34d7c2200133f70a4df1ace [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
kevinb9n1601ae52008-06-03 22:21:04 +000019import static com.google.common.base.Preconditions.checkState;
20import com.google.common.base.ReferenceType;
21import com.google.common.collect.Lists;
22import com.google.common.collect.Maps;
23import com.google.common.collect.Multimap;
24import com.google.common.collect.Multimaps;
25import com.google.common.collect.Sets;
26import com.google.inject.internal.Classes;
27import com.google.inject.internal.ErrorHandler;
limpbizkitdf98fcd2008-06-14 05:02:15 +000028import com.google.inject.internal.ErrorMessage;
kevinb9n1601ae52008-06-03 22:21:04 +000029import com.google.inject.internal.GuiceFastClass;
30import com.google.inject.internal.Keys;
31import com.google.inject.internal.MatcherAndConverter;
32import com.google.inject.internal.ReferenceCache;
33import com.google.inject.internal.ResolveFailedException;
34import com.google.inject.internal.ResolvingCallable;
35import com.google.inject.internal.StackTraceElements;
36import com.google.inject.internal.ToStringBuilder;
37import com.google.inject.spi.BindingVisitor;
38import com.google.inject.spi.ConvertedConstantBinding;
39import com.google.inject.spi.Dependency;
limpbizkitdf98fcd2008-06-14 05:02:15 +000040import com.google.inject.spi.Message;
kevinb9n1601ae52008-06-03 22:21:04 +000041import com.google.inject.spi.ProviderBinding;
42import com.google.inject.spi.SourceProviders;
crazyboblee712705c2007-09-07 03:20:30 +000043import com.google.inject.util.Providers;
kevinb9n1601ae52008-06-03 22:21:04 +000044import java.lang.annotation.Annotation;
45import java.lang.reflect.AnnotatedElement;
46import java.lang.reflect.Field;
47import java.lang.reflect.InvocationTargetException;
48import java.lang.reflect.Member;
49import java.lang.reflect.Method;
50import java.lang.reflect.Modifier;
51import java.lang.reflect.ParameterizedType;
52import java.lang.reflect.Type;
53import java.util.ArrayList;
54import java.util.Arrays;
55import java.util.Collection;
56import java.util.Collections;
57import java.util.List;
58import java.util.Map;
59import java.util.Set;
kevinb9n225310e2007-02-20 04:12:01 +000060import net.sf.cglib.reflect.FastClass;
61import net.sf.cglib.reflect.FastMethod;
crazyboblee66b415a2006-08-25 02:01:19 +000062
63/**
kevinb9na2915a92007-02-28 06:20:30 +000064 * Default {@link Injector} implementation.
crazyboblee66b415a2006-08-25 02:01:19 +000065 *
crazyboblee66b415a2006-08-25 02:01:19 +000066 * @author crazybob@google.com (Bob Lee)
limpbizkit3d58d6b2008-03-08 16:11:47 +000067 * @see InjectorBuilder
crazyboblee66b415a2006-08-25 02:01:19 +000068 */
kevinb9na2915a92007-02-28 06:20:30 +000069class InjectorImpl implements Injector {
dan.halem5d187432008-02-22 22:52:28 +000070 final Injector parentInjector;
kevinb9n1601ae52008-06-03 22:21:04 +000071 final Map<Key<?>, BindingImpl<?>> explicitBindings = Maps.newHashMap();
limpbizkit3d58d6b2008-03-08 16:11:47 +000072 final BindingsMultimap bindingsMultimap = new BindingsMultimap();
kevinb9n1601ae52008-06-03 22:21:04 +000073 final Map<Class<? extends Annotation>, Scope> scopes = Maps.newHashMap();
74 final List<MatcherAndConverter<?>> converters = Lists.newArrayList();
75 final Map<Key<?>, BindingImpl<?>> parentBindings = Maps.newHashMap();
76 final Set<Object> outstandingInjections = Sets.newIdentityHashSet(ReferenceType.STRONG);
limpbizkitb1d8ab42008-04-27 08:11:37 +000077 final ErrorHandler errorHandler;
limpbizkit916f5482008-04-16 20:51:14 +000078 Reflection reflection;
crazyboblee4727ee22007-01-30 03:13:38 +000079
limpbizkitb1d8ab42008-04-27 08:11:37 +000080 InjectorImpl(Injector parentInjector, ErrorHandler errorHandler) {
dan.halem5d187432008-02-22 22:52:28 +000081 this.parentInjector = parentInjector;
limpbizkitb1d8ab42008-04-27 08:11:37 +000082 this.errorHandler = errorHandler;
crazyboblee66b415a2006-08-25 02:01:19 +000083 }
84
limpbizkit51515b52008-03-11 03:46:25 +000085 void validateOustandingInjections() {
kevinb9n1601ae52008-06-03 22:21:04 +000086 for (Object toInject : outstandingInjections) {
limpbizkit51515b52008-03-11 03:46:25 +000087 injectors.get(toInject.getClass());
88 }
89 }
90
91 /**
kevinb9n1601ae52008-06-03 22:21:04 +000092 * Performs creation-time injections on all objects that require it. Whenever fulfilling an
93 * injection depends on another object that requires injection, we use {@link
94 * InternalContext#ensureMemberInjected} to inject that member first.
limpbizkit51515b52008-03-11 03:46:25 +000095 *
kevinb9n1601ae52008-06-03 22:21:04 +000096 * <p>If the two objects are codependent (directly or transitively), ordering of injection is
97 * arbitrary.
limpbizkit51515b52008-03-11 03:46:25 +000098 */
99 void fulfillOutstandingInjections() {
100 callInContext(new ContextualCallable<Void>() {
101 public Void call(InternalContext context) {
kevinb9n1601ae52008-06-03 22:21:04 +0000102 // loop over a defensive copy, since ensureMemberInjected() mutates the set
103 for (Object toInject : Lists.newArrayList(outstandingInjections)) {
limpbizkit51515b52008-03-11 03:46:25 +0000104 context.ensureMemberInjected(toInject);
105 }
106 return null;
107 }
108 });
109
110 if (!outstandingInjections.isEmpty()) {
kevinb9n1601ae52008-06-03 22:21:04 +0000111 throw new AssertionError("failed to satisfy " + outstandingInjections);
limpbizkit51515b52008-03-11 03:46:25 +0000112 }
113 }
114
kevinb9n1601ae52008-06-03 22:21:04 +0000115 /** Indexes bindings by type. */
crazyboblee62fcdde2007-02-03 02:10:13 +0000116 void index() {
crazyboblee712705c2007-09-07 03:20:30 +0000117 for (BindingImpl<?> binding : explicitBindings.values()) {
crazyboblee62fcdde2007-02-03 02:10:13 +0000118 index(binding);
119 }
120 }
121
crazyboblee1fc49782007-02-25 21:02:47 +0000122 <T> void index(BindingImpl<T> binding) {
crazybobleec3e88492007-02-25 22:36:58 +0000123 bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
crazyboblee62fcdde2007-02-03 02:10:13 +0000124 }
125
kevinb9n225310e2007-02-20 04:12:01 +0000126 // not test-covered
crazyboblee62fcdde2007-02-03 02:10:13 +0000127 public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
kevinb9n1601ae52008-06-03 22:21:04 +0000128 return Collections.<Binding<T>>unmodifiableList(bindingsMultimap.getAll(type));
crazyboblee62fcdde2007-02-03 02:10:13 +0000129 }
130
kevinb9n225310e2007-02-20 04:12:01 +0000131 // not test-covered
crazyboblee4602a6f2007-02-15 02:45:18 +0000132 <T> List<String> getNamesOfBindingAnnotations(TypeLiteral<T> type) {
kevinb9n1601ae52008-06-03 22:21:04 +0000133 List<String> names = Lists.newArrayList();
crazyboblee62fcdde2007-02-03 02:10:13 +0000134 for (Binding<T> binding : findBindingsByType(type)) {
crazybobleeb1f2e682007-02-15 05:14:32 +0000135 Key<T> key = binding.getKey();
kevinb9n1601ae52008-06-03 22:21:04 +0000136 names.add(key.hasAnnotationType() ? key.getAnnotationName() : "[no annotation]");
crazyboblee62fcdde2007-02-03 02:10:13 +0000137 }
138 return names;
139 }
140
kevinb9n1601ae52008-06-03 22:21:04 +0000141 /** This is only used during Injector building. */
crazyboblee9a3861b2007-02-20 03:37:31 +0000142 void withDefaultSource(Object defaultSource, Runnable runnable) {
kevinb9n1601ae52008-06-03 22:21:04 +0000143 // TODO: inline/get rid of?
crazyboblee712705c2007-09-07 03:20:30 +0000144 SourceProviders.withDefault(defaultSource, runnable);
crazyboblee4727ee22007-01-30 03:13:38 +0000145 }
146
kevinb9n1601ae52008-06-03 22:21:04 +0000147 /** Returns the binding for {@code key}, or {@code null} if that binding cannot be resolved. */
limpbizkit3b1cd582008-04-28 00:06:01 +0000148 public <T> BindingImpl<T> getBinding(Key<T> key) {
149 try {
150 return getBindingOrThrow(key);
kevinb9n1601ae52008-06-03 22:21:04 +0000151 }
152 catch (ResolveFailedException e) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000153 return null;
154 }
155 }
156
157 /**
kevinb9n1601ae52008-06-03 22:21:04 +0000158 * Gets a binding implementation. First, it check to see if the parent has a binding. If the
159 * parent has a binding and the binding is scoped, it will use that binding. Otherwise, this
160 * checks for an explicit binding. If no explicit binding is found, it looks for a just-in-time
161 * binding.
crazyboblee712705c2007-09-07 03:20:30 +0000162 */
limpbizkit3b1cd582008-04-28 00:06:01 +0000163 public <T> BindingImpl<T> getBindingOrThrow(Key<T> key) throws ResolveFailedException {
dan.halem5d187432008-02-22 22:52:28 +0000164 if (parentInjector != null) {
165 BindingImpl<T> bindingImpl = getParentBinding(key);
166 if (bindingImpl != null) {
167 return bindingImpl;
168 }
169 }
170
crazyboblee712705c2007-09-07 03:20:30 +0000171 // Check explicit bindings, i.e. bindings created by modules.
172 BindingImpl<T> binding = getExplicitBindingImpl(key);
crazybobleea6e73982007-02-02 00:21:07 +0000173 if (binding != null) {
crazyboblee712705c2007-09-07 03:20:30 +0000174 return binding;
crazyboblee07e41822006-11-21 01:27:08 +0000175 }
176
crazyboblee712705c2007-09-07 03:20:30 +0000177 // Look for an on-demand binding.
178 return getJitBindingImpl(key);
179 }
crazybobleef33d23e2007-02-12 04:17:48 +0000180
dan.halem5d187432008-02-22 22:52:28 +0000181 /**
kevinb9n1601ae52008-06-03 22:21:04 +0000182 * Checks the parent injector for a scoped binding, and if available, creates an appropriate
183 * binding local to this injector and remembers it.
184 *
185 * TODO: think about this wrt parent jit bindings
dan.halem5d187432008-02-22 22:52:28 +0000186 */
187 @SuppressWarnings("unchecked")
188 private <T> BindingImpl<T> getParentBinding(Key<T> key) {
kevinb9n1601ae52008-06-03 22:21:04 +0000189 synchronized (parentBindings) {
dan.halem5d187432008-02-22 22:52:28 +0000190 // null values will mean that the parent doesn't have this binding
kevinb9n1601ae52008-06-03 22:21:04 +0000191 Binding<T> binding = (Binding<T>) parentBindings.get(key);
192 if (binding != null) {
193 return (BindingImpl<T>) binding;
dan.halem5d187432008-02-22 22:52:28 +0000194 }
kevinb9n1601ae52008-06-03 22:21:04 +0000195 try {
196 binding = parentInjector.getBinding(key);
197 }
limpbizkitdf98fcd2008-06-14 05:02:15 +0000198 catch (CreationException e) {
kevinb9n1601ae52008-06-03 22:21:04 +0000199 // if this happens, the parent can't create this key, and we ignore it
200 }
201
202 BindingImpl<T> bindingImpl = null;
203 if (binding != null
204 && binding.getScope() != null
205 && !binding.getScope().equals(Scopes.NO_SCOPE)) {
206 bindingImpl = new ProviderInstanceBindingImpl(
207 this,
208 key,
209 binding.getSource(),
210 new InternalFactoryToProviderAdapter(binding.getProvider(), binding.getSource()),
211 Scopes.NO_SCOPE,
212 binding.getProvider(),
213 LoadStrategy.LAZY);
214 }
215 parentBindings.put(key, bindingImpl); // this kinda scares me
216 return bindingImpl;
dan.halem5d187432008-02-22 22:52:28 +0000217 }
dan.halem5d187432008-02-22 22:52:28 +0000218 }
219
crazyboblee552472f2007-09-07 16:52:39 +0000220 public <T> Binding<T> getBinding(Class<T> type) {
221 return getBinding(Key.get(type));
222 }
223
kevinb9n1601ae52008-06-03 22:21:04 +0000224 /** Gets a binding which was specified explicitly in a module. */
crazyboblee712705c2007-09-07 03:20:30 +0000225 @SuppressWarnings("unchecked")
226 <T> BindingImpl<T> getExplicitBindingImpl(Key<T> key) {
227 return (BindingImpl<T>) explicitBindings.get(key);
228 }
229
kevinb9n1601ae52008-06-03 22:21:04 +0000230 /*
231 * Gets a just-in-time binding. This could be an injectable class (including those with
232 * @ImplementedBy), an automatically converted constant, a Provider<X> binding, etc.
crazyboblee712705c2007-09-07 03:20:30 +0000233 */
234 @SuppressWarnings("unchecked")
limpbizkit3b1cd582008-04-28 00:06:01 +0000235 <T> BindingImpl<T> getJitBindingImpl(Key<T> key) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000236 synchronized (jitBindings) {
237 // Support null values.
238 if (!jitBindings.containsKey(key)) {
239 BindingImpl<T> binding = createBindingJustInTime(key);
240 jitBindings.put(key, binding);
241 return binding;
kevinb9n1601ae52008-06-03 22:21:04 +0000242 }
243 else {
crazyboblee712705c2007-09-07 03:20:30 +0000244 return (BindingImpl<T>) jitBindings.get(key);
crazyboblee63b592b2007-01-25 02:45:24 +0000245 }
limpbizkitc808df02007-08-25 03:25:13 +0000246 }
crazyboblee07e41822006-11-21 01:27:08 +0000247 }
248
crazyboblee712705c2007-09-07 03:20:30 +0000249 /** Just-in-time binding cache. */
kevinb9n1601ae52008-06-03 22:21:04 +0000250 final Map<Key<?>, BindingImpl<?>> jitBindings = Maps.newHashMap();
crazyboblee712705c2007-09-07 03:20:30 +0000251
kevinb9n1601ae52008-06-03 22:21:04 +0000252 /* Returns true if the key type is Provider<?> (but not a subclass of Provider<?>). */
crazyboblee712705c2007-09-07 03:20:30 +0000253 static boolean isProvider(Key<?> key) {
254 return key.getTypeLiteral().getRawType().equals(Provider.class);
255 }
256
kevinb9n1601ae52008-06-03 22:21:04 +0000257 /** Creates a synthetic binding to Provider<T>, i.e. a binding to the provider from Binding<T>. */
crazyboblee712705c2007-09-07 03:20:30 +0000258 private <T> BindingImpl<Provider<T>> createProviderBinding(
limpbizkit05757142008-06-02 06:58:47 +0000259 Key<Provider<T>> key, LoadStrategy loadStrategy) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000260 Type providerType = key.getTypeLiteral().getType();
261
262 // If the Provider has no type parameter (raw Provider)...
263 if (!(providerType instanceof ParameterizedType)) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000264 throw new ResolveFailedException(ErrorMessage.cannotInjectRawProvider());
crazyboblee712705c2007-09-07 03:20:30 +0000265 }
266
kevinb9n1601ae52008-06-03 22:21:04 +0000267 Type entryType = ((ParameterizedType) providerType).getActualTypeArguments()[0];
crazyboblee712705c2007-09-07 03:20:30 +0000268
kevinb9n1601ae52008-06-03 22:21:04 +0000269 @SuppressWarnings("unchecked") // safe because T came from Key<Provider<T>>
crazyboblee712705c2007-09-07 03:20:30 +0000270 Key<T> providedKey = (Key<T>) key.ofType(entryType);
271
limpbizkit05757142008-06-02 06:58:47 +0000272 return new ProviderBindingImpl<T>(this, key, getBindingOrThrow(providedKey), loadStrategy);
crazyboblee712705c2007-09-07 03:20:30 +0000273 }
274
limpbizkit916f5482008-04-16 20:51:14 +0000275 void handleMissingBinding(Object source, Key<?> key) {
276 List<String> otherNames = getNamesOfBindingAnnotations(key.getTypeLiteral());
277
278 if (source instanceof Member) {
279 source = StackTraceElements.forMember((Member) source);
280 }
281
282 if (otherNames.isEmpty()) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000283 errorHandler.handle(source, ErrorMessage.missingBinding(key));
limpbizkit916f5482008-04-16 20:51:14 +0000284 }
285 else {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000286 errorHandler.handle(source, ErrorMessage.missingBindingButOthersExist(key, otherNames));
limpbizkit916f5482008-04-16 20:51:14 +0000287 }
288 }
289
crazyboblee712705c2007-09-07 03:20:30 +0000290 static class ProviderBindingImpl<T> extends BindingImpl<Provider<T>>
291 implements ProviderBinding<T> {
292
293 final Binding<T> providedBinding;
294
kevinb9n1601ae52008-06-03 22:21:04 +0000295 ProviderBindingImpl(
296 InjectorImpl injector,
297 Key<Provider<T>> key,
298 Binding<T> providedBinding,
299 LoadStrategy loadStrategy) {
300 super(
301 injector,
302 key,
303 SourceProviders.UNKNOWN_SOURCE,
304 createInternalFactory(providedBinding),
305 Scopes.NO_SCOPE,
306 loadStrategy);
crazyboblee712705c2007-09-07 03:20:30 +0000307 this.providedBinding = providedBinding;
308 }
309
kevinb9n1601ae52008-06-03 22:21:04 +0000310 static <T> InternalFactory<Provider<T>> createInternalFactory(Binding<T> providedBinding) {
crazyboblee712705c2007-09-07 03:20:30 +0000311 final Provider<T> provider = providedBinding.getProvider();
312 return new InternalFactory<Provider<T>>() {
kevinb9n1601ae52008-06-03 22:21:04 +0000313 public Provider<T> get(InternalContext context, InjectionPoint injectionPoint) {
crazyboblee712705c2007-09-07 03:20:30 +0000314 return provider;
315 }
316 };
317 }
318
319 public void accept(BindingVisitor<? super Provider<T>> bindingVisitor) {
320 bindingVisitor.visit(this);
321 }
322
323 public Binding<T> getTarget() {
324 return providedBinding;
325 }
326 }
327
328 <T> BindingImpl<T> invalidBinding(Class<T> clazz) {
329 return invalidBinding(Key.get(clazz));
330 }
331
332 <T> BindingImpl<T> invalidBinding(Key<T> key) {
kevinb9n1601ae52008-06-03 22:21:04 +0000333 return new InvalidBindingImpl<T>(this, key, SourceProviders.defaultSource());
crazyboblee712705c2007-09-07 03:20:30 +0000334 }
335
336 /**
crazyboblee712705c2007-09-07 03:20:30 +0000337 * Converts a constant string binding to the required type.
338 *
kevinb9n1601ae52008-06-03 22:21:04 +0000339 * <p>If the required type is eligible for conversion and a constant string binding is found but
340 * the actual conversion fails, an error is generated.
crazyboblee712705c2007-09-07 03:20:30 +0000341 *
kevinb9n1601ae52008-06-03 22:21:04 +0000342 * <p>If the type is not eligible for conversion or a constant string binding is not found, this
343 * method returns null.
crazyboblee712705c2007-09-07 03:20:30 +0000344 */
limpbizkit3b1cd582008-04-28 00:06:01 +0000345 private <T> BindingImpl<T> convertConstantStringBinding(Key<T> key)
346 throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000347 // Find a constant string binding.
348 Key<String> stringKey = key.ofType(String.class);
349 BindingImpl<String> stringBinding = getExplicitBindingImpl(stringKey);
350 if (stringBinding == null || !stringBinding.isConstant()) {
crazyboblee712705c2007-09-07 03:20:30 +0000351 return null;
352 }
353
crazyboblee7c9d7792007-09-09 03:41:05 +0000354 String stringValue = stringBinding.getProvider().get();
crazyboblee712705c2007-09-07 03:20:30 +0000355
crazyboblee7c9d7792007-09-09 03:41:05 +0000356 // Find a matching type converter.
357 TypeLiteral<T> type = key.getTypeLiteral();
358 MatcherAndConverter<?> matchingConverter = null;
359 for (MatcherAndConverter<?> converter : converters) {
limpbizkit916f5482008-04-16 20:51:14 +0000360 if (converter.getTypeMatcher().matches(type)) {
crazyboblee7c9d7792007-09-09 03:41:05 +0000361 if (matchingConverter != null) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000362 throw new ResolveFailedException(ErrorMessage.ambiguousTypeConversion(
363 stringValue, type, matchingConverter, converter));
crazyboblee7c9d7792007-09-09 03:41:05 +0000364 }
crazyboblee7c9d7792007-09-09 03:41:05 +0000365 matchingConverter = converter;
366 }
crazyboblee712705c2007-09-07 03:20:30 +0000367 }
368
crazyboblee7c9d7792007-09-09 03:41:05 +0000369 if (matchingConverter == null) {
370 // No converter can handle the given type.
371 return null;
crazyboblee712705c2007-09-07 03:20:30 +0000372 }
373
crazyboblee7c9d7792007-09-09 03:41:05 +0000374 // Try to convert the string. A failed conversion results in an error.
crazyboblee712705c2007-09-07 03:20:30 +0000375 try {
kevinb9n1601ae52008-06-03 22:21:04 +0000376 @SuppressWarnings("unchecked") // This cast is safe because we double check below.
limpbizkit916f5482008-04-16 20:51:14 +0000377 T converted = (T) matchingConverter.getTypeConverter()
378 .convert(stringValue, key.getTypeLiteral());
crazyboblee7c9d7792007-09-09 03:41:05 +0000379
380 if (converted == null) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000381 throw new ResolveFailedException(ErrorMessage.converterReturnedNull());
crazyboblee7c9d7792007-09-09 03:41:05 +0000382 }
383
kevinb9n1601ae52008-06-03 22:21:04 +0000384 // We have to filter out primitive types because an Integer is not an instance of int, and we
385 // provide converters for all the primitive types and know that they work anyway.
limpbizkitc0fe03b2008-06-02 04:46:53 +0000386 if (!type.getRawType().isInstance(converted)) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000387 throw new ResolveFailedException(ErrorMessage.conversionTypeError(converted, type));
crazyboblee7c9d7792007-09-09 03:41:05 +0000388 }
kevinb9n1601ae52008-06-03 22:21:04 +0000389 return new ConvertedConstantBindingImpl<T>(this, key, converted, stringBinding);
390 }
391 catch (ResolveFailedException e) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000392 throw e;
kevinb9n1601ae52008-06-03 22:21:04 +0000393 }
394 catch (Exception e) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000395 throw new ResolveFailedException(ErrorMessage.conversionError(stringValue,
396 stringBinding.getSource(), type, matchingConverter, e.getMessage()));
crazyboblee712705c2007-09-07 03:20:30 +0000397 }
398 }
399
400 private static class ConvertedConstantBindingImpl<T> extends BindingImpl<T>
401 implements ConvertedConstantBinding<T> {
crazyboblee712705c2007-09-07 03:20:30 +0000402 final T value;
403 final Provider<T> provider;
404 final Binding<String> originalBinding;
405
kevinb9n1601ae52008-06-03 22:21:04 +0000406 ConvertedConstantBindingImpl(
407 InjectorImpl injector, Key<T> key, T value, Binding<String> originalBinding) {
408 super(injector, key, SourceProviders.UNKNOWN_SOURCE, new ConstantFactory<T>(value),
409 Scopes.NO_SCOPE, LoadStrategy.LAZY);
crazyboblee712705c2007-09-07 03:20:30 +0000410 this.value = value;
kevinb9n1601ae52008-06-03 22:21:04 +0000411 provider = Providers.of(value);
crazyboblee712705c2007-09-07 03:20:30 +0000412 this.originalBinding = originalBinding;
413 }
414
kevinb9n1601ae52008-06-03 22:21:04 +0000415 @Override public Provider<T> getProvider() {
416 return provider;
crazyboblee712705c2007-09-07 03:20:30 +0000417 }
418
419 public void accept(BindingVisitor<? super T> bindingVisitor) {
420 bindingVisitor.visit(this);
421 }
422
423 public T getValue() {
kevinb9n1601ae52008-06-03 22:21:04 +0000424 return value;
crazyboblee712705c2007-09-07 03:20:30 +0000425 }
426
427 public Binding<String> getOriginal() {
kevinb9n1601ae52008-06-03 22:21:04 +0000428 return originalBinding;
crazyboblee712705c2007-09-07 03:20:30 +0000429 }
430
kevinb9n1601ae52008-06-03 22:21:04 +0000431 @Override public String toString() {
crazyboblee712705c2007-09-07 03:20:30 +0000432 return new ToStringBuilder(ConvertedConstantBinding.class)
433 .add("key", key)
434 .add("value", value)
435 .add("original", originalBinding)
436 .toString();
437 }
438 }
439
limpbizkit05757142008-06-02 06:58:47 +0000440 <T> BindingImpl<T> createBindingFromType(Class<T> type, LoadStrategy loadStrategy)
limpbizkit3b1cd582008-04-28 00:06:01 +0000441 throws ResolveFailedException {
kevinb9n1601ae52008-06-03 22:21:04 +0000442 BindingImpl<T> binding
443 = createUnitializedBinding(type, null, SourceProviders.defaultSource(), loadStrategy);
limpbizkit51411872008-05-13 22:15:29 +0000444 initializeBinding(binding);
445 return binding;
446 }
447
448 <T> void initializeBinding(BindingImpl<T> binding) throws ResolveFailedException {
kevinb9n1601ae52008-06-03 22:21:04 +0000449 // Put the partially constructed binding in the map a little early. This enables us to handle
450 // circular dependencies. Example: FooImpl -> BarImpl -> FooImpl.
451 // Note: We don't need to synchronize on jitBindings during injector creation.
limpbizkit51411872008-05-13 22:15:29 +0000452 if (binding instanceof ClassBindingImpl<?>) {
453 Key<T> key = binding.getKey();
454 jitBindings.put(key, binding);
455 boolean successful = false;
456 try {
457 binding.initialize(this);
458 successful = true;
kevinb9n1601ae52008-06-03 22:21:04 +0000459 }
460 finally {
limpbizkit51411872008-05-13 22:15:29 +0000461 if (!successful) {
462 jitBindings.remove(key);
463 }
464 }
465 }
466 }
467
468 /**
kevinb9n1601ae52008-06-03 22:21:04 +0000469 * Creates a binding for an injectable type with the given scope. Looks for a scope on the type if
470 * none is specified.
limpbizkit51411872008-05-13 22:15:29 +0000471 */
kevinb9n1601ae52008-06-03 22:21:04 +0000472 <T> BindingImpl<T> createUnitializedBinding(
473 Class<T> type, Scope scope, Object source, LoadStrategy loadStrategy)
474 throws ResolveFailedException {
limpbizkitc0fe03b2008-06-02 04:46:53 +0000475 // Don't try to inject arrays, or enums.
476 if (type.isArray() || type.isEnum()) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000477 throw new ResolveFailedException(ErrorMessage.missingBinding(type));
crazyboblee712705c2007-09-07 03:20:30 +0000478 }
479
480 // Handle @ImplementedBy
481 ImplementedBy implementedBy = type.getAnnotation(ImplementedBy.class);
482 if (implementedBy != null) {
crazybobleed71c19e2007-09-08 01:55:10 +0000483 // TODO: Scope internal factory.
limpbizkit05757142008-06-02 06:58:47 +0000484 return createImplementedByBinding(type, implementedBy, loadStrategy);
crazyboblee712705c2007-09-07 03:20:30 +0000485 }
486
487 // Handle @ProvidedBy.
488 ProvidedBy providedBy = type.getAnnotation(ProvidedBy.class);
489 if (providedBy != null) {
crazybobleed71c19e2007-09-08 01:55:10 +0000490 // TODO: Scope internal factory.
limpbizkit05757142008-06-02 06:58:47 +0000491 return createProvidedByBinding(type, providedBy, loadStrategy);
crazyboblee712705c2007-09-07 03:20:30 +0000492 }
493
crazyboblee712705c2007-09-07 03:20:30 +0000494 // We can't inject abstract classes.
495 // TODO: Method interceptors could actually enable us to implement
496 // abstract types. Should we remove this restriction?
497 if (Modifier.isAbstract(type.getModifiers())) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000498 throw new ResolveFailedException(ErrorMessage.cannotInjectAbstractType(type));
crazyboblee712705c2007-09-07 03:20:30 +0000499 }
500
501 // Error: Inner class.
502 if (Classes.isInnerClass(type)) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000503 throw new ResolveFailedException(ErrorMessage.cannotInjectInnerClass(type));
crazyboblee712705c2007-09-07 03:20:30 +0000504 }
505
506 if (scope == null) {
507 scope = Scopes.getScopeForType(type, scopes, errorHandler);
508 }
509
510 Key<T> key = Key.get(type);
511
limpbizkit05757142008-06-02 06:58:47 +0000512 LateBoundConstructor<T> lateBoundConstructor = new LateBoundConstructor<T>();
crazyboblee712705c2007-09-07 03:20:30 +0000513 InternalFactory<? extends T> scopedFactory
514 = Scopes.scope(key, this, lateBoundConstructor, scope);
kevinb9n1601ae52008-06-03 22:21:04 +0000515 return new ClassBindingImpl<T>(
516 this, key, source, scopedFactory, scope, lateBoundConstructor, loadStrategy);
crazyboblee712705c2007-09-07 03:20:30 +0000517 }
518
519 static class LateBoundConstructor<T> implements InternalFactory<T> {
crazyboblee712705c2007-09-07 03:20:30 +0000520 ConstructorInjector<T> constructorInjector;
521
kevinb9n1601ae52008-06-03 22:21:04 +0000522 void bind(InjectorImpl injector, Class<T> implementation) throws ResolveFailedException {
523 constructorInjector = injector.getConstructor(implementation);
crazyboblee712705c2007-09-07 03:20:30 +0000524 }
525
526 @SuppressWarnings("unchecked")
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000527 public T get(InternalContext context, InjectionPoint<?> injectionPoint) {
kevinb9n1601ae52008-06-03 22:21:04 +0000528 checkState(constructorInjector != null, "Construct before bind, " + constructorInjector);
limpbizkit00d513f2008-05-17 07:51:07 +0000529
kevinb9n1601ae52008-06-03 22:21:04 +0000530 // This may not actually be safe because it could return a super type of T (if that's all the
531 // client needs), but it should be OK in practice thanks to the wonders of erasure.
532 return (T) constructorInjector.construct(context, injectionPoint.getKey().getRawType());
crazyboblee712705c2007-09-07 03:20:30 +0000533 }
534 }
535
kevinb9n1601ae52008-06-03 22:21:04 +0000536 /** Creates a binding for a type annotated with @ProvidedBy. */
537 <T> BindingImpl<T> createProvidedByBinding(final Class<T> type, ProvidedBy providedBy,
538 LoadStrategy loadStrategy) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000539 final Class<? extends Provider<?>> providerType = providedBy.value();
540
541 // Make sure it's not the same type. TODO: Can we check for deeper loops?
542 if (providerType == type) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000543 throw new ResolveFailedException(ErrorMessage.recursiveProviderType());
crazyboblee712705c2007-09-07 03:20:30 +0000544 }
545
kevinb9n1601ae52008-06-03 22:21:04 +0000546 // TODO: Make sure the provided type extends type. We at least check the type at runtime below.
crazyboblee712705c2007-09-07 03:20:30 +0000547
kevinb9n1601ae52008-06-03 22:21:04 +0000548 // Assume the provider provides an appropriate type. We double check at runtime.
crazyboblee712705c2007-09-07 03:20:30 +0000549 @SuppressWarnings("unchecked")
kevinb9n1601ae52008-06-03 22:21:04 +0000550 Key<? extends Provider<T>> providerKey = (Key<? extends Provider<T>>) Key.get(providerType);
551 final BindingImpl<? extends Provider<?>> providerBinding = getBindingOrThrow(providerKey);
crazyboblee712705c2007-09-07 03:20:30 +0000552
553 InternalFactory<T> internalFactory = new InternalFactory<T>() {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000554 public T get(InternalContext context, InjectionPoint injectionPoint) {
kevinb9n1601ae52008-06-03 22:21:04 +0000555 Provider<?> provider = providerBinding.internalFactory.get(context, injectionPoint);
crazyboblee712705c2007-09-07 03:20:30 +0000556 Object o = provider.get();
kevinb9n1601ae52008-06-03 22:21:04 +0000557 if (o != null && !type.isInstance(o)) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000558 errorHandler.handle(StackTraceElements.forType(type),
559 ErrorMessage.subtypeNotProvided(providerType, type));
crazyboblee712705c2007-09-07 03:20:30 +0000560 throw new AssertionError();
561 }
kevinb9n1601ae52008-06-03 22:21:04 +0000562
563 @SuppressWarnings("unchecked") // protected by isInstance() check above
564 T t = (T) o;
565 return t;
crazyboblee712705c2007-09-07 03:20:30 +0000566 }
567 };
568
kevinb9n1601ae52008-06-03 22:21:04 +0000569 return new LinkedProviderBindingImpl<T>(
570 this,
571 Key.get(type),
572 StackTraceElements.forType(type),
573 internalFactory,
574 Scopes.NO_SCOPE,
575 providerKey,
576 loadStrategy);
crazyboblee712705c2007-09-07 03:20:30 +0000577 }
578
kevinb9n1601ae52008-06-03 22:21:04 +0000579 /** Creates a binding for a type annotated with @ImplementedBy. */
580 <T> BindingImpl<T> createImplementedByBinding(
581 Class<T> type, ImplementedBy implementedBy, LoadStrategy loadStrategy)
582 throws ResolveFailedException {
583 // TODO: Use scope annotation on type if present. Right now, we always use NO_SCOPE.
crazyboblee712705c2007-09-07 03:20:30 +0000584 Class<?> implementationType = implementedBy.value();
585
586 // Make sure it's not the same type. TODO: Can we check for deeper cycles?
587 if (implementationType == type) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000588 throw new ResolveFailedException(ErrorMessage.recursiveImplementationType());
crazyboblee712705c2007-09-07 03:20:30 +0000589 }
590
591 // Make sure implementationType extends type.
592 if (!type.isAssignableFrom(implementationType)) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000593 throw new ResolveFailedException(ErrorMessage.notASubtype(implementationType, type));
crazyboblee712705c2007-09-07 03:20:30 +0000594 }
595
596 // After the preceding check, this cast is safe.
597 @SuppressWarnings("unchecked")
598 Class<? extends T> subclass = (Class<? extends T>) implementationType;
599
600 // Look up the target binding.
kevinb9n1601ae52008-06-03 22:21:04 +0000601 final BindingImpl<? extends T> targetBinding = getBindingOrThrow(Key.get(subclass));
crazyboblee712705c2007-09-07 03:20:30 +0000602
603 InternalFactory<T> internalFactory = new InternalFactory<T>() {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000604 public T get(InternalContext context, InjectionPoint<?> injectionPoint) {
605 return targetBinding.internalFactory.get(context, injectionPoint);
crazyboblee712705c2007-09-07 03:20:30 +0000606 }
607 };
608
kevinb9n1601ae52008-06-03 22:21:04 +0000609 return new LinkedBindingImpl<T>(
610 this,
611 Key.get(type),
612 StackTraceElements.forType(type),
613 internalFactory,
614 Scopes.NO_SCOPE,
615 Key.get(subclass),
616 loadStrategy);
crazyboblee712705c2007-09-07 03:20:30 +0000617 }
618
limpbizkit3b1cd582008-04-28 00:06:01 +0000619 <T> BindingImpl<T> createBindingJustInTime(Key<T> key) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000620 // Handle cases where T is a Provider<?>.
621 if (isProvider(key)) {
kevinb9n1601ae52008-06-03 22:21:04 +0000622 // These casts are safe. We know T extends Provider<X> and that given Key<Provider<X>>,
623 // createProviderBinding() will return BindingImpl<Provider<X>>.
624 @SuppressWarnings("unchecked")
625 BindingImpl<T> binding = (BindingImpl<T>) createProviderBinding((Key) key, LoadStrategy.LAZY);
crazyboblee5d575692007-09-07 17:42:28 +0000626 return binding;
crazyboblee712705c2007-09-07 03:20:30 +0000627 }
628
crazyboblee712705c2007-09-07 03:20:30 +0000629 // Try to convert a constant string binding to the requested type.
630 BindingImpl<T> convertedBinding = convertConstantStringBinding(key);
631 if (convertedBinding != null) {
632 return convertedBinding;
633 }
634
635 // If the key has an annotation...
636 if (key.hasAnnotationType()) {
637 // Look for a binding without annotation attributes or return null.
limpbizkit3b1cd582008-04-28 00:06:01 +0000638 if (key.hasAttributes()) {
639 try {
640 return getBindingOrThrow(key.withoutAttributes());
kevinb9n1601ae52008-06-03 22:21:04 +0000641 }
642 catch (ResolveFailedException ignored) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000643 // throw with a more appropriate message below
644 }
645 }
limpbizkitdf98fcd2008-06-14 05:02:15 +0000646 throw new ResolveFailedException(ErrorMessage.missingBinding(key));
crazyboblee712705c2007-09-07 03:20:30 +0000647 }
648
limpbizkit9b0be9f2008-03-28 06:12:41 +0000649 // Create a binding based on the raw type.
crazyboblee712705c2007-09-07 03:20:30 +0000650 @SuppressWarnings("unchecked")
limpbizkit9b0be9f2008-03-28 06:12:41 +0000651 Class<T> clazz = (Class<T>) key.getTypeLiteral().getRawType();
limpbizkit05757142008-06-02 06:58:47 +0000652 return createBindingFromType(clazz, LoadStrategy.LAZY);
crazyboblee712705c2007-09-07 03:20:30 +0000653 }
654
kevinb9n1601ae52008-06-03 22:21:04 +0000655 <T> InternalFactory<? extends T> getInternalFactory(Key<T> key) throws ResolveFailedException {
limpbizkit3b1cd582008-04-28 00:06:01 +0000656 return getBindingOrThrow(key).internalFactory;
crazyboblee712705c2007-09-07 03:20:30 +0000657 }
658
kevinb9n1601ae52008-06-03 22:21:04 +0000659 /** Field and method injectors. */
kevinb9na2915a92007-02-28 06:20:30 +0000660 final Map<Class<?>, List<SingleMemberInjector>> injectors
661 = new ReferenceCache<Class<?>, List<SingleMemberInjector>>() {
662 protected List<SingleMemberInjector> create(Class<?> key) {
kevinb9n1601ae52008-06-03 22:21:04 +0000663 List<SingleMemberInjector> injectors = Lists.newArrayList();
kevinb9na99dca72007-02-11 04:48:57 +0000664 addInjectors(key, injectors);
665 return injectors;
666 }
667 };
crazyboblee66b415a2006-08-25 02:01:19 +0000668
669 /**
kevinb9n1601ae52008-06-03 22:21:04 +0000670 * Recursively adds injectors for fields and methods from the given class to the given list.
671 * Injects parent classes before sub classes.
crazyboblee66b415a2006-08-25 02:01:19 +0000672 */
kevinb9na2915a92007-02-28 06:20:30 +0000673 void addInjectors(Class clazz, List<SingleMemberInjector> injectors) {
crazyboblee66b415a2006-08-25 02:01:19 +0000674 if (clazz == Object.class) {
675 return;
676 }
677
678 // Add injectors for superclass first.
679 addInjectors(clazz.getSuperclass(), injectors);
680
681 // TODO (crazybob): Filter out overridden members.
kevinb9na2915a92007-02-28 06:20:30 +0000682 addSingleInjectorsForFields(clazz.getDeclaredFields(), false, injectors);
683 addSingleInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors);
crazyboblee66b415a2006-08-25 02:01:19 +0000684 }
685
kevinb9na2915a92007-02-28 06:20:30 +0000686 void addSingleInjectorsForMethods(Method[] methods, boolean statics,
687 List<SingleMemberInjector> injectors) {
crazyboblee66b415a2006-08-25 02:01:19 +0000688 addInjectorsForMembers(Arrays.asList(methods), statics, injectors,
kevinb9na2915a92007-02-28 06:20:30 +0000689 new SingleInjectorFactory<Method>() {
kevinb9n1601ae52008-06-03 22:21:04 +0000690 public SingleMemberInjector create(InjectorImpl injector, Method method)
691 throws ResolveFailedException {
kevinb9na2915a92007-02-28 06:20:30 +0000692 return new SingleMethodInjector(injector, method);
crazyboblee66b415a2006-08-25 02:01:19 +0000693 }
694 });
695 }
696
kevinb9na2915a92007-02-28 06:20:30 +0000697 void addSingleInjectorsForFields(Field[] fields, boolean statics,
698 List<SingleMemberInjector> injectors) {
crazyboblee66b415a2006-08-25 02:01:19 +0000699 addInjectorsForMembers(Arrays.asList(fields), statics, injectors,
kevinb9na2915a92007-02-28 06:20:30 +0000700 new SingleInjectorFactory<Field>() {
kevinb9n1601ae52008-06-03 22:21:04 +0000701 public SingleMemberInjector create(InjectorImpl injector, Field field)
702 throws ResolveFailedException {
kevinb9na2915a92007-02-28 06:20:30 +0000703 return new SingleFieldInjector(injector, field);
crazyboblee66b415a2006-08-25 02:01:19 +0000704 }
705 });
706 }
707
kevinb9n1601ae52008-06-03 22:21:04 +0000708 <M extends Member & AnnotatedElement> void addInjectorsForMembers(List<M> members,
709 boolean statics, List<SingleMemberInjector> injectors,
kevinb9na2915a92007-02-28 06:20:30 +0000710 SingleInjectorFactory<M> injectorFactory) {
crazyboblee66b415a2006-08-25 02:01:19 +0000711 for (M member : members) {
712 if (isStatic(member) == statics) {
crazyboblee9a3861b2007-02-20 03:37:31 +0000713 Inject inject = member.getAnnotation(Inject.class);
crazyboblee66b415a2006-08-25 02:01:19 +0000714 if (inject != null) {
715 try {
crazyboblee4602a6f2007-02-15 02:45:18 +0000716 injectors.add(injectorFactory.create(this, member));
kevinb9na99dca72007-02-11 04:48:57 +0000717 }
limpbizkit3b1cd582008-04-28 00:06:01 +0000718 catch (ResolveFailedException e) {
crazyboblee4602a6f2007-02-15 02:45:18 +0000719 if (!inject.optional()) {
crazyboblee4727ee22007-01-30 03:13:38 +0000720 // TODO: Report errors for more than one parameter per member.
limpbizkitdf98fcd2008-06-14 05:02:15 +0000721 errorHandler.handle(e.getMessage(member));
crazyboblee66b415a2006-08-25 02:01:19 +0000722 }
723 }
724 }
725 }
726 }
727 }
728
crazyboblee1fc49782007-02-25 21:02:47 +0000729 Map<Key<?>, BindingImpl<?>> internalBindings() {
crazyboblee712705c2007-09-07 03:20:30 +0000730 return explicitBindings;
crazybobleea6e73982007-02-02 00:21:07 +0000731 }
732
kevinb9n225310e2007-02-20 04:12:01 +0000733 // not test-covered
crazybobleea6e73982007-02-02 00:21:07 +0000734 public Map<Key<?>, Binding<?>> getBindings() {
crazyboblee712705c2007-09-07 03:20:30 +0000735 return Collections.<Key<?>, Binding<?>>unmodifiableMap(explicitBindings);
crazybobleea6e73982007-02-02 00:21:07 +0000736 }
737
kevinb9na2915a92007-02-28 06:20:30 +0000738 interface SingleInjectorFactory<M extends Member & AnnotatedElement> {
kevinb9n1601ae52008-06-03 22:21:04 +0000739 SingleMemberInjector create(InjectorImpl injector, M member) throws ResolveFailedException;
crazyboblee66b415a2006-08-25 02:01:19 +0000740 }
741
742 private boolean isStatic(Member member) {
743 return Modifier.isStatic(member.getModifiers());
744 }
745
kevinb9n48d13072007-02-12 18:21:26 +0000746 private static class BindingsMultimap {
kevinb9n1601ae52008-06-03 22:21:04 +0000747 final Multimap<TypeLiteral<?>, Binding<?>> multimap = Multimaps.newArrayListMultimap();
kevinb9n48d13072007-02-12 18:21:26 +0000748
kevinb9n1601ae52008-06-03 22:21:04 +0000749 <T> void put(TypeLiteral<T> type, BindingImpl<T> binding) {
750 multimap.put(type, binding);
kevinb9n48d13072007-02-12 18:21:26 +0000751 }
752
753 // safe because we only put matching entries into the map
754 @SuppressWarnings("unchecked")
kevinb9n1601ae52008-06-03 22:21:04 +0000755 <T> List<Binding<T>> getAll(TypeLiteral<T> type) {
756 return (List<Binding<T>>) (List) multimap.get(type);
kevinb9n48d13072007-02-12 18:21:26 +0000757 }
758 }
759
kevinb9na2915a92007-02-28 06:20:30 +0000760 class SingleFieldInjector implements SingleMemberInjector {
crazyboblee66b415a2006-08-25 02:01:19 +0000761 final Field field;
762 final InternalFactory<?> factory;
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000763 final InjectionPoint<?> injectionPoint;
crazyboblee66b415a2006-08-25 02:01:19 +0000764
crazyboblee712705c2007-09-07 03:20:30 +0000765 public SingleFieldInjector(final InjectorImpl injector, Field field)
limpbizkit3b1cd582008-04-28 00:06:01 +0000766 throws ResolveFailedException {
crazyboblee66b415a2006-08-25 02:01:19 +0000767 this.field = field;
crazyboblee4727ee22007-01-30 03:13:38 +0000768
769 // Ewwwww...
crazyboblee66b415a2006-08-25 02:01:19 +0000770 field.setAccessible(true);
771
kevinb9n1601ae52008-06-03 22:21:04 +0000772 final Key<?> key
773 = Keys.get(field.getGenericType(), field, field.getAnnotations(), errorHandler);
limpbizkit3b1cd582008-04-28 00:06:01 +0000774 factory = new ResolvingCallable<InternalFactory<?>>() {
kevinb9n1601ae52008-06-03 22:21:04 +0000775 public InternalFactory<?> call() throws ResolveFailedException {
776 return injector.getInternalFactory(key);
777 }
778 }.runWithDefaultSource(StackTraceElements.forMember(field));
crazyboblee66b415a2006-08-25 02:01:19 +0000779
kevinb9n1601ae52008-06-03 22:21:04 +0000780 injectionPoint = InjectionPoint.newInstance(
781 field, Nullability.forAnnotations(field.getAnnotations()), key, injector);
crazyboblee66b415a2006-08-25 02:01:19 +0000782 }
783
crazybobleed71c19e2007-09-08 01:55:10 +0000784 public Collection<Dependency<?>> getDependencies() {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000785 return Collections.<Dependency<?>>singleton(injectionPoint);
crazybobleed71c19e2007-09-08 01:55:10 +0000786 }
787
crazyboblee66b415a2006-08-25 02:01:19 +0000788 public void inject(InternalContext context, Object o) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000789 context.setInjectionPoint(injectionPoint);
crazyboblee66b415a2006-08-25 02:01:19 +0000790 try {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000791 Object value = factory.get(context, injectionPoint);
crazyboblee4602a6f2007-02-15 02:45:18 +0000792 field.set(o, value);
kevinb9na99dca72007-02-11 04:48:57 +0000793 }
794 catch (IllegalAccessException e) {
crazyboblee66b415a2006-08-25 02:01:19 +0000795 throw new AssertionError(e);
kevinb9na99dca72007-02-11 04:48:57 +0000796 }
limpbizkitdf98fcd2008-06-14 05:02:15 +0000797 catch (CreationException e) {
kevinb9n9119a632007-02-22 01:28:24 +0000798 throw e;
799 }
limpbizkit1dabcfd2007-08-25 08:06:30 +0000800 catch (ProvisionException provisionException) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000801 provisionException.addContext(injectionPoint);
limpbizkit1dabcfd2007-08-25 08:06:30 +0000802 throw provisionException;
803 }
804 catch (RuntimeException runtimeException) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000805 throw new ProvisionException(
806 ErrorMessage.errorInjectingField().toString(), runtimeException);
kevinb9n9119a632007-02-22 01:28:24 +0000807 }
kevinb9na99dca72007-02-11 04:48:57 +0000808 finally {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000809 context.setInjectionPoint(null);
crazyboblee66b415a2006-08-25 02:01:19 +0000810 }
811 }
812 }
813
814 /**
815 * Gets parameter injectors.
816 *
817 * @param member to which the parameters belong
crazyboblee66b415a2006-08-25 02:01:19 +0000818 * @return injections
819 */
kevinb9n1601ae52008-06-03 22:21:04 +0000820 SingleParameterInjector<?>[] getParametersInjectors(Member member, List<Parameter<?>> parameters)
limpbizkit3b1cd582008-04-28 00:06:01 +0000821 throws ResolveFailedException {
kevinb9na2915a92007-02-28 06:20:30 +0000822 SingleParameterInjector<?>[] parameterInjectors
limpbizkit916f5482008-04-16 20:51:14 +0000823 = new SingleParameterInjector<?>[parameters.size()];
crazyboblee15969212007-02-01 02:01:59 +0000824 int index = 0;
limpbizkit916f5482008-04-16 20:51:14 +0000825 for (Parameter<?> parameter : parameters) {
826 parameterInjectors[index] = createParameterInjector(parameter, member);
kevinb9na99dca72007-02-11 04:48:57 +0000827 index++;
crazyboblee66b415a2006-08-25 02:01:19 +0000828 }
kevinb9na99dca72007-02-11 04:48:57 +0000829 return parameterInjectors;
crazyboblee66b415a2006-08-25 02:01:19 +0000830 }
831
kevinb9na2915a92007-02-28 06:20:30 +0000832 <T> SingleParameterInjector<T> createParameterInjector(
kevinb9n1601ae52008-06-03 22:21:04 +0000833 final Parameter<T> parameter, Member member) throws ResolveFailedException {
834 InternalFactory<? extends T> factory = new ResolvingCallable<InternalFactory<? extends T>>() {
835 public InternalFactory<? extends T> call() throws ResolveFailedException {
836 return getInternalFactory(parameter.getKey());
837 }
limpbizkit3b1cd582008-04-28 00:06:01 +0000838 }.runWithDefaultSource(StackTraceElements.forMember(member));
crazyboblee66b415a2006-08-25 02:01:19 +0000839
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000840 InjectionPoint<T> injectionPoint = InjectionPoint.newInstance(
limpbizkit916f5482008-04-16 20:51:14 +0000841 member, parameter.getIndex(), parameter.getNullability(), parameter.getKey(), this);
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000842 return new SingleParameterInjector<T>(injectionPoint, factory);
crazyboblee66b415a2006-08-25 02:01:19 +0000843 }
844
kevinb9na2915a92007-02-28 06:20:30 +0000845 static class SingleMethodInjector implements SingleMemberInjector {
crazyboblee0b3189c2007-02-24 00:14:51 +0000846 final MethodInvoker methodInvoker;
kevinb9na2915a92007-02-28 06:20:30 +0000847 final SingleParameterInjector<?>[] parameterInjectors;
crazyboblee66b415a2006-08-25 02:01:19 +0000848
kevinb9na2915a92007-02-28 06:20:30 +0000849 public SingleMethodInjector(InjectorImpl injector, final Method method)
limpbizkit3b1cd582008-04-28 00:06:01 +0000850 throws ResolveFailedException {
crazyboblee0b3189c2007-02-24 00:14:51 +0000851 // We can't use FastMethod if the method is private.
kevinb9n1601ae52008-06-03 22:21:04 +0000852 if (Modifier.isPrivate(method.getModifiers()) || Modifier.isProtected(method.getModifiers()))
853 {
crazyboblee0b3189c2007-02-24 00:14:51 +0000854 method.setAccessible(true);
kevinb9n1601ae52008-06-03 22:21:04 +0000855 methodInvoker = new MethodInvoker() {
856 public Object invoke(Object target, Object... parameters)
857 throws IllegalAccessException, InvocationTargetException {
crazyboblee0b3189c2007-02-24 00:14:51 +0000858 return method.invoke(target, parameters);
859 }
860 };
861 }
862 else {
863 FastClass fastClass = GuiceFastClass.create(method.getDeclaringClass());
864 final FastMethod fastMethod = fastClass.getMethod(method);
865
kevinb9n1601ae52008-06-03 22:21:04 +0000866 methodInvoker = new MethodInvoker() {
crazyboblee0b3189c2007-02-24 00:14:51 +0000867 public Object invoke(Object target, Object... parameters)
kevinb9n1601ae52008-06-03 22:21:04 +0000868 throws IllegalAccessException, InvocationTargetException {
crazyboblee0b3189c2007-02-24 00:14:51 +0000869 return fastMethod.invoke(target, parameters);
870 }
871 };
872 }
873
kevinb9n1601ae52008-06-03 22:21:04 +0000874 parameterInjectors = method.getGenericParameterTypes().length > 0
875 ? injector.getParametersInjectors(
876 method, Parameter.forMethod(injector.errorHandler, method))
crazyboblee4727ee22007-01-30 03:13:38 +0000877 : null;
crazyboblee66b415a2006-08-25 02:01:19 +0000878 }
879
880 public void inject(InternalContext context, Object o) {
881 try {
crazyboblee0b3189c2007-02-24 00:14:51 +0000882 methodInvoker.invoke(o, getParameters(context, parameterInjectors));
kevinb9na99dca72007-02-11 04:48:57 +0000883 }
limpbizkit1dabcfd2007-08-25 08:06:30 +0000884 catch (IllegalAccessException e) {
885 throw new AssertionError(e);
886 }
limpbizkitc808df02007-08-25 03:25:13 +0000887 catch (InvocationTargetException e) {
limpbizkit1dabcfd2007-08-25 08:06:30 +0000888 Throwable cause = e.getCause() != null ? e.getCause() : e;
limpbizkitdf98fcd2008-06-14 05:02:15 +0000889 throw new ProvisionException(ErrorMessage.errorInjectingMethod().toString(), cause);
crazyboblee66b415a2006-08-25 02:01:19 +0000890 }
891 }
crazybobleed71c19e2007-09-08 01:55:10 +0000892
893 public Collection<Dependency<?>> getDependencies() {
kevinb9n1601ae52008-06-03 22:21:04 +0000894 List<Dependency<?>> dependencies = new ArrayList<Dependency<?>>(parameterInjectors.length);
crazybobleed71c19e2007-09-08 01:55:10 +0000895 for (SingleParameterInjector<?> parameterInjector : parameterInjectors) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000896 dependencies.add(parameterInjector.injectionPoint);
crazybobleed71c19e2007-09-08 01:55:10 +0000897 }
898 return Collections.unmodifiableList(dependencies);
899 }
crazyboblee66b415a2006-08-25 02:01:19 +0000900 }
901
kevinb9n1601ae52008-06-03 22:21:04 +0000902 /** Invokes a method. */
crazyboblee0b3189c2007-02-24 00:14:51 +0000903 interface MethodInvoker {
kevinb9n1601ae52008-06-03 22:21:04 +0000904 Object invoke(Object target, Object... parameters)
905 throws IllegalAccessException, InvocationTargetException;
crazyboblee0b3189c2007-02-24 00:14:51 +0000906 }
907
kevinb9n1601ae52008-06-03 22:21:04 +0000908 final Map<Class<?>, Object> constructors = new ReferenceCache<Class<?>, Object>() {
kevinb9na99dca72007-02-11 04:48:57 +0000909 @SuppressWarnings("unchecked")
limpbizkit3b1cd582008-04-28 00:06:01 +0000910 protected Object create(Class<?> implementation) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000911 // TODO: reduce duplication between this and createUnitializedBinding
crazybobleed0c4b8b2007-09-06 02:47:04 +0000912 if (!Classes.isConcrete(implementation)) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000913 return new ResolveFailedException(
limpbizkitdf98fcd2008-06-14 05:02:15 +0000914 ErrorMessage.cannotInjectAbstractType(implementation));
kevinb9na99dca72007-02-11 04:48:57 +0000915 }
crazybobleed0c4b8b2007-09-06 02:47:04 +0000916 if (Classes.isInnerClass(implementation)) {
kevinb9n1601ae52008-06-03 22:21:04 +0000917 return new ResolveFailedException(
limpbizkitdf98fcd2008-06-14 05:02:15 +0000918 ErrorMessage.cannotInjectInnerClass(implementation));
kevinb9n9da90b32007-04-20 15:28:04 +0000919 }
kevinb9na2915a92007-02-28 06:20:30 +0000920 return new ConstructorInjector(InjectorImpl.this, implementation);
kevinb9na99dca72007-02-11 04:48:57 +0000921 }
922 };
crazyboblee66b415a2006-08-25 02:01:19 +0000923
kevinb9na2915a92007-02-28 06:20:30 +0000924 static class SingleParameterInjector<T> {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000925 final InjectionPoint<T> injectionPoint;
crazyboblee66b415a2006-08-25 02:01:19 +0000926 final InternalFactory<? extends T> factory;
927
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000928 public SingleParameterInjector(InjectionPoint<T> injectionPoint,
crazyboblee66b415a2006-08-25 02:01:19 +0000929 InternalFactory<? extends T> factory) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000930 this.injectionPoint = injectionPoint;
crazyboblee66b415a2006-08-25 02:01:19 +0000931 this.factory = factory;
932 }
933
crazyboblee664a82e2007-01-25 23:09:51 +0000934 T inject(InternalContext context) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000935 context.setInjectionPoint(injectionPoint);
crazyboblee66b415a2006-08-25 02:01:19 +0000936 try {
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000937 return factory.get(context, injectionPoint);
kevinb9na99dca72007-02-11 04:48:57 +0000938 }
limpbizkitdf98fcd2008-06-14 05:02:15 +0000939 catch (CreationException e) {
kevinb9n9119a632007-02-22 01:28:24 +0000940 throw e;
941 }
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000942 catch (ProvisionException provisionException) {
943 provisionException.addContext(injectionPoint);
944 throw provisionException;
limpbizkit1dabcfd2007-08-25 08:06:30 +0000945 }
946 catch (RuntimeException runtimeException) {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000947 throw new ProvisionException(
948 ErrorMessage.errorInjectingMethod().toString(), runtimeException);
kevinb9n9119a632007-02-22 01:28:24 +0000949 }
kevinb9na99dca72007-02-11 04:48:57 +0000950 finally {
limpbizkit05a6c5e2008-06-05 00:29:11 +0000951 context.setInjectionPoint(null);
crazyboblee66b415a2006-08-25 02:01:19 +0000952 }
953 }
954 }
955
kevinb9n1601ae52008-06-03 22:21:04 +0000956 /** Iterates over parameter injectors and creates an array of parameter values. */
957 static Object[] getParameters(
958 InternalContext context, SingleParameterInjector[] parameterInjectors) {
crazyboblee66b415a2006-08-25 02:01:19 +0000959 if (parameterInjectors == null) {
960 return null;
961 }
962
963 Object[] parameters = new Object[parameterInjectors.length];
964 for (int i = 0; i < parameters.length; i++) {
crazyboblee664a82e2007-01-25 23:09:51 +0000965 parameters[i] = parameterInjectors[i].inject(context);
crazyboblee66b415a2006-08-25 02:01:19 +0000966 }
967 return parameters;
968 }
969
crazyboblee63b592b2007-01-25 02:45:24 +0000970 void injectMembers(Object o, InternalContext context) {
limpbizkitc808df02007-08-25 03:25:13 +0000971 if (o == null) {
972 return;
973 }
kevinb9na2915a92007-02-28 06:20:30 +0000974 List<SingleMemberInjector> injectorsForClass = injectors.get(o.getClass());
975 for (SingleMemberInjector injector : injectorsForClass) {
crazyboblee66b415a2006-08-25 02:01:19 +0000976 injector.inject(context, o);
977 }
978 }
979
kevinb9n225310e2007-02-20 04:12:01 +0000980 // Not test-covered
crazyboblee63b592b2007-01-25 02:45:24 +0000981 public void injectMembers(final Object o) {
crazyboblee66b415a2006-08-25 02:01:19 +0000982 callInContext(new ContextualCallable<Void>() {
983 public Void call(InternalContext context) {
crazyboblee63b592b2007-01-25 02:45:24 +0000984 injectMembers(o, context);
crazyboblee66b415a2006-08-25 02:01:19 +0000985 return null;
986 }
987 });
988 }
989
crazybobleebd9544e2007-02-25 20:32:11 +0000990 public <T> Provider<T> getProvider(Class<T> type) {
991 return getProvider(Key.get(type));
crazybobleee5fbbb02007-02-05 07:00:27 +0000992 }
993
limpbizkit3b1cd582008-04-28 00:06:01 +0000994 <T> Provider<T> getProviderOrThrow(final Key<T> key) throws ResolveFailedException {
crazyboblee712705c2007-09-07 03:20:30 +0000995 final InternalFactory<? extends T> factory = getInternalFactory(key);
crazyboblee66b415a2006-08-25 02:01:19 +0000996
crazybobleebd9544e2007-02-25 20:32:11 +0000997 return new Provider<T>() {
crazyboblee63b592b2007-01-25 02:45:24 +0000998 public T get() {
999 return callInContext(new ContextualCallable<T>() {
1000 public T call(InternalContext context) {
kevinb9n1601ae52008-06-03 22:21:04 +00001001 InjectionPoint<T> injectionPoint = InjectionPoint.newInstance(key, InjectorImpl.this);
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001002 context.setInjectionPoint(injectionPoint);
crazyboblee63b592b2007-01-25 02:45:24 +00001003 try {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001004 return factory.get(context, injectionPoint);
1005 }
kevinb9n1601ae52008-06-03 22:21:04 +00001006 catch (ProvisionException provisionException) {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001007 provisionException.addContext(injectionPoint);
1008 throw provisionException;
kevinb9na99dca72007-02-11 04:48:57 +00001009 }
1010 finally {
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001011 context.setInjectionPoint(null);
crazyboblee63b592b2007-01-25 02:45:24 +00001012 }
1013 }
1014 });
crazyboblee66b415a2006-08-25 02:01:19 +00001015 }
crazybobleed7908e82007-02-16 01:04:53 +00001016
1017 public String toString() {
1018 return factory.toString();
1019 }
crazyboblee63b592b2007-01-25 02:45:24 +00001020 };
crazyboblee66b415a2006-08-25 02:01:19 +00001021 }
1022
crazyboblee712705c2007-09-07 03:20:30 +00001023 public <T> Provider<T> getProvider(final Key<T> key) {
limpbizkit3b1cd582008-04-28 00:06:01 +00001024 try {
1025 return getProviderOrThrow(key);
kevinb9n1601ae52008-06-03 22:21:04 +00001026 }
1027 catch (ResolveFailedException e) {
limpbizkitdf98fcd2008-06-14 05:02:15 +00001028 throw new CreationException(new Message(
1029 ErrorMessage.bindingNotFound(key, e.getMessage()).toString()));
crazyboblee712705c2007-09-07 03:20:30 +00001030 }
crazyboblee712705c2007-09-07 03:20:30 +00001031 }
1032
kevinb9n27f8a582007-02-28 22:54:06 +00001033 public <T> T getInstance(Key<T> key) {
1034 return getProvider(key).get();
1035 }
1036
1037 public <T> T getInstance(Class<T> type) {
1038 return getProvider(type).get();
1039 }
1040
kevinb9n1601ae52008-06-03 22:21:04 +00001041 final ThreadLocal<InternalContext[]> localContext = new ThreadLocal<InternalContext[]>() {
kevinb9na99dca72007-02-11 04:48:57 +00001042 protected InternalContext[] initialValue() {
1043 return new InternalContext[1];
1044 }
1045 };
crazyboblee66b415a2006-08-25 02:01:19 +00001046
kevinb9n1601ae52008-06-03 22:21:04 +00001047 /** Looks up thread local context. Creates (and removes) a new context if necessary. */
crazyboblee66b415a2006-08-25 02:01:19 +00001048 <T> T callInContext(ContextualCallable<T> callable) {
1049 InternalContext[] reference = localContext.get();
1050 if (reference[0] == null) {
crazyboblee63b592b2007-01-25 02:45:24 +00001051 reference[0] = new InternalContext(this);
crazyboblee66b415a2006-08-25 02:01:19 +00001052 try {
1053 return callable.call(reference[0]);
kevinb9na99dca72007-02-11 04:48:57 +00001054 }
1055 finally {
crazyboblee66b415a2006-08-25 02:01:19 +00001056 // Only remove the context if this call created it.
1057 reference[0] = null;
1058 }
kevinb9na99dca72007-02-11 04:48:57 +00001059 }
1060 else {
crazyboblee66b415a2006-08-25 02:01:19 +00001061 // Someone else will clean up this context.
1062 return callable.call(reference[0]);
1063 }
1064 }
1065
kevinb9n1601ae52008-06-03 22:21:04 +00001066 /** Gets a constructor function for a given implementation class. */
crazyboblee66b415a2006-08-25 02:01:19 +00001067 @SuppressWarnings("unchecked")
kevinb9n1601ae52008-06-03 22:21:04 +00001068 <T> ConstructorInjector<T> getConstructor(Class<T> implementation) throws ResolveFailedException {
limpbizkit3b1cd582008-04-28 00:06:01 +00001069 Object o = constructors.get(implementation);
1070 if (o instanceof ResolveFailedException) {
1071 throw (ResolveFailedException) o;
kevinb9n1601ae52008-06-03 22:21:04 +00001072 }
1073 else if (o instanceof ConstructorInjector<?>) {
limpbizkit3b1cd582008-04-28 00:06:01 +00001074 return (ConstructorInjector<T>) o;
kevinb9n1601ae52008-06-03 22:21:04 +00001075 }
1076 else {
limpbizkit3b1cd582008-04-28 00:06:01 +00001077 throw new AssertionError();
1078 }
crazyboblee66b415a2006-08-25 02:01:19 +00001079 }
1080
kevinb9n1601ae52008-06-03 22:21:04 +00001081 /** Injects a field or method in a given object. */
limpbizkit8b237452008-04-22 06:47:36 +00001082 public interface SingleMemberInjector {
crazyboblee66b415a2006-08-25 02:01:19 +00001083 void inject(InternalContext context, Object o);
crazybobleed71c19e2007-09-08 01:55:10 +00001084 Collection<Dependency<?>> getDependencies();
1085 }
1086
kevinb9n1601ae52008-06-03 22:21:04 +00001087 List<Dependency<?>> getModifiableFieldAndMethodDependenciesFor(Class<?> clazz) {
crazybobleed71c19e2007-09-08 01:55:10 +00001088 List<SingleMemberInjector> injectors = this.injectors.get(clazz);
kevinb9n1601ae52008-06-03 22:21:04 +00001089 List<Dependency<?>> dependencies = Lists.newArrayList();
crazybobleed71c19e2007-09-08 01:55:10 +00001090 for (SingleMemberInjector singleMemberInjector : injectors) {
1091 dependencies.addAll(singleMemberInjector.getDependencies());
1092 }
1093 return dependencies;
1094 }
1095
1096 Collection<Dependency<?>> getFieldAndMethodDependenciesFor(Class<?> clazz) {
kevinb9n1601ae52008-06-03 22:21:04 +00001097 return Collections.unmodifiableList(getModifiableFieldAndMethodDependenciesFor(clazz));
crazyboblee66b415a2006-08-25 02:01:19 +00001098 }
1099
crazybobleee3adfd62007-02-02 21:30:08 +00001100 public String toString() {
kevinb9na2915a92007-02-28 06:20:30 +00001101 return new ToStringBuilder(Injector.class)
crazyboblee712705c2007-09-07 03:20:30 +00001102 .add("bindings", explicitBindings)
crazybobleee3adfd62007-02-02 21:30:08 +00001103 .toString();
1104 }
crazyboblee66b415a2006-08-25 02:01:19 +00001105}