blob: be1c4c8b3e50e7acd2a5af8aa4c09e9671282593 [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
limpbizkit5ae41eb2009-06-06 17:51:27 +000017package com.google.inject.internal;
crazyboblee66b415a2006-08-25 02:01:19 +000018
sberlinb7a02b02011-07-08 00:34:16 +000019import com.google.common.base.Objects;
20import com.google.common.collect.ImmutableList;
21import com.google.common.collect.ImmutableMap;
22import com.google.common.collect.ImmutableSet;
23import com.google.common.collect.Lists;
24import com.google.common.collect.Maps;
guice.mirrorbot@gmail.comefa4e9f2011-09-13 17:41:32 +000025import com.google.common.collect.Sets;
limpbizkit5ae41eb2009-06-06 17:51:27 +000026import com.google.inject.Binder;
27import com.google.inject.Binding;
28import com.google.inject.ConfigurationException;
29import com.google.inject.ImplementedBy;
30import com.google.inject.Injector;
31import com.google.inject.Key;
32import com.google.inject.MembersInjector;
33import com.google.inject.Module;
34import com.google.inject.ProvidedBy;
35import com.google.inject.Provider;
36import com.google.inject.ProvisionException;
limpbizkit19203222009-07-24 00:48:12 +000037import com.google.inject.Scope;
sberlin8b64d452010-12-13 02:44:36 +000038import com.google.inject.Stage;
limpbizkit48f3a912009-11-23 20:24:31 +000039import com.google.inject.TypeLiteral;
limpbizkit@gmail.com9a227be2010-07-03 15:51:31 +000040import com.google.inject.internal.util.SourceProvider;
limpbizkitafa4b5d2008-08-02 18:40:47 +000041import com.google.inject.spi.BindingTargetVisitor;
limpbizkit76c24b12008-12-25 04:32:41 +000042import com.google.inject.spi.ConvertedConstantBinding;
limpbizkita98bc7a2008-08-29 16:52:44 +000043import com.google.inject.spi.Dependency;
limpbizkit48f3a912009-11-23 20:24:31 +000044import com.google.inject.spi.HasDependencies;
limpbizkit9dc32d42008-06-15 11:29:10 +000045import com.google.inject.spi.InjectionPoint;
limpbizkit76c24b12008-12-25 04:32:41 +000046import com.google.inject.spi.ProviderBinding;
sberlinb2f17602010-11-19 02:33:32 +000047import com.google.inject.spi.TypeConverterBinding;
crazyboblee712705c2007-09-07 03:20:30 +000048import com.google.inject.util.Providers;
sberlinb7a02b02011-07-08 00:34:16 +000049
limpbizkit48f3a912009-11-23 20:24:31 +000050import java.lang.annotation.Annotation;
limpbizkitb0f3c9b2008-11-15 09:19:28 +000051import java.lang.reflect.GenericArrayType;
kevinb9n1601ae52008-06-03 22:21:04 +000052import java.lang.reflect.InvocationTargetException;
kevinb9n1601ae52008-06-03 22:21:04 +000053import java.lang.reflect.ParameterizedType;
54import java.lang.reflect.Type;
kevinb9n1601ae52008-06-03 22:21:04 +000055import java.util.Collections;
sberlin7df9cf32010-05-25 12:25:46 +000056import java.util.HashSet;
kevinb9n1601ae52008-06-03 22:21:04 +000057import java.util.List;
58import java.util.Map;
limpbizkit3a8c1552008-11-16 21:43:01 +000059import java.util.Set;
crazyboblee66b415a2006-08-25 02:01:19 +000060
61/**
kevinb9na2915a92007-02-28 06:20:30 +000062 * Default {@link Injector} implementation.
crazyboblee66b415a2006-08-25 02:01:19 +000063 *
crazyboblee66b415a2006-08-25 02:01:19 +000064 * @author crazybob@google.com (Bob Lee)
65 */
limpbizkit5ae41eb2009-06-06 17:51:27 +000066final class InjectorImpl implements Injector, Lookups {
limpbizkit3ea80952009-07-26 02:01:55 +000067 public static final TypeLiteral<String> STRING_TYPE = TypeLiteral.get(String.class);
Sam Berlind57f8ec2014-04-08 12:25:33 -040068
sberlin8b64d452010-12-13 02:44:36 +000069 /** Options that control how the injector behaves. */
70 static class InjectorOptions {
71 final Stage stage;
72 final boolean jitDisabled;
73 final boolean disableCircularProxies;
Sam Berlinc7567772012-05-31 19:54:04 -040074 final boolean atInjectRequired;
Christian Edward Grubere3915852013-05-16 11:00:54 -070075 final boolean exactBindingAnnotationsRequired;
Christian Edward Gruber9e2d95b2013-06-26 17:43:11 -070076
Sam Berlinc7567772012-05-31 19:54:04 -040077 InjectorOptions(Stage stage, boolean jitDisabled, boolean disableCircularProxies,
Christian Edward Grubere3915852013-05-16 11:00:54 -070078 boolean atInjectRequired, boolean exactBindingAnnotationsRequired) {
sberlin8b64d452010-12-13 02:44:36 +000079 this.stage = stage;
80 this.jitDisabled = jitDisabled;
81 this.disableCircularProxies = disableCircularProxies;
Sam Berlinc7567772012-05-31 19:54:04 -040082 this.atInjectRequired = atInjectRequired;
Christian Edward Grubere3915852013-05-16 11:00:54 -070083 this.exactBindingAnnotationsRequired = exactBindingAnnotationsRequired;
sberlin8b64d452010-12-13 02:44:36 +000084 }
Sam Berlind57f8ec2014-04-08 12:25:33 -040085
sberlin8b64d452010-12-13 02:44:36 +000086 @Override
87 public String toString() {
sberlind9c913a2011-06-26 21:02:54 +000088 return Objects.toStringHelper(getClass())
sberlin8b64d452010-12-13 02:44:36 +000089 .add("stage", stage)
90 .add("jitDisabled", jitDisabled)
91 .add("disableCircularProxies", disableCircularProxies)
Sam Berlinc7567772012-05-31 19:54:04 -040092 .add("atInjectRequired", atInjectRequired)
Christian Edward Grubere3915852013-05-16 11:00:54 -070093 .add("exactBindingAnnotationsRequired", exactBindingAnnotationsRequired)
sberlin8b64d452010-12-13 02:44:36 +000094 .toString();
95 }
96 }
Sam Berlind57f8ec2014-04-08 12:25:33 -040097
sberlin888a2642010-02-11 22:07:07 +000098 /** some limitations on what just in time bindings are allowed. */
Sam Berlind57f8ec2014-04-08 12:25:33 -040099 enum JitLimitation {
sberlin888a2642010-02-11 22:07:07 +0000100 /** does not allow just in time bindings */
101 NO_JIT,
102 /** allows existing just in time bindings, but does not allow new ones */
103 EXISTING_JIT,
Tavian Barnes6c9726f2015-01-07 10:37:17 -0500104 /** allows existing just in time bindings & allows new ones to be created */
sberlin888a2642010-02-11 22:07:07 +0000105 NEW_OR_EXISTING_JIT,
106 }
limpbizkit3ea80952009-07-26 02:01:55 +0000107
limpbizkit5fb9d922008-10-14 23:35:56 +0000108 final State state;
109 final InjectorImpl parent;
limpbizkit3d58d6b2008-03-08 16:11:47 +0000110 final BindingsMultimap bindingsMultimap = new BindingsMultimap();
sberlinc2a66252010-02-13 16:16:44 +0000111 final InjectorOptions options;
crazyboblee4727ee22007-01-30 03:13:38 +0000112
limpbizkit79dc99b2008-12-09 19:02:12 +0000113 /** Just-in-time binding cache. Guarded by state.lock() */
114 final Map<Key<?>, BindingImpl<?>> jitBindings = Maps.newHashMap();
guice.mirrorbot@gmail.comefa4e9f2011-09-13 17:41:32 +0000115 /**
116 * Cache of Keys that we were unable to create JIT bindings for, so we don't
117 * keep trying. Also guarded by state.lock().
118 */
119 final Set<Key<?>> failedJitBindings = Sets.newHashSet();
limpbizkit79dc99b2008-12-09 19:02:12 +0000120
limpbizkit8d620752009-03-31 22:37:26 +0000121 Lookups lookups = new DeferredLookups(this);
122
sberlind9c913a2011-06-26 21:02:54 +0000123 InjectorImpl(InjectorImpl parent, State state, InjectorOptions injectorOptions) {
limpbizkit5fb9d922008-10-14 23:35:56 +0000124 this.parent = parent;
limpbizkitfcbdf992008-11-26 02:37:35 +0000125 this.state = state;
sberlinc2a66252010-02-13 16:16:44 +0000126 this.options = injectorOptions;
limpbizkit5fb9d922008-10-14 23:35:56 +0000127
128 if (parent != null) {
129 localContext = parent.localContext;
130 } else {
Sam Berlinca81e592014-07-01 16:52:59 -0400131 localContext = new ThreadLocal<Object[]>();
limpbizkit5fb9d922008-10-14 23:35:56 +0000132 }
crazyboblee66b415a2006-08-25 02:01:19 +0000133 }
134
kevinb9n1601ae52008-06-03 22:21:04 +0000135 /** Indexes bindings by type. */
crazyboblee62fcdde2007-02-03 02:10:13 +0000136 void index() {
limpbizkit5fb9d922008-10-14 23:35:56 +0000137 for (Binding<?> binding : state.getExplicitBindingsThisLevel().values()) {
crazyboblee62fcdde2007-02-03 02:10:13 +0000138 index(binding);
139 }
140 }
141
limpbizkit5fb9d922008-10-14 23:35:56 +0000142 <T> void index(Binding<T> binding) {
crazybobleec3e88492007-02-25 22:36:58 +0000143 bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
crazyboblee62fcdde2007-02-03 02:10:13 +0000144 }
145
crazyboblee62fcdde2007-02-03 02:10:13 +0000146 public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
limpbizkit76c24b12008-12-25 04:32:41 +0000147 return bindingsMultimap.getAll(type);
crazyboblee62fcdde2007-02-03 02:10:13 +0000148 }
149
limpbizkit9dc32d42008-06-15 11:29:10 +0000150 /** Returns the binding for {@code key} */
limpbizkit3b1cd582008-04-28 00:06:01 +0000151 public <T> BindingImpl<T> getBinding(Key<T> key) {
limpbizkit06898062008-11-02 05:14:55 +0000152 Errors errors = new Errors(key);
limpbizkit3b1cd582008-04-28 00:06:01 +0000153 try {
sberlin888a2642010-02-11 22:07:07 +0000154 BindingImpl<T> result = getBindingOrThrow(key, errors, JitLimitation.EXISTING_JIT);
limpbizkit06898062008-11-02 05:14:55 +0000155 errors.throwConfigurationExceptionIfErrorsExist();
limpbizkit9dc32d42008-06-15 11:29:10 +0000156 return result;
limpbizkit490833f2008-11-02 00:12:39 +0000157 } catch (ErrorsException e) {
158 throw new ConfigurationException(errors.merge(e.getErrors()).getMessages());
limpbizkit3b1cd582008-04-28 00:06:01 +0000159 }
160 }
161
sberlin67606252010-03-10 22:18:52 +0000162 public <T> BindingImpl<T> getExistingBinding(Key<T> key) {
163 // Check explicit bindings, i.e. bindings created by modules.
164 BindingImpl<T> explicitBinding = state.getExplicitBinding(key);
165 if (explicitBinding != null) {
166 return explicitBinding;
167 }
168 synchronized (state.lock()) {
169 // See if any jit bindings have been created for this key.
170 for (InjectorImpl injector = this; injector != null; injector = injector.parent) {
171 @SuppressWarnings("unchecked")
172 BindingImpl<T> jitBinding = (BindingImpl<T>) injector.jitBindings.get(key);
173 if(jitBinding != null) {
174 return jitBinding;
175 }
176 }
177 }
Sam Berlind57f8ec2014-04-08 12:25:33 -0400178
sberlin67606252010-03-10 22:18:52 +0000179 // If Key is a Provider, we have to see if the type it is providing exists,
180 // and, if so, we have to create the binding for the provider.
181 if(isProvider(key)) {
182 try {
183 // This is safe because isProvider above ensures that T is a Provider<?>
Sam Berlinc7567772012-05-31 19:54:04 -0400184 @SuppressWarnings({"unchecked", "cast"})
sberlin67606252010-03-10 22:18:52 +0000185 Key<?> providedKey = (Key<?>)getProvidedKey((Key)key, new Errors());
186 if(getExistingBinding(providedKey) != null) {
187 return getBinding(key);
188 }
189 } catch(ErrorsException e) {
190 throw new ConfigurationException(e.getErrors().getMessages());
191 }
192 }
193
194 // No existing binding exists.
195 return null;
196 }
197
limpbizkit3b1cd582008-04-28 00:06:01 +0000198 /**
kevinb9n1601ae52008-06-03 22:21:04 +0000199 * Gets a binding implementation. First, it check to see if the parent has a binding. If the
200 * parent has a binding and the binding is scoped, it will use that binding. Otherwise, this
201 * checks for an explicit binding. If no explicit binding is found, it looks for a just-in-time
202 * binding.
crazyboblee712705c2007-09-07 03:20:30 +0000203 */
sberlin888a2642010-02-11 22:07:07 +0000204 <T> BindingImpl<T> getBindingOrThrow(Key<T> key, Errors errors, JitLimitation jitType)
limpbizkit163c48a2008-06-16 02:58:08 +0000205 throws ErrorsException {
crazyboblee712705c2007-09-07 03:20:30 +0000206 // Check explicit bindings, i.e. bindings created by modules.
limpbizkit5fb9d922008-10-14 23:35:56 +0000207 BindingImpl<T> binding = state.getExplicitBinding(key);
crazybobleea6e73982007-02-02 00:21:07 +0000208 if (binding != null) {
crazyboblee712705c2007-09-07 03:20:30 +0000209 return binding;
crazyboblee07e41822006-11-21 01:27:08 +0000210 }
211
crazyboblee712705c2007-09-07 03:20:30 +0000212 // Look for an on-demand binding.
sberlin888a2642010-02-11 22:07:07 +0000213 return getJustInTimeBinding(key, errors, jitType);
crazyboblee712705c2007-09-07 03:20:30 +0000214 }
crazybobleef33d23e2007-02-12 04:17:48 +0000215
crazyboblee552472f2007-09-07 16:52:39 +0000216 public <T> Binding<T> getBinding(Class<T> type) {
217 return getBinding(Key.get(type));
218 }
219
limpbizkitedd8d642008-10-18 19:50:49 +0000220 public Injector getParent() {
221 return parent;
222 }
223
limpbizkit5fb9d922008-10-14 23:35:56 +0000224 public Injector createChildInjector(Iterable<? extends Module> modules) {
sberlinc2a66252010-02-13 16:16:44 +0000225 return new InternalInjectorCreator()
limpbizkit5fb9d922008-10-14 23:35:56 +0000226 .parentInjector(this)
limpbizkit5fb9d922008-10-14 23:35:56 +0000227 .addModules(modules)
228 .build();
229 }
230
231 public Injector createChildInjector(Module... modules) {
sberlin5221c152011-07-22 21:13:53 +0000232 return createChildInjector(ImmutableList.copyOf(modules));
crazyboblee712705c2007-09-07 03:20:30 +0000233 }
234
limpbizkit9dc32d42008-06-15 11:29:10 +0000235 /**
236 * Returns a just-in-time binding for {@code key}, creating it if necessary.
237 *
limpbizkit79dc99b2008-12-09 19:02:12 +0000238 * @throws ErrorsException if the binding could not be created.
crazyboblee712705c2007-09-07 03:20:30 +0000239 */
sberlin888a2642010-02-11 22:07:07 +0000240 private <T> BindingImpl<T> getJustInTimeBinding(Key<T> key, Errors errors, JitLimitation jitType)
limpbizkit5fb9d922008-10-14 23:35:56 +0000241 throws ErrorsException {
sberlin888a2642010-02-11 22:07:07 +0000242
guice.mirrorbot@gmail.comefa4e9f2011-09-13 17:41:32 +0000243 boolean jitOverride = isProvider(key) || isTypeLiteral(key) || isMembersInjector(key);
limpbizkita8dccb32008-11-11 22:41:56 +0000244 synchronized (state.lock()) {
limpbizkit79dc99b2008-12-09 19:02:12 +0000245 // first try to find a JIT binding that we've already created
246 for (InjectorImpl injector = this; injector != null; injector = injector.parent) {
247 @SuppressWarnings("unchecked") // we only store bindings that match their key
248 BindingImpl<T> binding = (BindingImpl<T>) injector.jitBindings.get(key);
249
250 if (binding != null) {
sberlin9cdfe3a2011-03-02 13:53:17 +0000251 // If we found a JIT binding and we don't allow them,
252 // fail. (But allow bindings created through TypeConverters.)
253 if (options.jitDisabled
254 && jitType == JitLimitation.NO_JIT
255 && !jitOverride
256 && !(binding instanceof ConvertedConstantBindingImpl)) {
257 throw errors.jitDisabled(key).toException();
258 } else {
259 return binding;
260 }
limpbizkit5fb9d922008-10-14 23:35:56 +0000261 }
kevinb9n1601ae52008-06-03 22:21:04 +0000262 }
Christian Edward Gruber9e2d95b2013-06-26 17:43:11 -0700263
guice.mirrorbot@gmail.comefa4e9f2011-09-13 17:41:32 +0000264 // If we previously failed creating this JIT binding and our Errors has
265 // already recorded an error, then just directly throw that error.
266 // We need to do this because it's possible we already cleaned up the
267 // entry in jitBindings (during cleanup), and we may be trying
268 // to create it again (in the case of a recursive JIT binding).
269 // We need both of these guards for different reasons
270 // failedJitBindings.contains: We want to continue processing if we've never
271 // failed before, so that our initial error message contains
272 // as much useful information as possible about what errors exist.
273 // errors.hasErrors: If we haven't already failed, then it's OK to
274 // continue processing, to make sure the ultimate error message
275 // is the correct one.
276 // See: ImplicitBindingsTest#testRecursiveJitBindingsCleanupCorrectly
277 // for where this guard compes into play.
278 if (failedJitBindings.contains(key) && errors.hasErrors()) {
279 throw errors.toException();
280 }
sberlin9cdfe3a2011-03-02 13:53:17 +0000281 return createJustInTimeBindingRecursive(key, errors, options.jitDisabled, jitType);
guice.mirrorbot@gmail.comefa4e9f2011-09-13 17:41:32 +0000282 } // end synchronized(state.lock())
crazyboblee07e41822006-11-21 01:27:08 +0000283 }
284
limpbizkit0ca7f912009-03-28 19:11:40 +0000285 /** Returns true if the key type is Provider (but not a subclass of Provider). */
limpbizkit5ae41eb2009-06-06 17:51:27 +0000286 private static boolean isProvider(Key<?> key) {
crazyboblee712705c2007-09-07 03:20:30 +0000287 return key.getTypeLiteral().getRawType().equals(Provider.class);
288 }
Christian Edward Gruber9e2d95b2013-06-26 17:43:11 -0700289
sberlin@gmail.comb1fa81f2010-08-26 22:36:19 +0000290 private static boolean isTypeLiteral(Key<?> key) {
291 return key.getTypeLiteral().getRawType().equals(TypeLiteral.class);
292 }
Sam Berlind57f8ec2014-04-08 12:25:33 -0400293
sberlin67606252010-03-10 22:18:52 +0000294 private static <T> Key<T> getProvidedKey(Key<Provider<T>> key, Errors errors) throws ErrorsException {
295 Type providerType = key.getTypeLiteral().getType();
296
297 // If the Provider has no type parameter (raw Provider)...
298 if (!(providerType instanceof ParameterizedType)) {
299 throw errors.cannotInjectRawProvider().toException();
300 }
301
302 Type entryType = ((ParameterizedType) providerType).getActualTypeArguments()[0];
303
304 @SuppressWarnings("unchecked") // safe because T came from Key<Provider<T>>
305 Key<T> providedKey = (Key<T>) key.ofType(entryType);
306 return providedKey;
307 }
crazyboblee712705c2007-09-07 03:20:30 +0000308
limpbizkit0ca7f912009-03-28 19:11:40 +0000309 /** Returns true if the key type is MembersInjector (but not a subclass of MembersInjector). */
limpbizkit5ae41eb2009-06-06 17:51:27 +0000310 private static boolean isMembersInjector(Key<?> key) {
limpbizkit0ca7f912009-03-28 19:11:40 +0000311 return key.getTypeLiteral().getRawType().equals(MembersInjector.class)
Sam Berlinc00df282014-07-01 16:53:41 -0400312 && key.getAnnotationType() == null;
limpbizkit0ca7f912009-03-28 19:11:40 +0000313 }
314
315 private <T> BindingImpl<MembersInjector<T>> createMembersInjectorBinding(
316 Key<MembersInjector<T>> key, Errors errors) throws ErrorsException {
317 Type membersInjectorType = key.getTypeLiteral().getType();
318 if (!(membersInjectorType instanceof ParameterizedType)) {
319 throw errors.cannotInjectRawMembersInjector().toException();
320 }
321
322 @SuppressWarnings("unchecked") // safe because T came from Key<MembersInjector<T>>
323 TypeLiteral<T> instanceType = (TypeLiteral<T>) TypeLiteral.get(
324 ((ParameterizedType) membersInjectorType).getActualTypeArguments()[0]);
limpbizkit7cef5b02009-03-29 21:16:51 +0000325 MembersInjector<T> membersInjector = membersInjectorStore.get(instanceType, errors);
limpbizkit0ca7f912009-03-28 19:11:40 +0000326
327 InternalFactory<MembersInjector<T>> factory = new ConstantFactory<MembersInjector<T>>(
328 Initializables.of(membersInjector));
329
330
limpbizkit@gmail.com9a227be2010-07-03 15:51:31 +0000331 return new InstanceBindingImpl<MembersInjector<T>>(this, key, SourceProvider.UNKNOWN_SOURCE,
limpbizkit0ca7f912009-03-28 19:11:40 +0000332 factory, ImmutableSet.<InjectionPoint>of(), membersInjector);
333 }
334
335 /**
336 * Creates a synthetic binding to {@code Provider<T>}, i.e. a binding to the provider from
337 * {@code Binding<T>}.
338 */
limpbizkit76c24b12008-12-25 04:32:41 +0000339 private <T> BindingImpl<Provider<T>> createProviderBinding(Key<Provider<T>> key, Errors errors)
340 throws ErrorsException {
sberlin67606252010-03-10 22:18:52 +0000341 Key<T> providedKey = getProvidedKey(key, errors);
sberlin888a2642010-02-11 22:07:07 +0000342 BindingImpl<T> delegate = getBindingOrThrow(providedKey, errors, JitLimitation.NO_JIT);
limpbizkit76c24b12008-12-25 04:32:41 +0000343 return new ProviderBindingImpl<T>(this, key, delegate);
limpbizkit916f5482008-04-16 20:51:14 +0000344 }
345
limpbizkit5ae41eb2009-06-06 17:51:27 +0000346 private static class ProviderBindingImpl<T> extends BindingImpl<Provider<T>>
limpbizkit19203222009-07-24 00:48:12 +0000347 implements ProviderBinding<Provider<T>>, HasDependencies {
limpbizkita8865992008-08-21 07:09:59 +0000348 final BindingImpl<T> providedBinding;
crazyboblee712705c2007-09-07 03:20:30 +0000349
limpbizkit76c24b12008-12-25 04:32:41 +0000350 ProviderBindingImpl(InjectorImpl injector, Key<Provider<T>> key, Binding<T> providedBinding) {
351 super(injector, key, providedBinding.getSource(), createInternalFactory(providedBinding),
352 Scoping.UNSCOPED);
limpbizkita8865992008-08-21 07:09:59 +0000353 this.providedBinding = (BindingImpl<T>) providedBinding;
crazyboblee712705c2007-09-07 03:20:30 +0000354 }
355
kevinb9n1601ae52008-06-03 22:21:04 +0000356 static <T> InternalFactory<Provider<T>> createInternalFactory(Binding<T> providedBinding) {
crazyboblee712705c2007-09-07 03:20:30 +0000357 final Provider<T> provider = providedBinding.getProvider();
358 return new InternalFactory<Provider<T>>() {
sberlin888a2642010-02-11 22:07:07 +0000359 public Provider<T> get(Errors errors, InternalContext context, Dependency dependency, boolean linked) {
crazyboblee712705c2007-09-07 03:20:30 +0000360 return provider;
361 }
362 };
363 }
364
limpbizkit76c24b12008-12-25 04:32:41 +0000365 public Key<? extends T> getProvidedKey() {
366 return providedBinding.getKey();
367 }
368
limpbizkit8996e802008-12-28 01:44:29 +0000369 public <V> V acceptTargetVisitor(BindingTargetVisitor<? super Provider<T>, V> visitor) {
limpbizkit03b81a62009-03-18 05:34:39 +0000370 return visitor.visit(this);
371 }
372
373 public void applyTo(Binder binder) {
374 throw new UnsupportedOperationException("This element represents a synthetic binding.");
limpbizkit477f9f92008-07-28 07:05:14 +0000375 }
limpbizkitc3f92842008-12-30 19:43:47 +0000376
377 @Override public String toString() {
sberlind9c913a2011-06-26 21:02:54 +0000378 return Objects.toStringHelper(ProviderBinding.class)
limpbizkitc3f92842008-12-30 19:43:47 +0000379 .add("key", getKey())
380 .add("providedKey", getProvidedKey())
381 .toString();
382 }
limpbizkit19203222009-07-24 00:48:12 +0000383
384 public Set<Dependency<?>> getDependencies() {
385 return ImmutableSet.<Dependency<?>>of(Dependency.get(getProvidedKey()));
386 }
Sam Berlind57f8ec2014-04-08 12:25:33 -0400387
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000388 @Override
389 public boolean equals(Object obj) {
390 if(obj instanceof ProviderBindingImpl) {
391 ProviderBindingImpl<?> o = (ProviderBindingImpl<?>)obj;
392 return getKey().equals(o.getKey())
393 && getScoping().equals(o.getScoping())
394 && Objects.equal(providedBinding, o.providedBinding);
395 } else {
396 return false;
397 }
398 }
Sam Berlind57f8ec2014-04-08 12:25:33 -0400399
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000400 @Override
401 public int hashCode() {
402 return Objects.hashCode(getKey(), getScoping(), providedBinding);
403 }
crazyboblee712705c2007-09-07 03:20:30 +0000404 }
405
crazyboblee712705c2007-09-07 03:20:30 +0000406 /**
crazyboblee712705c2007-09-07 03:20:30 +0000407 * Converts a constant string binding to the required type.
408 *
limpbizkit9dc32d42008-06-15 11:29:10 +0000409 * @return the binding if it could be resolved, or null if the binding doesn't exist
limpbizkit163c48a2008-06-16 02:58:08 +0000410 * @throws com.google.inject.internal.ErrorsException if there was an error resolving the binding
crazyboblee712705c2007-09-07 03:20:30 +0000411 */
limpbizkit9dc32d42008-06-15 11:29:10 +0000412 private <T> BindingImpl<T> convertConstantStringBinding(Key<T> key, Errors errors)
limpbizkit163c48a2008-06-16 02:58:08 +0000413 throws ErrorsException {
crazyboblee712705c2007-09-07 03:20:30 +0000414 // Find a constant string binding.
limpbizkit3ea80952009-07-26 02:01:55 +0000415 Key<String> stringKey = key.ofType(STRING_TYPE);
limpbizkit5fb9d922008-10-14 23:35:56 +0000416 BindingImpl<String> stringBinding = state.getExplicitBinding(stringKey);
crazyboblee712705c2007-09-07 03:20:30 +0000417 if (stringBinding == null || !stringBinding.isConstant()) {
crazyboblee712705c2007-09-07 03:20:30 +0000418 return null;
419 }
420
crazyboblee7c9d7792007-09-09 03:41:05 +0000421 String stringValue = stringBinding.getProvider().get();
limpbizkit163c48a2008-06-16 02:58:08 +0000422 Object source = stringBinding.getSource();
crazyboblee712705c2007-09-07 03:20:30 +0000423
crazyboblee7c9d7792007-09-09 03:41:05 +0000424 // Find a matching type converter.
425 TypeLiteral<T> type = key.getTypeLiteral();
sberlinb2f17602010-11-19 02:33:32 +0000426 TypeConverterBinding typeConverterBinding = state.getConverter(stringValue, type, errors, source);
crazyboblee712705c2007-09-07 03:20:30 +0000427
sberlinb2f17602010-11-19 02:33:32 +0000428 if (typeConverterBinding == null) {
crazyboblee7c9d7792007-09-09 03:41:05 +0000429 // No converter can handle the given type.
430 return null;
crazyboblee712705c2007-09-07 03:20:30 +0000431 }
432
crazyboblee7c9d7792007-09-09 03:41:05 +0000433 // Try to convert the string. A failed conversion results in an error.
crazyboblee712705c2007-09-07 03:20:30 +0000434 try {
kevinb9n1601ae52008-06-03 22:21:04 +0000435 @SuppressWarnings("unchecked") // This cast is safe because we double check below.
sberlinb2f17602010-11-19 02:33:32 +0000436 T converted = (T) typeConverterBinding.getTypeConverter().convert(stringValue, type);
crazyboblee7c9d7792007-09-09 03:41:05 +0000437
438 if (converted == null) {
sberlinb2f17602010-11-19 02:33:32 +0000439 throw errors.converterReturnedNull(stringValue, source, type, typeConverterBinding)
limpbizkitc5c488e2008-06-16 01:42:25 +0000440 .toException();
crazyboblee7c9d7792007-09-09 03:41:05 +0000441 }
442
limpbizkitc0fe03b2008-06-02 04:46:53 +0000443 if (!type.getRawType().isInstance(converted)) {
sberlinb2f17602010-11-19 02:33:32 +0000444 throw errors.conversionTypeError(stringValue, source, type, typeConverterBinding, converted)
limpbizkitc5c488e2008-06-16 01:42:25 +0000445 .toException();
crazyboblee7c9d7792007-09-09 03:41:05 +0000446 }
limpbizkit163c48a2008-06-16 02:58:08 +0000447
sberlinb2f17602010-11-19 02:33:32 +0000448 return new ConvertedConstantBindingImpl<T>(this, key, converted, stringBinding,
449 typeConverterBinding);
limpbizkit06898062008-11-02 05:14:55 +0000450 } catch (ErrorsException e) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000451 throw e;
limpbizkit516e2ab2009-03-26 22:01:18 +0000452 } catch (RuntimeException e) {
sberlinb2f17602010-11-19 02:33:32 +0000453 throw errors.conversionError(stringValue, source, type, typeConverterBinding, e)
limpbizkitc5c488e2008-06-16 01:42:25 +0000454 .toException();
crazyboblee712705c2007-09-07 03:20:30 +0000455 }
456 }
457
limpbizkit76c24b12008-12-25 04:32:41 +0000458 private static class ConvertedConstantBindingImpl<T>
459 extends BindingImpl<T> implements ConvertedConstantBinding<T> {
crazyboblee712705c2007-09-07 03:20:30 +0000460 final T value;
461 final Provider<T> provider;
462 final Binding<String> originalBinding;
sberlinb2f17602010-11-19 02:33:32 +0000463 final TypeConverterBinding typeConverterBinding;
crazyboblee712705c2007-09-07 03:20:30 +0000464
kevinb9n1601ae52008-06-03 22:21:04 +0000465 ConvertedConstantBindingImpl(
sberlinb2f17602010-11-19 02:33:32 +0000466 InjectorImpl injector, Key<T> key, T value, Binding<String> originalBinding,
467 TypeConverterBinding typeConverterBinding) {
limpbizkit5fb9d922008-10-14 23:35:56 +0000468 super(injector, key, originalBinding.getSource(),
limpbizkit76c24b12008-12-25 04:32:41 +0000469 new ConstantFactory<T>(Initializables.of(value)), Scoping.UNSCOPED);
crazyboblee712705c2007-09-07 03:20:30 +0000470 this.value = value;
kevinb9n1601ae52008-06-03 22:21:04 +0000471 provider = Providers.of(value);
crazyboblee712705c2007-09-07 03:20:30 +0000472 this.originalBinding = originalBinding;
sberlinb2f17602010-11-19 02:33:32 +0000473 this.typeConverterBinding = typeConverterBinding;
crazyboblee712705c2007-09-07 03:20:30 +0000474 }
475
kevinb9n1601ae52008-06-03 22:21:04 +0000476 @Override public Provider<T> getProvider() {
477 return provider;
crazyboblee712705c2007-09-07 03:20:30 +0000478 }
479
limpbizkit8996e802008-12-28 01:44:29 +0000480 public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
limpbizkit03b81a62009-03-18 05:34:39 +0000481 return visitor.visit(this);
limpbizkit76c24b12008-12-25 04:32:41 +0000482 }
483
484 public T getValue() {
485 return value;
486 }
487
sberlinb2f17602010-11-19 02:33:32 +0000488 public TypeConverterBinding getTypeConverterBinding() {
489 return typeConverterBinding;
490 }
491
limpbizkitc45600e2008-12-27 02:57:04 +0000492 public Key<String> getSourceKey() {
493 return originalBinding.getKey();
494 }
495
limpbizkit76c24b12008-12-25 04:32:41 +0000496 public Set<Dependency<?>> getDependencies() {
limpbizkitc45600e2008-12-27 02:57:04 +0000497 return ImmutableSet.<Dependency<?>>of(Dependency.get(getSourceKey()));
limpbizkit477f9f92008-07-28 07:05:14 +0000498 }
499
limpbizkit03b81a62009-03-18 05:34:39 +0000500 public void applyTo(Binder binder) {
501 throw new UnsupportedOperationException("This element represents a synthetic binding.");
502 }
503
kevinb9n1601ae52008-06-03 22:21:04 +0000504 @Override public String toString() {
sberlind9c913a2011-06-26 21:02:54 +0000505 return Objects.toStringHelper(ConvertedConstantBinding.class)
limpbizkit76c24b12008-12-25 04:32:41 +0000506 .add("key", getKey())
limpbizkitc45600e2008-12-27 02:57:04 +0000507 .add("sourceKey", getSourceKey())
limpbizkitc3f92842008-12-30 19:43:47 +0000508 .add("value", value)
crazyboblee712705c2007-09-07 03:20:30 +0000509 .toString();
510 }
Sam Berlind57f8ec2014-04-08 12:25:33 -0400511
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000512 @Override
513 public boolean equals(Object obj) {
514 if(obj instanceof ConvertedConstantBindingImpl) {
515 ConvertedConstantBindingImpl<?> o = (ConvertedConstantBindingImpl<?>)obj;
516 return getKey().equals(o.getKey())
517 && getScoping().equals(o.getScoping())
518 && Objects.equal(value, o.value);
519 } else {
520 return false;
521 }
522 }
Sam Berlind57f8ec2014-04-08 12:25:33 -0400523
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000524 @Override
525 public int hashCode() {
526 return Objects.hashCode(getKey(), getScoping(), value);
527 }
crazyboblee712705c2007-09-07 03:20:30 +0000528 }
529
limpbizkit163c48a2008-06-16 02:58:08 +0000530 <T> void initializeBinding(BindingImpl<T> binding, Errors errors) throws ErrorsException {
sberlind5737a62011-05-02 18:03:35 +0000531 if (binding instanceof DelayedInitialize) {
532 ((DelayedInitialize) binding).initialize(this, errors);
limpbizkit91425c32009-07-17 03:10:13 +0000533 }
534 }
535
536 <T> void initializeJitBinding(BindingImpl<T> binding, Errors errors) throws ErrorsException {
kevinb9n1601ae52008-06-03 22:21:04 +0000537 // Put the partially constructed binding in the map a little early. This enables us to handle
538 // circular dependencies. Example: FooImpl -> BarImpl -> FooImpl.
Sam Berlind57f8ec2014-04-08 12:25:33 -0400539 // Note: We don't need to synchronize on state.lock() during injector creation.
sberlind5737a62011-05-02 18:03:35 +0000540 if (binding instanceof DelayedInitialize) {
limpbizkit51411872008-05-13 22:15:29 +0000541 Key<T> key = binding.getKey();
542 jitBindings.put(key, binding);
543 boolean successful = false;
sberlind5737a62011-05-02 18:03:35 +0000544 DelayedInitialize delayed = (DelayedInitialize)binding;
limpbizkit51411872008-05-13 22:15:29 +0000545 try {
sberlind5737a62011-05-02 18:03:35 +0000546 delayed.initialize(this, errors);
limpbizkit51411872008-05-13 22:15:29 +0000547 successful = true;
limpbizkit72d11dd2008-11-02 07:59:13 +0000548 } finally {
limpbizkit51411872008-05-13 22:15:29 +0000549 if (!successful) {
sberlin7df9cf32010-05-25 12:25:46 +0000550 // We do not pass cb.getInternalConstructor as the second parameter
551 // so that cached exceptions while constructing it get stored.
552 // See TypeListenerTest#testTypeListenerThrows
Sam Berlind51292d2012-02-26 21:23:19 -0500553 removeFailedJitBinding(binding, null);
sberlin7df9cf32010-05-25 12:25:46 +0000554 cleanup(binding, new HashSet<Key>());
limpbizkit51411872008-05-13 22:15:29 +0000555 }
556 }
557 }
558 }
Sam Berlind57f8ec2014-04-08 12:25:33 -0400559
sberlin7df9cf32010-05-25 12:25:46 +0000560 /**
561 * Iterates through the binding's dependencies to clean up any stray bindings that were leftover
562 * from a failed JIT binding. This is required because the bindings are eagerly &
563 * optimistically added to allow circular dependency support, so dependencies may pass where they
564 * should have failed.
565 */
566 private boolean cleanup(BindingImpl<?> binding, Set<Key> encountered) {
567 boolean bindingFailed = false;
568 Set<Dependency<?>> deps = getInternalDependencies(binding);
569 for(Dependency dep : deps) {
570 Key<?> depKey = dep.getKey();
571 InjectionPoint ip = dep.getInjectionPoint();
572 if(encountered.add(depKey)) { // only check if we haven't looked at this key yet
573 BindingImpl depBinding = jitBindings.get(depKey);
574 if(depBinding != null) { // if the binding still exists, validate
575 boolean failed = cleanup(depBinding, encountered); // if children fail, we fail
576 if(depBinding instanceof ConstructorBindingImpl) {
577 ConstructorBindingImpl ctorBinding = (ConstructorBindingImpl)depBinding;
578 ip = ctorBinding.getInternalConstructor();
579 if(!ctorBinding.isInitialized()) {
580 failed = true;
581 }
582 }
583 if(failed) {
Sam Berlind51292d2012-02-26 21:23:19 -0500584 removeFailedJitBinding(depBinding, ip);
sberlin7df9cf32010-05-25 12:25:46 +0000585 bindingFailed = true;
586 }
587 } else if(state.getExplicitBinding(depKey) == null) {
588 // ignore keys if they were explicitly bound, but if neither JIT
589 // nor explicit, it's also invalid & should let parent know.
590 bindingFailed = true;
591 }
592 }
593 }
594 return bindingFailed;
595 }
Sam Berlind57f8ec2014-04-08 12:25:33 -0400596
sberlin7df9cf32010-05-25 12:25:46 +0000597 /** Cleans up any state that may have been cached when constructing the JIT binding. */
Sam Berlind51292d2012-02-26 21:23:19 -0500598 private void removeFailedJitBinding(Binding<?> binding, InjectionPoint ip) {
599 failedJitBindings.add(binding.getKey());
600 jitBindings.remove(binding.getKey());
601 membersInjectorStore.remove(binding.getKey().getTypeLiteral());
602 provisionListenerStore.remove(binding);
sberlin7df9cf32010-05-25 12:25:46 +0000603 if(ip != null) {
604 constructors.remove(ip);
605 }
606 }
Sam Berlind57f8ec2014-04-08 12:25:33 -0400607
sberlin7df9cf32010-05-25 12:25:46 +0000608 /** Safely gets the dependencies of possibly not initialized bindings. */
609 @SuppressWarnings("unchecked")
610 private Set<Dependency<?>> getInternalDependencies(BindingImpl<?> binding) {
611 if(binding instanceof ConstructorBindingImpl) {
612 return ((ConstructorBindingImpl)binding).getInternalDependencies();
sberlin47e69ef2010-07-03 15:35:50 +0000613 } else if(binding instanceof HasDependencies) {
sberlin7df9cf32010-05-25 12:25:46 +0000614 return ((HasDependencies)binding).getDependencies();
sberlin47e69ef2010-07-03 15:35:50 +0000615 } else {
616 return ImmutableSet.of();
sberlin7df9cf32010-05-25 12:25:46 +0000617 }
618 }
limpbizkit51411872008-05-13 22:15:29 +0000619
620 /**
kevinb9n1601ae52008-06-03 22:21:04 +0000621 * Creates a binding for an injectable type with the given scope. Looks for a scope on the type if
622 * none is specified.
limpbizkit51411872008-05-13 22:15:29 +0000623 */
limpbizkitf3740142009-06-22 00:14:02 +0000624 <T> BindingImpl<T> createUninitializedBinding(Key<T> key, Scoping scoping, Object source,
sberlin888a2642010-02-11 22:07:07 +0000625 Errors errors, boolean jitBinding) throws ErrorsException {
limpbizkit4272aef2008-11-23 08:10:09 +0000626 Class<?> rawType = key.getTypeLiteral().getRawType();
limpbizkit8ba97882008-11-04 02:52:54 +0000627
Sam Berlin12857902014-08-06 11:54:29 -0400628 ImplementedBy implementedBy = rawType.getAnnotation(ImplementedBy.class);
629
630 // Don't try to inject arrays or enums annotated with @ImplementedBy.
631 if (rawType.isArray() || (rawType.isEnum() && implementedBy != null)) {
limpbizkit06898062008-11-02 05:14:55 +0000632 throw errors.missingImplementation(key).toException();
crazyboblee712705c2007-09-07 03:20:30 +0000633 }
634
limpbizkitb0f3c9b2008-11-15 09:19:28 +0000635 // Handle TypeLiteral<T> by binding the inner type
636 if (rawType == TypeLiteral.class) {
637 @SuppressWarnings("unchecked") // we have to fudge the inner type as Object
638 BindingImpl<T> binding = (BindingImpl<T>) createTypeLiteralBinding(
639 (Key<TypeLiteral<Object>>) key, errors);
640 return binding;
641 }
642
crazyboblee712705c2007-09-07 03:20:30 +0000643 // Handle @ImplementedBy
crazyboblee712705c2007-09-07 03:20:30 +0000644 if (implementedBy != null) {
limpbizkit8ba97882008-11-04 02:52:54 +0000645 Annotations.checkForMisplacedScopeAnnotations(rawType, source, errors);
limpbizkit76c24b12008-12-25 04:32:41 +0000646 return createImplementedByBinding(key, scoping, implementedBy, errors);
crazyboblee712705c2007-09-07 03:20:30 +0000647 }
648
649 // Handle @ProvidedBy.
limpbizkit8ba97882008-11-04 02:52:54 +0000650 ProvidedBy providedBy = rawType.getAnnotation(ProvidedBy.class);
crazyboblee712705c2007-09-07 03:20:30 +0000651 if (providedBy != null) {
limpbizkit8ba97882008-11-04 02:52:54 +0000652 Annotations.checkForMisplacedScopeAnnotations(rawType, source, errors);
limpbizkit76c24b12008-12-25 04:32:41 +0000653 return createProvidedByBinding(key, scoping, providedBy, errors);
crazyboblee712705c2007-09-07 03:20:30 +0000654 }
655
Sam Berlind57f8ec2014-04-08 12:25:33 -0400656
Sam Berlinc7567772012-05-31 19:54:04 -0400657 return ConstructorBindingImpl.create(this,
658 key,
659 null, /* use default constructor */
660 source,
661 scoping,
662 errors,
663 jitBinding && options.jitDisabled,
664 options.atInjectRequired);
crazyboblee712705c2007-09-07 03:20:30 +0000665 }
666
limpbizkitb0f3c9b2008-11-15 09:19:28 +0000667 /**
668 * Converts a binding for a {@code Key<TypeLiteral<T>>} to the value {@code TypeLiteral<T>}. It's
669 * a bit awkward because we have to pull out the inner type in the type literal.
670 */
671 private <T> BindingImpl<TypeLiteral<T>> createTypeLiteralBinding(
672 Key<TypeLiteral<T>> key, Errors errors) throws ErrorsException {
673 Type typeLiteralType = key.getTypeLiteral().getType();
674 if (!(typeLiteralType instanceof ParameterizedType)) {
675 throw errors.cannotInjectRawTypeLiteral().toException();
676 }
677
678 ParameterizedType parameterizedType = (ParameterizedType) typeLiteralType;
679 Type innerType = parameterizedType.getActualTypeArguments()[0];
680
681 // this is unforunate. We don't support building TypeLiterals for type variable like 'T'. If
682 // this proves problematic, we can probably fix TypeLiteral to support type variables
683 if (!(innerType instanceof Class)
684 && !(innerType instanceof GenericArrayType)
685 && !(innerType instanceof ParameterizedType)) {
686 throw errors.cannotInjectTypeLiteralOf(innerType).toException();
687 }
688
689 @SuppressWarnings("unchecked") // by definition, innerType == T, so this is safe
690 TypeLiteral<T> value = (TypeLiteral<T>) TypeLiteral.get(innerType);
691 InternalFactory<TypeLiteral<T>> factory = new ConstantFactory<TypeLiteral<T>>(
692 Initializables.of(value));
693 return new InstanceBindingImpl<TypeLiteral<T>>(this, key, SourceProvider.UNKNOWN_SOURCE,
694 factory, ImmutableSet.<InjectionPoint>of(), value);
695 }
696
kevinb9n1601ae52008-06-03 22:21:04 +0000697 /** Creates a binding for a type annotated with @ProvidedBy. */
limpbizkit76c24b12008-12-25 04:32:41 +0000698 <T> BindingImpl<T> createProvidedByBinding(Key<T> key, Scoping scoping,
699 ProvidedBy providedBy, Errors errors) throws ErrorsException {
sberlind5737a62011-05-02 18:03:35 +0000700 Class<?> rawType = key.getTypeLiteral().getRawType();
701 Class<? extends Provider<?>> providerType = providedBy.value();
crazyboblee712705c2007-09-07 03:20:30 +0000702
703 // Make sure it's not the same type. TODO: Can we check for deeper loops?
limpbizkit8ba97882008-11-04 02:52:54 +0000704 if (providerType == rawType) {
limpbizkit9dc32d42008-06-15 11:29:10 +0000705 throw errors.recursiveProviderType().toException();
crazyboblee712705c2007-09-07 03:20:30 +0000706 }
707
kevinb9n1601ae52008-06-03 22:21:04 +0000708 // Assume the provider provides an appropriate type. We double check at runtime.
crazyboblee712705c2007-09-07 03:20:30 +0000709 @SuppressWarnings("unchecked")
sberlind5737a62011-05-02 18:03:35 +0000710 Key<? extends Provider<T>> providerKey = (Key<? extends Provider<T>>) Key.get(providerType);
711 ProvidedByInternalFactory<T> internalFactory =
712 new ProvidedByInternalFactory<T>(rawType, providerType,
Sam Berlind51292d2012-02-26 21:23:19 -0500713 providerKey, !options.disableCircularProxies);
limpbizkit0cb8b862009-08-10 23:57:56 +0000714 Object source = rawType;
Sam Berlind51292d2012-02-26 21:23:19 -0500715 BindingImpl<T> binding = LinkedProviderBindingImpl.createWithInitializer(
kevinb9n1601ae52008-06-03 22:21:04 +0000716 this,
limpbizkit27fc50d2008-08-08 07:43:39 +0000717 key,
limpbizkit0cb8b862009-08-10 23:57:56 +0000718 source,
719 Scoping.<T>scope(key, this, internalFactory, source, scoping),
limpbizkit76c24b12008-12-25 04:32:41 +0000720 scoping,
sberlind5737a62011-05-02 18:03:35 +0000721 providerKey,
722 internalFactory);
Sam Berlind51292d2012-02-26 21:23:19 -0500723 internalFactory.setProvisionListenerCallback(provisionListenerStore.get(binding));
724 return binding;
crazyboblee712705c2007-09-07 03:20:30 +0000725 }
726
kevinb9n1601ae52008-06-03 22:21:04 +0000727 /** Creates a binding for a type annotated with @ImplementedBy. */
limpbizkit5ae41eb2009-06-06 17:51:27 +0000728 private <T> BindingImpl<T> createImplementedByBinding(Key<T> key, Scoping scoping,
limpbizkit76c24b12008-12-25 04:32:41 +0000729 ImplementedBy implementedBy, Errors errors)
limpbizkit163c48a2008-06-16 02:58:08 +0000730 throws ErrorsException {
limpbizkit4272aef2008-11-23 08:10:09 +0000731 Class<?> rawType = key.getTypeLiteral().getRawType();
crazyboblee712705c2007-09-07 03:20:30 +0000732 Class<?> implementationType = implementedBy.value();
733
734 // Make sure it's not the same type. TODO: Can we check for deeper cycles?
limpbizkit8ba97882008-11-04 02:52:54 +0000735 if (implementationType == rawType) {
limpbizkit9dc32d42008-06-15 11:29:10 +0000736 throw errors.recursiveImplementationType().toException();
crazyboblee712705c2007-09-07 03:20:30 +0000737 }
738
739 // Make sure implementationType extends type.
limpbizkit8ba97882008-11-04 02:52:54 +0000740 if (!rawType.isAssignableFrom(implementationType)) {
741 throw errors.notASubtype(implementationType, rawType).toException();
crazyboblee712705c2007-09-07 03:20:30 +0000742 }
743
limpbizkit06898062008-11-02 05:14:55 +0000744 @SuppressWarnings("unchecked") // After the preceding check, this cast is safe.
crazyboblee712705c2007-09-07 03:20:30 +0000745 Class<? extends T> subclass = (Class<? extends T>) implementationType;
746
747 // Look up the target binding.
limpbizkit06898062008-11-02 05:14:55 +0000748 final Key<? extends T> targetKey = Key.get(subclass);
sberlin888a2642010-02-11 22:07:07 +0000749 final BindingImpl<? extends T> targetBinding = getBindingOrThrow(targetKey, errors, JitLimitation.NEW_OR_EXISTING_JIT);
crazyboblee712705c2007-09-07 03:20:30 +0000750
751 InternalFactory<T> internalFactory = new InternalFactory<T>() {
sberlin888a2642010-02-11 22:07:07 +0000752 public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
limpbizkit163c48a2008-06-16 02:58:08 +0000753 throws ErrorsException {
sberlinba75f352011-06-12 21:54:43 +0000754 context.pushState(targetKey, targetBinding.getSource());
755 try {
756 return targetBinding.getInternalFactory().get(
757 errors.withSource(targetKey), context, dependency, true);
758 } finally {
759 context.popState();
760 }
crazyboblee712705c2007-09-07 03:20:30 +0000761 }
762 };
763
limpbizkit0cb8b862009-08-10 23:57:56 +0000764 Object source = rawType;
kevinb9n1601ae52008-06-03 22:21:04 +0000765 return new LinkedBindingImpl<T>(
766 this,
limpbizkit27fc50d2008-08-08 07:43:39 +0000767 key,
limpbizkit0cb8b862009-08-10 23:57:56 +0000768 source,
769 Scoping.<T>scope(key, this, internalFactory, source, scoping),
limpbizkit76c24b12008-12-25 04:32:41 +0000770 scoping,
771 targetKey);
crazyboblee712705c2007-09-07 03:20:30 +0000772 }
773
limpbizkit9dc32d42008-06-15 11:29:10 +0000774 /**
limpbizkit79dc99b2008-12-09 19:02:12 +0000775 * Attempts to create a just-in-time binding for {@code key} in the root injector, falling back to
776 * other ancestor injectors until this injector is tried.
777 */
sberlin9cdfe3a2011-03-02 13:53:17 +0000778 private <T> BindingImpl<T> createJustInTimeBindingRecursive(Key<T> key, Errors errors,
779 boolean jitDisabled, JitLimitation jitType) throws ErrorsException {
limpbizkit79dc99b2008-12-09 19:02:12 +0000780 // ask the parent to create the JIT binding
sberlin9cdfe3a2011-03-02 13:53:17 +0000781 if (parent != null) {
Tavian Barnes1dd0a912014-12-19 22:38:50 -0500782 if (jitDisabled && jitType == JitLimitation.NEW_OR_EXISTING_JIT) {
783 throw errors.jitDisabledInParent(key).toException();
784 } else {
785 try {
786 return parent.createJustInTimeBindingRecursive(key, new Errors(), jitDisabled,
787 parent.options.jitDisabled ? JitLimitation.NO_JIT : jitType);
788 } catch (ErrorsException ignored) {
789 }
limpbizkit79dc99b2008-12-09 19:02:12 +0000790 }
791 }
792
Sam Berlind57f8ec2014-04-08 12:25:33 -0400793 // Retrieve the sources before checking for blacklisting to guard against sources becoming null
794 // due to a full GC happening after calling state.isBlacklisted and
795 // state.getSourcesForBlacklistedKey.
796 // TODO(user): Consolidate these two APIs.
797 Set<Object> sources = state.getSourcesForBlacklistedKey(key);
limpbizkit79dc99b2008-12-09 19:02:12 +0000798 if (state.isBlacklisted(key)) {
sberlincc17f142011-02-27 00:02:03 +0000799 throw errors.childBindingAlreadySet(key, sources).toException();
limpbizkit79dc99b2008-12-09 19:02:12 +0000800 }
801
sberlin9cdfe3a2011-03-02 13:53:17 +0000802 BindingImpl<T> binding = createJustInTimeBinding(key, errors, jitDisabled, jitType);
Sam Berlind57f8ec2014-04-08 12:25:33 -0400803 state.parent().blacklist(key, state, binding.getSource());
limpbizkit79dc99b2008-12-09 19:02:12 +0000804 jitBindings.put(key, binding);
805 return binding;
806 }
807
808 /**
limpbizkit5fb9d922008-10-14 23:35:56 +0000809 * Returns a new just-in-time binding created by resolving {@code key}. The strategies used to
810 * create just-in-time bindings are:
811 * <ol>
812 * <li>Internalizing Providers. If the requested binding is for {@code Provider<T>}, we delegate
813 * to the binding for {@code T}.
814 * <li>Converting constants.
815 * <li>ImplementedBy and ProvidedBy annotations. Only for unannotated keys.
816 * <li>The constructor of the raw type. Only for unannotated keys.
817 * </ol>
limpbizkit9dc32d42008-06-15 11:29:10 +0000818 *
limpbizkit163c48a2008-06-16 02:58:08 +0000819 * @throws com.google.inject.internal.ErrorsException if the binding cannot be created.
limpbizkit9dc32d42008-06-15 11:29:10 +0000820 */
sberlin9cdfe3a2011-03-02 13:53:17 +0000821 private <T> BindingImpl<T> createJustInTimeBinding(Key<T> key, Errors errors,
822 boolean jitDisabled, JitLimitation jitType) throws ErrorsException {
limpbizkitb92f5402009-06-03 16:50:27 +0000823 int numErrorsBefore = errors.size();
824
Sam Berlind57f8ec2014-04-08 12:25:33 -0400825 // Retrieve the sources before checking for blacklisting to guard against sources becoming null
826 // due to a full GC happening after calling state.isBlacklisted and
827 // state.getSourcesForBlacklistedKey.
828 // TODO(user): Consolidate these two APIs.
829 Set<Object> sources = state.getSourcesForBlacklistedKey(key);
limpbizkit5fb9d922008-10-14 23:35:56 +0000830 if (state.isBlacklisted(key)) {
sberlincc17f142011-02-27 00:02:03 +0000831 throw errors.childBindingAlreadySet(key, sources).toException();
limpbizkit5fb9d922008-10-14 23:35:56 +0000832 }
833
crazyboblee712705c2007-09-07 03:20:30 +0000834 // Handle cases where T is a Provider<?>.
835 if (isProvider(key)) {
kevinb9n1601ae52008-06-03 22:21:04 +0000836 // These casts are safe. We know T extends Provider<X> and that given Key<Provider<X>>,
837 // createProviderBinding() will return BindingImpl<Provider<X>>.
Sam Berlinc7567772012-05-31 19:54:04 -0400838 @SuppressWarnings({"unchecked", "cast"})
limpbizkit5ae41eb2009-06-06 17:51:27 +0000839 BindingImpl<T> binding = (BindingImpl<T>) createProviderBinding((Key) key, errors);
crazyboblee5d575692007-09-07 17:42:28 +0000840 return binding;
crazyboblee712705c2007-09-07 03:20:30 +0000841 }
842
limpbizkit0ca7f912009-03-28 19:11:40 +0000843 // Handle cases where T is a MembersInjector<?>
844 if (isMembersInjector(key)) {
845 // These casts are safe. T extends MembersInjector<X> and that given Key<MembersInjector<X>>,
846 // createMembersInjectorBinding() will return BindingImpl<MembersInjector<X>>.
Sam Berlinc7567772012-05-31 19:54:04 -0400847 @SuppressWarnings({"unchecked", "cast"})
limpbizkit5ae41eb2009-06-06 17:51:27 +0000848 BindingImpl<T> binding = (BindingImpl<T>) createMembersInjectorBinding((Key) key, errors);
limpbizkit0ca7f912009-03-28 19:11:40 +0000849 return binding;
850 }
851
crazyboblee712705c2007-09-07 03:20:30 +0000852 // Try to convert a constant string binding to the requested type.
limpbizkit9dc32d42008-06-15 11:29:10 +0000853 BindingImpl<T> convertedBinding = convertConstantStringBinding(key, errors);
crazyboblee712705c2007-09-07 03:20:30 +0000854 if (convertedBinding != null) {
855 return convertedBinding;
856 }
Christian Edward Gruber9e2d95b2013-06-26 17:43:11 -0700857
Sam Berlind57f8ec2014-04-08 12:25:33 -0400858 if (!isTypeLiteral(key)
sberlin9cdfe3a2011-03-02 13:53:17 +0000859 && jitDisabled
860 && jitType != JitLimitation.NEW_OR_EXISTING_JIT) {
861 throw errors.jitDisabled(key).toException();
862 }
crazyboblee712705c2007-09-07 03:20:30 +0000863
864 // If the key has an annotation...
limpbizkit5ae41eb2009-06-06 17:51:27 +0000865 if (key.getAnnotationType() != null) {
crazyboblee712705c2007-09-07 03:20:30 +0000866 // Look for a binding without annotation attributes or return null.
Christian Edward Grubere3915852013-05-16 11:00:54 -0700867 if (key.hasAttributes() && !options.exactBindingAnnotationsRequired) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000868 try {
limpbizkit2c2c6102008-06-20 13:34:36 +0000869 Errors ignored = new Errors();
sberlin888a2642010-02-11 22:07:07 +0000870 return getBindingOrThrow(key.withoutAttributes(), ignored, JitLimitation.NO_JIT);
limpbizkit2c2c6102008-06-20 13:34:36 +0000871 } catch (ErrorsException ignored) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000872 // throw with a more appropriate message below
873 }
874 }
limpbizkit9dc32d42008-06-15 11:29:10 +0000875 throw errors.missingImplementation(key).toException();
crazyboblee712705c2007-09-07 03:20:30 +0000876 }
877
limpbizkit4272aef2008-11-23 08:10:09 +0000878 Object source = key.getTypeLiteral().getRawType();
sberlin888a2642010-02-11 22:07:07 +0000879 BindingImpl<T> binding = createUninitializedBinding(key, Scoping.UNSCOPED, source, errors, true);
limpbizkitb92f5402009-06-03 16:50:27 +0000880 errors.throwIfNewErrors(numErrorsBefore);
limpbizkit91425c32009-07-17 03:10:13 +0000881 initializeJitBinding(binding, errors);
limpbizkit5fb9d922008-10-14 23:35:56 +0000882 return binding;
crazyboblee712705c2007-09-07 03:20:30 +0000883 }
884
sberlin888a2642010-02-11 22:07:07 +0000885 <T> InternalFactory<? extends T> getInternalFactory(Key<T> key, Errors errors, JitLimitation jitType)
limpbizkit163c48a2008-06-16 02:58:08 +0000886 throws ErrorsException {
sberlin888a2642010-02-11 22:07:07 +0000887 return getBindingOrThrow(key, errors, jitType).getInternalFactory();
crazyboblee712705c2007-09-07 03:20:30 +0000888 }
889
crazybobleea6e73982007-02-02 00:21:07 +0000890 public Map<Key<?>, Binding<?>> getBindings() {
limpbizkit5fb9d922008-10-14 23:35:56 +0000891 return state.getExplicitBindingsThisLevel();
crazybobleea6e73982007-02-02 00:21:07 +0000892 }
893
limpbizkit37387e22009-07-04 16:20:55 +0000894 public Map<Key<?>, Binding<?>> getAllBindings() {
895 synchronized (state.lock()) {
896 return new ImmutableMap.Builder<Key<?>, Binding<?>>()
897 .putAll(state.getExplicitBindingsThisLevel())
898 .putAll(jitBindings)
899 .build();
900 }
901 }
902
limpbizkit19203222009-07-24 00:48:12 +0000903 public Map<Class<? extends Annotation>, Scope> getScopeBindings() {
sberlinb2f17602010-11-19 02:33:32 +0000904 return ImmutableMap.copyOf(state.getScopes());
905 }
906
907 public Set<TypeConverterBinding> getTypeConverterBindings() {
908 return ImmutableSet.copyOf(state.getConvertersThisLevel());
limpbizkit19203222009-07-24 00:48:12 +0000909 }
910
kevinb9n48d13072007-02-12 18:21:26 +0000911 private static class BindingsMultimap {
limpbizkit53664a72009-02-21 00:25:27 +0000912 final Map<TypeLiteral<?>, List<Binding<?>>> multimap = Maps.newHashMap();
kevinb9n48d13072007-02-12 18:21:26 +0000913
limpbizkit5fb9d922008-10-14 23:35:56 +0000914 <T> void put(TypeLiteral<T> type, Binding<T> binding) {
limpbizkit53664a72009-02-21 00:25:27 +0000915 List<Binding<?>> bindingsForType = multimap.get(type);
916 if (bindingsForType == null) {
917 bindingsForType = Lists.newArrayList();
918 multimap.put(type, bindingsForType);
919 }
920 bindingsForType.add(binding);
kevinb9n48d13072007-02-12 18:21:26 +0000921 }
922
limpbizkit76c24b12008-12-25 04:32:41 +0000923
924 @SuppressWarnings("unchecked") // safe because we only put matching entries into the map
kevinb9n1601ae52008-06-03 22:21:04 +0000925 <T> List<Binding<T>> getAll(TypeLiteral<T> type) {
limpbizkit53664a72009-02-21 00:25:27 +0000926 List<Binding<?>> bindings = multimap.get(type);
927 return bindings != null
Sam Berlind57f8ec2014-04-08 12:25:33 -0400928 ? Collections.<Binding<T>>unmodifiableList((List) multimap.get(type))
limpbizkit53664a72009-02-21 00:25:27 +0000929 : ImmutableList.<Binding<T>>of();
kevinb9n48d13072007-02-12 18:21:26 +0000930 }
931 }
932
crazyboblee66b415a2006-08-25 02:01:19 +0000933 /**
limpbizkita6e0e782008-09-03 06:19:56 +0000934 * Returns parameter injectors, or {@code null} if there are no parameters.
crazyboblee66b415a2006-08-25 02:01:19 +0000935 */
limpbizkite89c49e2009-05-06 01:02:14 +0000936 SingleParameterInjector<?>[] getParametersInjectors(
limpbizkit06898062008-11-02 05:14:55 +0000937 List<Dependency<?>> parameters, Errors errors) throws ErrorsException {
limpbizkita6e0e782008-09-03 06:19:56 +0000938 if (parameters.isEmpty()) {
939 return null;
limpbizkit185d2a22008-06-16 07:22:47 +0000940 }
941
limpbizkit72d11dd2008-11-02 07:59:13 +0000942 int numErrorsBefore = errors.size();
limpbizkit06898062008-11-02 05:14:55 +0000943 SingleParameterInjector<?>[] result = new SingleParameterInjector<?>[parameters.size()];
944 int i = 0;
limpbizkita98bc7a2008-08-29 16:52:44 +0000945 for (Dependency<?> parameter : parameters) {
limpbizkit9dc32d42008-06-15 11:29:10 +0000946 try {
limpbizkit06898062008-11-02 05:14:55 +0000947 result[i++] = createParameterInjector(parameter, errors.withSource(parameter));
limpbizkit163c48a2008-06-16 02:58:08 +0000948 } catch (ErrorsException rethrownBelow) {
limpbizkita6e0e782008-09-03 06:19:56 +0000949 // rethrown below
limpbizkit9dc32d42008-06-15 11:29:10 +0000950 }
crazyboblee66b415a2006-08-25 02:01:19 +0000951 }
limpbizkit9dc32d42008-06-15 11:29:10 +0000952
limpbizkit72d11dd2008-11-02 07:59:13 +0000953 errors.throwIfNewErrors(numErrorsBefore);
limpbizkite89c49e2009-05-06 01:02:14 +0000954 return result;
crazyboblee66b415a2006-08-25 02:01:19 +0000955 }
956
limpbizkita98bc7a2008-08-29 16:52:44 +0000957 <T> SingleParameterInjector<T> createParameterInjector(final Dependency<T> dependency,
limpbizkita6e0e782008-09-03 06:19:56 +0000958 final Errors errors) throws ErrorsException {
sberlinba75f352011-06-12 21:54:43 +0000959 BindingImpl<? extends T> binding = getBindingOrThrow(dependency.getKey(), errors, JitLimitation.NO_JIT);
960 return new SingleParameterInjector<T>(dependency, binding);
crazyboblee66b415a2006-08-25 02:01:19 +0000961 }
962
kevinb9n1601ae52008-06-03 22:21:04 +0000963 /** Invokes a method. */
crazyboblee0b3189c2007-02-24 00:14:51 +0000964 interface MethodInvoker {
kevinb9n1601ae52008-06-03 22:21:04 +0000965 Object invoke(Object target, Object... parameters)
966 throws IllegalAccessException, InvocationTargetException;
crazyboblee0b3189c2007-02-24 00:14:51 +0000967 }
968
limpbizkitb3a8f0b2008-09-05 22:30:40 +0000969 /** Cached constructor injectors for each type */
limpbizkita843a952009-04-08 22:24:55 +0000970 final ConstructorInjectorStore constructors = new ConstructorInjectorStore(this);
limpbizkit7cef5b02009-03-29 21:16:51 +0000971
972 /** Cached field and method injectors for each type. */
973 MembersInjectorStore membersInjectorStore;
Sam Berlind57f8ec2014-04-08 12:25:33 -0400974
sberlin132a5db2011-06-05 18:32:05 +0000975 /** Cached provision listener callbacks for each key. */
976 ProvisionListenerCallbackStore provisionListenerStore;
crazyboblee66b415a2006-08-25 02:01:19 +0000977
limpbizkit97eac0f2009-03-28 18:25:35 +0000978 @SuppressWarnings("unchecked") // the members injector type is consistent with instance's type
979 public void injectMembers(Object instance) {
980 MembersInjector membersInjector = getMembersInjector(instance.getClass());
981 membersInjector.injectMembers(instance);
limpbizkit9dc32d42008-06-15 11:29:10 +0000982 }
983
limpbizkit03b81a62009-03-18 05:34:39 +0000984 public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
limpbizkit97eac0f2009-03-28 18:25:35 +0000985 Errors errors = new Errors(typeLiteral);
986 try {
limpbizkit7cef5b02009-03-29 21:16:51 +0000987 return membersInjectorStore.get(typeLiteral, errors);
limpbizkit97eac0f2009-03-28 18:25:35 +0000988 } catch (ErrorsException e) {
989 throw new ConfigurationException(errors.merge(e.getErrors()).getMessages());
990 }
limpbizkit03b81a62009-03-18 05:34:39 +0000991 }
992
993 public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
limpbizkit97eac0f2009-03-28 18:25:35 +0000994 return getMembersInjector(TypeLiteral.get(type));
limpbizkit03b81a62009-03-18 05:34:39 +0000995 }
996
crazybobleebd9544e2007-02-25 20:32:11 +0000997 public <T> Provider<T> getProvider(Class<T> type) {
998 return getProvider(Key.get(type));
crazybobleee5fbbb02007-02-05 07:00:27 +0000999 }
1000
limpbizkitb3a8f0b2008-09-05 22:30:40 +00001001 <T> Provider<T> getProviderOrThrow(final Key<T> key, Errors errors) throws ErrorsException {
sberlinba75f352011-06-12 21:54:43 +00001002 final BindingImpl<? extends T> binding = getBindingOrThrow(key, errors, JitLimitation.NO_JIT);
limpbizkit06898062008-11-02 05:14:55 +00001003 final Dependency<T> dependency = Dependency.get(key);
crazyboblee66b415a2006-08-25 02:01:19 +00001004
crazybobleebd9544e2007-02-25 20:32:11 +00001005 return new Provider<T>() {
crazyboblee63b592b2007-01-25 02:45:24 +00001006 public T get() {
limpbizkit06898062008-11-02 05:14:55 +00001007 final Errors errors = new Errors(dependency);
limpbizkit9dc32d42008-06-15 11:29:10 +00001008 try {
1009 T t = callInContext(new ContextualCallable<T>() {
limpbizkit163c48a2008-06-16 02:58:08 +00001010 public T call(InternalContext context) throws ErrorsException {
sberlinba75f352011-06-12 21:54:43 +00001011 Dependency previous = context.pushDependency(dependency, binding.getSource());
limpbizkit9dc32d42008-06-15 11:29:10 +00001012 try {
sberlinba75f352011-06-12 21:54:43 +00001013 return binding.getInternalFactory().get(errors, context, dependency, false);
limpbizkit490833f2008-11-02 00:12:39 +00001014 } finally {
sberlinba75f352011-06-12 21:54:43 +00001015 context.popStateAndSetDependency(previous);
limpbizkit9dc32d42008-06-15 11:29:10 +00001016 }
limpbizkitfcf2b8c2007-10-21 18:23:43 +00001017 }
limpbizkit9dc32d42008-06-15 11:29:10 +00001018 });
limpbizkit72d11dd2008-11-02 07:59:13 +00001019 errors.throwIfNewErrors(0);
limpbizkit9dc32d42008-06-15 11:29:10 +00001020 return t;
limpbizkit163c48a2008-06-16 02:58:08 +00001021 } catch (ErrorsException e) {
limpbizkit490833f2008-11-02 00:12:39 +00001022 throw new ProvisionException(errors.merge(e.getErrors()).getMessages());
limpbizkit9dc32d42008-06-15 11:29:10 +00001023 }
crazyboblee66b415a2006-08-25 02:01:19 +00001024 }
crazybobleed7908e82007-02-16 01:04:53 +00001025
limpbizkit9dc32d42008-06-15 11:29:10 +00001026 @Override public String toString() {
sberlinba75f352011-06-12 21:54:43 +00001027 return binding.getInternalFactory().toString();
crazybobleed7908e82007-02-16 01:04:53 +00001028 }
crazyboblee63b592b2007-01-25 02:45:24 +00001029 };
crazyboblee66b415a2006-08-25 02:01:19 +00001030 }
1031
crazyboblee712705c2007-09-07 03:20:30 +00001032 public <T> Provider<T> getProvider(final Key<T> key) {
limpbizkit06898062008-11-02 05:14:55 +00001033 Errors errors = new Errors(key);
limpbizkit3b1cd582008-04-28 00:06:01 +00001034 try {
limpbizkit9dc32d42008-06-15 11:29:10 +00001035 Provider<T> result = getProviderOrThrow(key, errors);
limpbizkit72d11dd2008-11-02 07:59:13 +00001036 errors.throwIfNewErrors(0);
limpbizkit9dc32d42008-06-15 11:29:10 +00001037 return result;
limpbizkit490833f2008-11-02 00:12:39 +00001038 } catch (ErrorsException e) {
1039 throw new ConfigurationException(errors.merge(e.getErrors()).getMessages());
crazyboblee712705c2007-09-07 03:20:30 +00001040 }
crazyboblee712705c2007-09-07 03:20:30 +00001041 }
1042
kevinb9n27f8a582007-02-28 22:54:06 +00001043 public <T> T getInstance(Key<T> key) {
1044 return getProvider(key).get();
1045 }
1046
1047 public <T> T getInstance(Class<T> type) {
1048 return getProvider(type).get();
1049 }
1050
Sam Berlinca81e592014-07-01 16:52:59 -04001051 private final ThreadLocal<Object[]> localContext;
crazyboblee66b415a2006-08-25 02:01:19 +00001052
kevinb9n1601ae52008-06-03 22:21:04 +00001053 /** Looks up thread local context. Creates (and removes) a new context if necessary. */
limpbizkit163c48a2008-06-16 02:58:08 +00001054 <T> T callInContext(ContextualCallable<T> callable) throws ErrorsException {
limpbizkit833265f2009-05-06 18:14:32 +00001055 Object[] reference = localContext.get();
Sam Berlinca81e592014-07-01 16:52:59 -04001056 if (reference == null) {
1057 reference = new Object[1];
1058 localContext.set(reference);
1059 }
limpbizkit833265f2009-05-06 18:14:32 +00001060 if (reference[0] == null) {
1061 reference[0] = new InternalContext();
1062 try {
1063 return callable.call((InternalContext)reference[0]);
1064 } finally {
1065 // Only clear the context if this call created it.
1066 reference[0] = null;
1067 }
1068 } else {
1069 // Someone else will clean up this context.
1070 return callable.call((InternalContext)reference[0]);
crazyboblee66b415a2006-08-25 02:01:19 +00001071 }
1072 }
1073
guice.mirrorbot@gmail.comefa4e9f2011-09-13 17:41:32 +00001074 @Override
crazybobleee3adfd62007-02-02 21:30:08 +00001075 public String toString() {
sberlind9c913a2011-06-26 21:02:54 +00001076 return Objects.toStringHelper(Injector.class)
limpbizkitc3f92842008-12-30 19:43:47 +00001077 .add("bindings", state.getExplicitBindingsThisLevel().values())
crazybobleee3adfd62007-02-02 21:30:08 +00001078 .toString();
1079 }
crazyboblee66b415a2006-08-25 02:01:19 +00001080}