blob: a26b28c4f1bfd598a651e1d9fc7912ae35ec87cd [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
limpbizkitb3a8f0b2008-09-05 22:30:40 +000019import com.google.inject.internal.Annotations;
limpbizkit76c24b12008-12-25 04:32:41 +000020import static com.google.inject.internal.Annotations.findScopeAnnotation;
21import com.google.inject.internal.BindingImpl;
kevinb9n1601ae52008-06-03 22:21:04 +000022import com.google.inject.internal.Classes;
limpbizkit9dc32d42008-06-15 11:29:10 +000023import com.google.inject.internal.Errors;
limpbizkit163c48a2008-06-16 02:58:08 +000024import com.google.inject.internal.ErrorsException;
limpbizkit53664a72009-02-21 00:25:27 +000025import com.google.inject.internal.ImmutableList;
26import com.google.inject.internal.ImmutableSet;
limpbizkit76c24b12008-12-25 04:32:41 +000027import com.google.inject.internal.InstanceBindingImpl;
28import com.google.inject.internal.InternalContext;
29import com.google.inject.internal.InternalFactory;
30import com.google.inject.internal.LinkedBindingImpl;
31import com.google.inject.internal.LinkedProviderBindingImpl;
limpbizkit53664a72009-02-21 00:25:27 +000032import com.google.inject.internal.Lists;
33import com.google.inject.internal.Maps;
kevinb9n1601ae52008-06-03 22:21:04 +000034import com.google.inject.internal.MatcherAndConverter;
limpbizkit53664a72009-02-21 00:25:27 +000035import com.google.inject.internal.Nullable;
limpbizkit76c24b12008-12-25 04:32:41 +000036import com.google.inject.internal.Scoping;
limpbizkitb0f3c9b2008-11-15 09:19:28 +000037import com.google.inject.internal.SourceProvider;
kevinb9n1601ae52008-06-03 22:21:04 +000038import com.google.inject.internal.ToStringBuilder;
limpbizkitafa4b5d2008-08-02 18:40:47 +000039import com.google.inject.spi.BindingTargetVisitor;
limpbizkit76c24b12008-12-25 04:32:41 +000040import com.google.inject.spi.ConvertedConstantBinding;
limpbizkita98bc7a2008-08-29 16:52:44 +000041import com.google.inject.spi.Dependency;
limpbizkit9dc32d42008-06-15 11:29:10 +000042import com.google.inject.spi.InjectionPoint;
limpbizkit76c24b12008-12-25 04:32:41 +000043import com.google.inject.spi.ProviderBinding;
limpbizkitc3f92842008-12-30 19:43:47 +000044import com.google.inject.spi.ProviderKeyBinding;
crazyboblee712705c2007-09-07 03:20:30 +000045import com.google.inject.util.Providers;
kevinb9n1601ae52008-06-03 22:21:04 +000046import java.lang.annotation.Annotation;
limpbizkitb0f3c9b2008-11-15 09:19:28 +000047import java.lang.reflect.GenericArrayType;
kevinb9n1601ae52008-06-03 22:21:04 +000048import java.lang.reflect.InvocationTargetException;
kevinb9n1601ae52008-06-03 22:21:04 +000049import java.lang.reflect.Modifier;
50import java.lang.reflect.ParameterizedType;
51import java.lang.reflect.Type;
kevinb9n1601ae52008-06-03 22:21:04 +000052import java.util.Collections;
53import java.util.List;
54import java.util.Map;
limpbizkit3a8c1552008-11-16 21:43:01 +000055import java.util.Set;
crazyboblee66b415a2006-08-25 02:01:19 +000056
57/**
kevinb9na2915a92007-02-28 06:20:30 +000058 * Default {@link Injector} implementation.
crazyboblee66b415a2006-08-25 02:01:19 +000059 *
crazyboblee66b415a2006-08-25 02:01:19 +000060 * @author crazybob@google.com (Bob Lee)
limpbizkit3d58d6b2008-03-08 16:11:47 +000061 * @see InjectorBuilder
crazyboblee66b415a2006-08-25 02:01:19 +000062 */
limpbizkit8d620752009-03-31 22:37:26 +000063class InjectorImpl implements Injector, Lookups {
limpbizkit5fb9d922008-10-14 23:35:56 +000064 final State state;
65 final InjectorImpl parent;
limpbizkit3d58d6b2008-03-08 16:11:47 +000066 final BindingsMultimap bindingsMultimap = new BindingsMultimap();
limpbizkitfcbdf992008-11-26 02:37:35 +000067 final Initializer initializer;
crazyboblee4727ee22007-01-30 03:13:38 +000068
limpbizkit79dc99b2008-12-09 19:02:12 +000069 /** Just-in-time binding cache. Guarded by state.lock() */
70 final Map<Key<?>, BindingImpl<?>> jitBindings = Maps.newHashMap();
71
limpbizkit8d620752009-03-31 22:37:26 +000072 Lookups lookups = new DeferredLookups(this);
73
limpbizkitfcbdf992008-11-26 02:37:35 +000074 InjectorImpl(@Nullable InjectorImpl parent, State state, Initializer initializer) {
limpbizkit5fb9d922008-10-14 23:35:56 +000075 this.parent = parent;
limpbizkitfcbdf992008-11-26 02:37:35 +000076 this.state = state;
77 this.initializer = initializer;
limpbizkit5fb9d922008-10-14 23:35:56 +000078
79 if (parent != null) {
80 localContext = parent.localContext;
81 } else {
limpbizkit833265f2009-05-06 18:14:32 +000082 localContext = new ThreadLocal<Object[]>() {
83 protected Object[] initialValue() {
84 return new Object[1];
limpbizkit5fb9d922008-10-14 23:35:56 +000085 }
86 };
87 }
crazyboblee66b415a2006-08-25 02:01:19 +000088 }
89
kevinb9n1601ae52008-06-03 22:21:04 +000090 /** Indexes bindings by type. */
crazyboblee62fcdde2007-02-03 02:10:13 +000091 void index() {
limpbizkit5fb9d922008-10-14 23:35:56 +000092 for (Binding<?> binding : state.getExplicitBindingsThisLevel().values()) {
crazyboblee62fcdde2007-02-03 02:10:13 +000093 index(binding);
94 }
95 }
96
limpbizkit5fb9d922008-10-14 23:35:56 +000097 <T> void index(Binding<T> binding) {
crazybobleec3e88492007-02-25 22:36:58 +000098 bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
crazyboblee62fcdde2007-02-03 02:10:13 +000099 }
100
crazyboblee62fcdde2007-02-03 02:10:13 +0000101 public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
limpbizkit76c24b12008-12-25 04:32:41 +0000102 return bindingsMultimap.getAll(type);
crazyboblee62fcdde2007-02-03 02:10:13 +0000103 }
104
limpbizkit9dc32d42008-06-15 11:29:10 +0000105 /** Returns the binding for {@code key} */
limpbizkit3b1cd582008-04-28 00:06:01 +0000106 public <T> BindingImpl<T> getBinding(Key<T> key) {
limpbizkit06898062008-11-02 05:14:55 +0000107 Errors errors = new Errors(key);
limpbizkit3b1cd582008-04-28 00:06:01 +0000108 try {
limpbizkit9dc32d42008-06-15 11:29:10 +0000109 BindingImpl<T> result = getBindingOrThrow(key, errors);
limpbizkit06898062008-11-02 05:14:55 +0000110 errors.throwConfigurationExceptionIfErrorsExist();
limpbizkit9dc32d42008-06-15 11:29:10 +0000111 return result;
limpbizkit490833f2008-11-02 00:12:39 +0000112 } catch (ErrorsException e) {
113 throw new ConfigurationException(errors.merge(e.getErrors()).getMessages());
limpbizkit3b1cd582008-04-28 00:06:01 +0000114 }
115 }
116
117 /**
kevinb9n1601ae52008-06-03 22:21:04 +0000118 * Gets a binding implementation. First, it check to see if the parent has a binding. If the
119 * parent has a binding and the binding is scoped, it will use that binding. Otherwise, this
120 * checks for an explicit binding. If no explicit binding is found, it looks for a just-in-time
121 * binding.
crazyboblee712705c2007-09-07 03:20:30 +0000122 */
limpbizkit9dc32d42008-06-15 11:29:10 +0000123 public <T> BindingImpl<T> getBindingOrThrow(Key<T> key, Errors errors)
limpbizkit163c48a2008-06-16 02:58:08 +0000124 throws ErrorsException {
crazyboblee712705c2007-09-07 03:20:30 +0000125 // Check explicit bindings, i.e. bindings created by modules.
limpbizkit5fb9d922008-10-14 23:35:56 +0000126 BindingImpl<T> binding = state.getExplicitBinding(key);
crazybobleea6e73982007-02-02 00:21:07 +0000127 if (binding != null) {
crazyboblee712705c2007-09-07 03:20:30 +0000128 return binding;
crazyboblee07e41822006-11-21 01:27:08 +0000129 }
130
crazyboblee712705c2007-09-07 03:20:30 +0000131 // Look for an on-demand binding.
limpbizkit9dc32d42008-06-15 11:29:10 +0000132 return getJustInTimeBinding(key, errors);
crazyboblee712705c2007-09-07 03:20:30 +0000133 }
crazybobleef33d23e2007-02-12 04:17:48 +0000134
crazyboblee552472f2007-09-07 16:52:39 +0000135 public <T> Binding<T> getBinding(Class<T> type) {
136 return getBinding(Key.get(type));
137 }
138
limpbizkitedd8d642008-10-18 19:50:49 +0000139 public Injector getParent() {
140 return parent;
141 }
142
limpbizkit5fb9d922008-10-14 23:35:56 +0000143 public Injector createChildInjector(Iterable<? extends Module> modules) {
144 return new InjectorBuilder()
145 .parentInjector(this)
limpbizkit5fb9d922008-10-14 23:35:56 +0000146 .addModules(modules)
147 .build();
148 }
149
150 public Injector createChildInjector(Module... modules) {
151 return createChildInjector(ImmutableList.of(modules));
crazyboblee712705c2007-09-07 03:20:30 +0000152 }
153
limpbizkit9dc32d42008-06-15 11:29:10 +0000154 /**
155 * Returns a just-in-time binding for {@code key}, creating it if necessary.
156 *
limpbizkit79dc99b2008-12-09 19:02:12 +0000157 * @throws ErrorsException if the binding could not be created.
crazyboblee712705c2007-09-07 03:20:30 +0000158 */
limpbizkit5fb9d922008-10-14 23:35:56 +0000159 private <T> BindingImpl<T> getJustInTimeBinding(Key<T> key, Errors errors)
160 throws ErrorsException {
limpbizkita8dccb32008-11-11 22:41:56 +0000161 synchronized (state.lock()) {
limpbizkit79dc99b2008-12-09 19:02:12 +0000162 // first try to find a JIT binding that we've already created
163 for (InjectorImpl injector = this; injector != null; injector = injector.parent) {
164 @SuppressWarnings("unchecked") // we only store bindings that match their key
165 BindingImpl<T> binding = (BindingImpl<T>) injector.jitBindings.get(key);
166
167 if (binding != null) {
168 return binding;
limpbizkit5fb9d922008-10-14 23:35:56 +0000169 }
kevinb9n1601ae52008-06-03 22:21:04 +0000170 }
limpbizkit5fb9d922008-10-14 23:35:56 +0000171
limpbizkit79dc99b2008-12-09 19:02:12 +0000172 return createJustInTimeBindingRecursive(key, errors);
limpbizkitc808df02007-08-25 03:25:13 +0000173 }
crazyboblee07e41822006-11-21 01:27:08 +0000174 }
175
limpbizkit0ca7f912009-03-28 19:11:40 +0000176 /** Returns true if the key type is Provider (but not a subclass of Provider). */
crazyboblee712705c2007-09-07 03:20:30 +0000177 static boolean isProvider(Key<?> key) {
178 return key.getTypeLiteral().getRawType().equals(Provider.class);
179 }
180
limpbizkit0ca7f912009-03-28 19:11:40 +0000181 /** Returns true if the key type is MembersInjector (but not a subclass of MembersInjector). */
182 static boolean isMembersInjector(Key<?> key) {
183 return key.getTypeLiteral().getRawType().equals(MembersInjector.class)
184 && !key.hasAnnotationType();
185 }
186
187 private <T> BindingImpl<MembersInjector<T>> createMembersInjectorBinding(
188 Key<MembersInjector<T>> key, Errors errors) throws ErrorsException {
189 Type membersInjectorType = key.getTypeLiteral().getType();
190 if (!(membersInjectorType instanceof ParameterizedType)) {
191 throw errors.cannotInjectRawMembersInjector().toException();
192 }
193
194 @SuppressWarnings("unchecked") // safe because T came from Key<MembersInjector<T>>
195 TypeLiteral<T> instanceType = (TypeLiteral<T>) TypeLiteral.get(
196 ((ParameterizedType) membersInjectorType).getActualTypeArguments()[0]);
limpbizkit7cef5b02009-03-29 21:16:51 +0000197 MembersInjector<T> membersInjector = membersInjectorStore.get(instanceType, errors);
limpbizkit0ca7f912009-03-28 19:11:40 +0000198
199 InternalFactory<MembersInjector<T>> factory = new ConstantFactory<MembersInjector<T>>(
200 Initializables.of(membersInjector));
201
202
203 return new InstanceBindingImpl<MembersInjector<T>>(this, key, SourceProvider.UNKNOWN_SOURCE,
204 factory, ImmutableSet.<InjectionPoint>of(), membersInjector);
205 }
206
207 /**
208 * Creates a synthetic binding to {@code Provider<T>}, i.e. a binding to the provider from
209 * {@code Binding<T>}.
210 */
limpbizkit76c24b12008-12-25 04:32:41 +0000211 private <T> BindingImpl<Provider<T>> createProviderBinding(Key<Provider<T>> key, Errors errors)
212 throws ErrorsException {
crazyboblee712705c2007-09-07 03:20:30 +0000213 Type providerType = key.getTypeLiteral().getType();
214
215 // If the Provider has no type parameter (raw Provider)...
216 if (!(providerType instanceof ParameterizedType)) {
limpbizkit9dc32d42008-06-15 11:29:10 +0000217 throw errors.cannotInjectRawProvider().toException();
crazyboblee712705c2007-09-07 03:20:30 +0000218 }
219
kevinb9n1601ae52008-06-03 22:21:04 +0000220 Type entryType = ((ParameterizedType) providerType).getActualTypeArguments()[0];
crazyboblee712705c2007-09-07 03:20:30 +0000221
kevinb9n1601ae52008-06-03 22:21:04 +0000222 @SuppressWarnings("unchecked") // safe because T came from Key<Provider<T>>
crazyboblee712705c2007-09-07 03:20:30 +0000223 Key<T> providedKey = (Key<T>) key.ofType(entryType);
224
limpbizkit9dc32d42008-06-15 11:29:10 +0000225 BindingImpl<T> delegate = getBindingOrThrow(providedKey, errors);
limpbizkit76c24b12008-12-25 04:32:41 +0000226 return new ProviderBindingImpl<T>(this, key, delegate);
limpbizkit916f5482008-04-16 20:51:14 +0000227 }
228
limpbizkit76c24b12008-12-25 04:32:41 +0000229 static class ProviderBindingImpl<T> extends BindingImpl<Provider<T>>
limpbizkit8996e802008-12-28 01:44:29 +0000230 implements ProviderBinding<Provider<T>> {
limpbizkita8865992008-08-21 07:09:59 +0000231 final BindingImpl<T> providedBinding;
crazyboblee712705c2007-09-07 03:20:30 +0000232
limpbizkit76c24b12008-12-25 04:32:41 +0000233 ProviderBindingImpl(InjectorImpl injector, Key<Provider<T>> key, Binding<T> providedBinding) {
234 super(injector, key, providedBinding.getSource(), createInternalFactory(providedBinding),
235 Scoping.UNSCOPED);
limpbizkita8865992008-08-21 07:09:59 +0000236 this.providedBinding = (BindingImpl<T>) providedBinding;
crazyboblee712705c2007-09-07 03:20:30 +0000237 }
238
kevinb9n1601ae52008-06-03 22:21:04 +0000239 static <T> InternalFactory<Provider<T>> createInternalFactory(Binding<T> providedBinding) {
crazyboblee712705c2007-09-07 03:20:30 +0000240 final Provider<T> provider = providedBinding.getProvider();
241 return new InternalFactory<Provider<T>>() {
limpbizkita98bc7a2008-08-29 16:52:44 +0000242 public Provider<T> get(Errors errors, InternalContext context, Dependency dependency) {
crazyboblee712705c2007-09-07 03:20:30 +0000243 return provider;
244 }
245 };
246 }
247
limpbizkit76c24b12008-12-25 04:32:41 +0000248 public Key<? extends T> getProvidedKey() {
249 return providedBinding.getKey();
250 }
251
limpbizkit8996e802008-12-28 01:44:29 +0000252 public <V> V acceptTargetVisitor(BindingTargetVisitor<? super Provider<T>, V> visitor) {
limpbizkit03b81a62009-03-18 05:34:39 +0000253 return visitor.visit(this);
254 }
255
256 public void applyTo(Binder binder) {
257 throw new UnsupportedOperationException("This element represents a synthetic binding.");
limpbizkit477f9f92008-07-28 07:05:14 +0000258 }
limpbizkitc3f92842008-12-30 19:43:47 +0000259
260 @Override public String toString() {
261 return new ToStringBuilder(ProviderKeyBinding.class)
262 .add("key", getKey())
263 .add("providedKey", getProvidedKey())
264 .toString();
265 }
crazyboblee712705c2007-09-07 03:20:30 +0000266 }
267
crazyboblee712705c2007-09-07 03:20:30 +0000268 /**
crazyboblee712705c2007-09-07 03:20:30 +0000269 * Converts a constant string binding to the required type.
270 *
limpbizkit9dc32d42008-06-15 11:29:10 +0000271 * @return the binding if it could be resolved, or null if the binding doesn't exist
limpbizkit163c48a2008-06-16 02:58:08 +0000272 * @throws com.google.inject.internal.ErrorsException if there was an error resolving the binding
crazyboblee712705c2007-09-07 03:20:30 +0000273 */
limpbizkit9dc32d42008-06-15 11:29:10 +0000274 private <T> BindingImpl<T> convertConstantStringBinding(Key<T> key, Errors errors)
limpbizkit163c48a2008-06-16 02:58:08 +0000275 throws ErrorsException {
crazyboblee712705c2007-09-07 03:20:30 +0000276 // Find a constant string binding.
277 Key<String> stringKey = key.ofType(String.class);
limpbizkit5fb9d922008-10-14 23:35:56 +0000278 BindingImpl<String> stringBinding = state.getExplicitBinding(stringKey);
crazyboblee712705c2007-09-07 03:20:30 +0000279 if (stringBinding == null || !stringBinding.isConstant()) {
crazyboblee712705c2007-09-07 03:20:30 +0000280 return null;
281 }
282
crazyboblee7c9d7792007-09-09 03:41:05 +0000283 String stringValue = stringBinding.getProvider().get();
limpbizkit163c48a2008-06-16 02:58:08 +0000284 Object source = stringBinding.getSource();
crazyboblee712705c2007-09-07 03:20:30 +0000285
crazyboblee7c9d7792007-09-09 03:41:05 +0000286 // Find a matching type converter.
287 TypeLiteral<T> type = key.getTypeLiteral();
limpbizkit5fb9d922008-10-14 23:35:56 +0000288 MatcherAndConverter matchingConverter = state.getConverter(stringValue, type, errors, source);
crazyboblee712705c2007-09-07 03:20:30 +0000289
crazyboblee7c9d7792007-09-09 03:41:05 +0000290 if (matchingConverter == null) {
291 // No converter can handle the given type.
292 return null;
crazyboblee712705c2007-09-07 03:20:30 +0000293 }
294
crazyboblee7c9d7792007-09-09 03:41:05 +0000295 // Try to convert the string. A failed conversion results in an error.
crazyboblee712705c2007-09-07 03:20:30 +0000296 try {
kevinb9n1601ae52008-06-03 22:21:04 +0000297 @SuppressWarnings("unchecked") // This cast is safe because we double check below.
limpbizkitc5c488e2008-06-16 01:42:25 +0000298 T converted = (T) matchingConverter.getTypeConverter().convert(stringValue, type);
crazyboblee7c9d7792007-09-09 03:41:05 +0000299
300 if (converted == null) {
limpbizkitc5c488e2008-06-16 01:42:25 +0000301 throw errors.converterReturnedNull(stringValue, source, type, matchingConverter)
302 .toException();
crazyboblee7c9d7792007-09-09 03:41:05 +0000303 }
304
limpbizkitc0fe03b2008-06-02 04:46:53 +0000305 if (!type.getRawType().isInstance(converted)) {
limpbizkitc5c488e2008-06-16 01:42:25 +0000306 throw errors.conversionTypeError(stringValue, source, type, matchingConverter, converted)
307 .toException();
crazyboblee7c9d7792007-09-09 03:41:05 +0000308 }
limpbizkit163c48a2008-06-16 02:58:08 +0000309
kevinb9n1601ae52008-06-03 22:21:04 +0000310 return new ConvertedConstantBindingImpl<T>(this, key, converted, stringBinding);
limpbizkit06898062008-11-02 05:14:55 +0000311 } catch (ErrorsException e) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000312 throw e;
limpbizkit516e2ab2009-03-26 22:01:18 +0000313 } catch (RuntimeException e) {
limpbizkitc5c488e2008-06-16 01:42:25 +0000314 throw errors.conversionError(stringValue, source, type, matchingConverter, e)
315 .toException();
crazyboblee712705c2007-09-07 03:20:30 +0000316 }
317 }
318
limpbizkit76c24b12008-12-25 04:32:41 +0000319 private static class ConvertedConstantBindingImpl<T>
320 extends BindingImpl<T> implements ConvertedConstantBinding<T> {
crazyboblee712705c2007-09-07 03:20:30 +0000321 final T value;
322 final Provider<T> provider;
323 final Binding<String> originalBinding;
324
kevinb9n1601ae52008-06-03 22:21:04 +0000325 ConvertedConstantBindingImpl(
limpbizkit76c24b12008-12-25 04:32:41 +0000326 Injector injector, Key<T> key, T value, Binding<String> originalBinding) {
limpbizkit5fb9d922008-10-14 23:35:56 +0000327 super(injector, key, originalBinding.getSource(),
limpbizkit76c24b12008-12-25 04:32:41 +0000328 new ConstantFactory<T>(Initializables.of(value)), Scoping.UNSCOPED);
crazyboblee712705c2007-09-07 03:20:30 +0000329 this.value = value;
kevinb9n1601ae52008-06-03 22:21:04 +0000330 provider = Providers.of(value);
crazyboblee712705c2007-09-07 03:20:30 +0000331 this.originalBinding = originalBinding;
332 }
333
kevinb9n1601ae52008-06-03 22:21:04 +0000334 @Override public Provider<T> getProvider() {
335 return provider;
crazyboblee712705c2007-09-07 03:20:30 +0000336 }
337
limpbizkit8996e802008-12-28 01:44:29 +0000338 public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
limpbizkit03b81a62009-03-18 05:34:39 +0000339 return visitor.visit(this);
limpbizkit76c24b12008-12-25 04:32:41 +0000340 }
341
342 public T getValue() {
343 return value;
344 }
345
limpbizkitc45600e2008-12-27 02:57:04 +0000346 public Key<String> getSourceKey() {
347 return originalBinding.getKey();
348 }
349
limpbizkit76c24b12008-12-25 04:32:41 +0000350 public Set<Dependency<?>> getDependencies() {
limpbizkitc45600e2008-12-27 02:57:04 +0000351 return ImmutableSet.<Dependency<?>>of(Dependency.get(getSourceKey()));
limpbizkit477f9f92008-07-28 07:05:14 +0000352 }
353
limpbizkit03b81a62009-03-18 05:34:39 +0000354 public void applyTo(Binder binder) {
355 throw new UnsupportedOperationException("This element represents a synthetic binding.");
356 }
357
kevinb9n1601ae52008-06-03 22:21:04 +0000358 @Override public String toString() {
limpbizkit76c24b12008-12-25 04:32:41 +0000359 return new ToStringBuilder(ConvertedConstantBinding.class)
360 .add("key", getKey())
limpbizkitc45600e2008-12-27 02:57:04 +0000361 .add("sourceKey", getSourceKey())
limpbizkitc3f92842008-12-30 19:43:47 +0000362 .add("value", value)
crazyboblee712705c2007-09-07 03:20:30 +0000363 .toString();
364 }
365 }
366
limpbizkit163c48a2008-06-16 02:58:08 +0000367 <T> void initializeBinding(BindingImpl<T> binding, Errors errors) throws ErrorsException {
kevinb9n1601ae52008-06-03 22:21:04 +0000368 // Put the partially constructed binding in the map a little early. This enables us to handle
369 // circular dependencies. Example: FooImpl -> BarImpl -> FooImpl.
limpbizkita8dccb32008-11-11 22:41:56 +0000370 // Note: We don't need to synchronize on state.lock() during injector creation.
limpbizkit03b81a62009-03-18 05:34:39 +0000371 // TODO: for the above example, remove the binding for BarImpl if the binding for FooImpl fails
372 if (binding instanceof ConstructorBindingImpl<?>) {
limpbizkit51411872008-05-13 22:15:29 +0000373 Key<T> key = binding.getKey();
374 jitBindings.put(key, binding);
375 boolean successful = false;
376 try {
limpbizkit03b81a62009-03-18 05:34:39 +0000377 ((ConstructorBindingImpl) binding).initialize(this, errors);
limpbizkit51411872008-05-13 22:15:29 +0000378 successful = true;
limpbizkit72d11dd2008-11-02 07:59:13 +0000379 } finally {
limpbizkit51411872008-05-13 22:15:29 +0000380 if (!successful) {
381 jitBindings.remove(key);
382 }
383 }
384 }
385 }
386
387 /**
kevinb9n1601ae52008-06-03 22:21:04 +0000388 * Creates a binding for an injectable type with the given scope. Looks for a scope on the type if
389 * none is specified.
limpbizkit51411872008-05-13 22:15:29 +0000390 */
limpbizkit76c24b12008-12-25 04:32:41 +0000391 <T> BindingImpl<T> createUnitializedBinding(Key<T> key, Scoping scoping, Object source,
392 Errors errors) throws ErrorsException {
limpbizkit4272aef2008-11-23 08:10:09 +0000393 Class<?> rawType = key.getTypeLiteral().getRawType();
limpbizkit8ba97882008-11-04 02:52:54 +0000394
limpbizkitc0fe03b2008-06-02 04:46:53 +0000395 // Don't try to inject arrays, or enums.
limpbizkit8ba97882008-11-04 02:52:54 +0000396 if (rawType.isArray() || rawType.isEnum()) {
limpbizkit06898062008-11-02 05:14:55 +0000397 throw errors.missingImplementation(key).toException();
crazyboblee712705c2007-09-07 03:20:30 +0000398 }
399
limpbizkitb0f3c9b2008-11-15 09:19:28 +0000400 // Handle TypeLiteral<T> by binding the inner type
401 if (rawType == TypeLiteral.class) {
402 @SuppressWarnings("unchecked") // we have to fudge the inner type as Object
403 BindingImpl<T> binding = (BindingImpl<T>) createTypeLiteralBinding(
404 (Key<TypeLiteral<Object>>) key, errors);
405 return binding;
406 }
407
crazyboblee712705c2007-09-07 03:20:30 +0000408 // Handle @ImplementedBy
limpbizkit8ba97882008-11-04 02:52:54 +0000409 ImplementedBy implementedBy = rawType.getAnnotation(ImplementedBy.class);
crazyboblee712705c2007-09-07 03:20:30 +0000410 if (implementedBy != null) {
limpbizkit8ba97882008-11-04 02:52:54 +0000411 Annotations.checkForMisplacedScopeAnnotations(rawType, source, errors);
limpbizkit76c24b12008-12-25 04:32:41 +0000412 return createImplementedByBinding(key, scoping, implementedBy, errors);
crazyboblee712705c2007-09-07 03:20:30 +0000413 }
414
415 // Handle @ProvidedBy.
limpbizkit8ba97882008-11-04 02:52:54 +0000416 ProvidedBy providedBy = rawType.getAnnotation(ProvidedBy.class);
crazyboblee712705c2007-09-07 03:20:30 +0000417 if (providedBy != null) {
limpbizkit8ba97882008-11-04 02:52:54 +0000418 Annotations.checkForMisplacedScopeAnnotations(rawType, source, errors);
limpbizkit76c24b12008-12-25 04:32:41 +0000419 return createProvidedByBinding(key, scoping, providedBy, errors);
crazyboblee712705c2007-09-07 03:20:30 +0000420 }
421
crazyboblee712705c2007-09-07 03:20:30 +0000422 // We can't inject abstract classes.
423 // TODO: Method interceptors could actually enable us to implement
424 // abstract types. Should we remove this restriction?
limpbizkit8ba97882008-11-04 02:52:54 +0000425 if (Modifier.isAbstract(rawType.getModifiers())) {
limpbizkit4a89ad32008-07-24 21:32:33 +0000426 throw errors.missingImplementation(key).toException();
crazyboblee712705c2007-09-07 03:20:30 +0000427 }
428
429 // Error: Inner class.
limpbizkit8ba97882008-11-04 02:52:54 +0000430 if (Classes.isInnerClass(rawType)) {
431 throw errors.cannotInjectInnerClass(rawType).toException();
crazyboblee712705c2007-09-07 03:20:30 +0000432 }
433
limpbizkit76c24b12008-12-25 04:32:41 +0000434 if (!scoping.isExplicitlyScoped()) {
435 Class<? extends Annotation> scopeAnnotation = findScopeAnnotation(errors, rawType);
limpbizkit185d2a22008-06-16 07:22:47 +0000436 if (scopeAnnotation != null) {
limpbizkit76c24b12008-12-25 04:32:41 +0000437 scoping = Scopes.makeInjectable(Scoping.forAnnotation(scopeAnnotation),
438 this, errors.withSource(rawType));
limpbizkit185d2a22008-06-16 07:22:47 +0000439 }
crazyboblee712705c2007-09-07 03:20:30 +0000440 }
441
limpbizkit03b81a62009-03-18 05:34:39 +0000442 return ConstructorBindingImpl.create(this, key, source, scoping);
crazyboblee712705c2007-09-07 03:20:30 +0000443 }
444
limpbizkitb0f3c9b2008-11-15 09:19:28 +0000445 /**
446 * Converts a binding for a {@code Key<TypeLiteral<T>>} to the value {@code TypeLiteral<T>}. It's
447 * a bit awkward because we have to pull out the inner type in the type literal.
448 */
449 private <T> BindingImpl<TypeLiteral<T>> createTypeLiteralBinding(
450 Key<TypeLiteral<T>> key, Errors errors) throws ErrorsException {
451 Type typeLiteralType = key.getTypeLiteral().getType();
452 if (!(typeLiteralType instanceof ParameterizedType)) {
453 throw errors.cannotInjectRawTypeLiteral().toException();
454 }
455
456 ParameterizedType parameterizedType = (ParameterizedType) typeLiteralType;
457 Type innerType = parameterizedType.getActualTypeArguments()[0];
458
459 // this is unforunate. We don't support building TypeLiterals for type variable like 'T'. If
460 // this proves problematic, we can probably fix TypeLiteral to support type variables
461 if (!(innerType instanceof Class)
462 && !(innerType instanceof GenericArrayType)
463 && !(innerType instanceof ParameterizedType)) {
464 throw errors.cannotInjectTypeLiteralOf(innerType).toException();
465 }
466
467 @SuppressWarnings("unchecked") // by definition, innerType == T, so this is safe
468 TypeLiteral<T> value = (TypeLiteral<T>) TypeLiteral.get(innerType);
469 InternalFactory<TypeLiteral<T>> factory = new ConstantFactory<TypeLiteral<T>>(
470 Initializables.of(value));
471 return new InstanceBindingImpl<TypeLiteral<T>>(this, key, SourceProvider.UNKNOWN_SOURCE,
472 factory, ImmutableSet.<InjectionPoint>of(), value);
473 }
474
kevinb9n1601ae52008-06-03 22:21:04 +0000475 /** Creates a binding for a type annotated with @ProvidedBy. */
limpbizkit76c24b12008-12-25 04:32:41 +0000476 <T> BindingImpl<T> createProvidedByBinding(Key<T> key, Scoping scoping,
477 ProvidedBy providedBy, Errors errors) throws ErrorsException {
limpbizkit4272aef2008-11-23 08:10:09 +0000478 final Class<?> rawType = key.getTypeLiteral().getRawType();
crazyboblee712705c2007-09-07 03:20:30 +0000479 final Class<? extends Provider<?>> providerType = providedBy.value();
480
481 // Make sure it's not the same type. TODO: Can we check for deeper loops?
limpbizkit8ba97882008-11-04 02:52:54 +0000482 if (providerType == rawType) {
limpbizkit9dc32d42008-06-15 11:29:10 +0000483 throw errors.recursiveProviderType().toException();
crazyboblee712705c2007-09-07 03:20:30 +0000484 }
485
kevinb9n1601ae52008-06-03 22:21:04 +0000486 // Assume the provider provides an appropriate type. We double check at runtime.
crazyboblee712705c2007-09-07 03:20:30 +0000487 @SuppressWarnings("unchecked")
limpbizkit06898062008-11-02 05:14:55 +0000488 final Key<? extends Provider<T>> providerKey
489 = (Key<? extends Provider<T>>) Key.get(providerType);
limpbizkit9dc32d42008-06-15 11:29:10 +0000490 final BindingImpl<? extends Provider<?>> providerBinding
491 = getBindingOrThrow(providerKey, errors);
crazyboblee712705c2007-09-07 03:20:30 +0000492
493 InternalFactory<T> internalFactory = new InternalFactory<T>() {
limpbizkita98bc7a2008-08-29 16:52:44 +0000494 public T get(Errors errors, InternalContext context, Dependency dependency)
limpbizkit163c48a2008-06-16 02:58:08 +0000495 throws ErrorsException {
limpbizkit06898062008-11-02 05:14:55 +0000496 errors = errors.withSource(providerKey);
limpbizkit76c24b12008-12-25 04:32:41 +0000497 Provider<?> provider = providerBinding.getInternalFactory().get(
498 errors, context, dependency);
limpbizkit1490c5b2008-09-01 16:03:43 +0000499 try {
500 Object o = provider.get();
limpbizkit8ba97882008-11-04 02:52:54 +0000501 if (o != null && !rawType.isInstance(o)) {
502 throw errors.subtypeNotProvided(providerType, rawType).toException();
limpbizkit1490c5b2008-09-01 16:03:43 +0000503 }
504 @SuppressWarnings("unchecked") // protected by isInstance() check above
505 T t = (T) o;
506 return t;
507 } catch (RuntimeException e) {
limpbizkit06898062008-11-02 05:14:55 +0000508 throw errors.errorInProvider(e).toException();
crazyboblee712705c2007-09-07 03:20:30 +0000509 }
510 }
511 };
512
kevinb9n1601ae52008-06-03 22:21:04 +0000513 return new LinkedProviderBindingImpl<T>(
514 this,
limpbizkit27fc50d2008-08-08 07:43:39 +0000515 key,
limpbizkit8ba97882008-11-04 02:52:54 +0000516 rawType /* source */,
limpbizkit76c24b12008-12-25 04:32:41 +0000517 Scopes.<T>scope(key, this, internalFactory, scoping),
518 scoping,
519 providerKey);
crazyboblee712705c2007-09-07 03:20:30 +0000520 }
521
kevinb9n1601ae52008-06-03 22:21:04 +0000522 /** Creates a binding for a type annotated with @ImplementedBy. */
limpbizkit76c24b12008-12-25 04:32:41 +0000523 <T> BindingImpl<T> createImplementedByBinding(Key<T> key, Scoping scoping,
524 ImplementedBy implementedBy, Errors errors)
limpbizkit163c48a2008-06-16 02:58:08 +0000525 throws ErrorsException {
limpbizkit4272aef2008-11-23 08:10:09 +0000526 Class<?> rawType = key.getTypeLiteral().getRawType();
crazyboblee712705c2007-09-07 03:20:30 +0000527 Class<?> implementationType = implementedBy.value();
528
529 // Make sure it's not the same type. TODO: Can we check for deeper cycles?
limpbizkit8ba97882008-11-04 02:52:54 +0000530 if (implementationType == rawType) {
limpbizkit9dc32d42008-06-15 11:29:10 +0000531 throw errors.recursiveImplementationType().toException();
crazyboblee712705c2007-09-07 03:20:30 +0000532 }
533
534 // Make sure implementationType extends type.
limpbizkit8ba97882008-11-04 02:52:54 +0000535 if (!rawType.isAssignableFrom(implementationType)) {
536 throw errors.notASubtype(implementationType, rawType).toException();
crazyboblee712705c2007-09-07 03:20:30 +0000537 }
538
limpbizkit06898062008-11-02 05:14:55 +0000539 @SuppressWarnings("unchecked") // After the preceding check, this cast is safe.
crazyboblee712705c2007-09-07 03:20:30 +0000540 Class<? extends T> subclass = (Class<? extends T>) implementationType;
541
542 // Look up the target binding.
limpbizkit06898062008-11-02 05:14:55 +0000543 final Key<? extends T> targetKey = Key.get(subclass);
544 final BindingImpl<? extends T> targetBinding = getBindingOrThrow(targetKey, errors);
crazyboblee712705c2007-09-07 03:20:30 +0000545
546 InternalFactory<T> internalFactory = new InternalFactory<T>() {
limpbizkita98bc7a2008-08-29 16:52:44 +0000547 public T get(Errors errors, InternalContext context, Dependency<?> dependency)
limpbizkit163c48a2008-06-16 02:58:08 +0000548 throws ErrorsException {
limpbizkit76c24b12008-12-25 04:32:41 +0000549 return targetBinding.getInternalFactory().get(
550 errors.withSource(targetKey), context, dependency);
crazyboblee712705c2007-09-07 03:20:30 +0000551 }
552 };
553
kevinb9n1601ae52008-06-03 22:21:04 +0000554 return new LinkedBindingImpl<T>(
555 this,
limpbizkit27fc50d2008-08-08 07:43:39 +0000556 key,
limpbizkit8ba97882008-11-04 02:52:54 +0000557 rawType /* source */,
limpbizkit76c24b12008-12-25 04:32:41 +0000558 Scopes.<T>scope(key, this, internalFactory, scoping),
559 scoping,
560 targetKey);
crazyboblee712705c2007-09-07 03:20:30 +0000561 }
562
limpbizkit9dc32d42008-06-15 11:29:10 +0000563 /**
limpbizkit79dc99b2008-12-09 19:02:12 +0000564 * Attempts to create a just-in-time binding for {@code key} in the root injector, falling back to
565 * other ancestor injectors until this injector is tried.
566 */
567 private <T> BindingImpl<T> createJustInTimeBindingRecursive(Key<T> key, Errors errors)
568 throws ErrorsException {
569 // ask the parent to create the JIT binding
570 if (parent != null) {
571 try {
572 return parent.createJustInTimeBindingRecursive(key, new Errors());
573 } catch (ErrorsException ignored) {
574 }
575 }
576
577 if (state.isBlacklisted(key)) {
578 throw errors.childBindingAlreadySet(key).toException();
579 }
580
581 BindingImpl<T> binding = createJustInTimeBinding(key, errors);
582 state.parent().blacklist(key);
583 jitBindings.put(key, binding);
584 return binding;
585 }
586
587 /**
limpbizkit5fb9d922008-10-14 23:35:56 +0000588 * Returns a new just-in-time binding created by resolving {@code key}. The strategies used to
589 * create just-in-time bindings are:
590 * <ol>
591 * <li>Internalizing Providers. If the requested binding is for {@code Provider<T>}, we delegate
592 * to the binding for {@code T}.
593 * <li>Converting constants.
594 * <li>ImplementedBy and ProvidedBy annotations. Only for unannotated keys.
595 * <li>The constructor of the raw type. Only for unannotated keys.
596 * </ol>
limpbizkit9dc32d42008-06-15 11:29:10 +0000597 *
limpbizkit163c48a2008-06-16 02:58:08 +0000598 * @throws com.google.inject.internal.ErrorsException if the binding cannot be created.
limpbizkit9dc32d42008-06-15 11:29:10 +0000599 */
limpbizkit5fb9d922008-10-14 23:35:56 +0000600 <T> BindingImpl<T> createJustInTimeBinding(Key<T> key, Errors errors) throws ErrorsException {
limpbizkitb92f5402009-06-03 16:50:27 +0000601 int numErrorsBefore = errors.size();
602
limpbizkit5fb9d922008-10-14 23:35:56 +0000603 if (state.isBlacklisted(key)) {
604 throw errors.childBindingAlreadySet(key).toException();
605 }
606
crazyboblee712705c2007-09-07 03:20:30 +0000607 // Handle cases where T is a Provider<?>.
608 if (isProvider(key)) {
kevinb9n1601ae52008-06-03 22:21:04 +0000609 // These casts are safe. We know T extends Provider<X> and that given Key<Provider<X>>,
610 // createProviderBinding() will return BindingImpl<Provider<X>>.
611 @SuppressWarnings("unchecked")
limpbizkit8996e802008-12-28 01:44:29 +0000612 BindingImpl binding = createProviderBinding((Key) key, errors);
crazyboblee5d575692007-09-07 17:42:28 +0000613 return binding;
crazyboblee712705c2007-09-07 03:20:30 +0000614 }
615
limpbizkit0ca7f912009-03-28 19:11:40 +0000616 // Handle cases where T is a MembersInjector<?>
617 if (isMembersInjector(key)) {
618 // These casts are safe. T extends MembersInjector<X> and that given Key<MembersInjector<X>>,
619 // createMembersInjectorBinding() will return BindingImpl<MembersInjector<X>>.
620 @SuppressWarnings("unchecked")
621 BindingImpl binding = createMembersInjectorBinding((Key) key, errors);
622 return binding;
623 }
624
crazyboblee712705c2007-09-07 03:20:30 +0000625 // Try to convert a constant string binding to the requested type.
limpbizkit9dc32d42008-06-15 11:29:10 +0000626 BindingImpl<T> convertedBinding = convertConstantStringBinding(key, errors);
crazyboblee712705c2007-09-07 03:20:30 +0000627 if (convertedBinding != null) {
628 return convertedBinding;
629 }
630
631 // If the key has an annotation...
632 if (key.hasAnnotationType()) {
633 // Look for a binding without annotation attributes or return null.
limpbizkit3b1cd582008-04-28 00:06:01 +0000634 if (key.hasAttributes()) {
635 try {
limpbizkit2c2c6102008-06-20 13:34:36 +0000636 Errors ignored = new Errors();
637 return getBindingOrThrow(key.withoutAttributes(), ignored);
638 } catch (ErrorsException ignored) {
limpbizkit3b1cd582008-04-28 00:06:01 +0000639 // throw with a more appropriate message below
640 }
641 }
limpbizkit9dc32d42008-06-15 11:29:10 +0000642 throw errors.missingImplementation(key).toException();
crazyboblee712705c2007-09-07 03:20:30 +0000643 }
644
limpbizkit4272aef2008-11-23 08:10:09 +0000645 Object source = key.getTypeLiteral().getRawType();
limpbizkit76c24b12008-12-25 04:32:41 +0000646 BindingImpl<T> binding = createUnitializedBinding(key, Scoping.UNSCOPED, source, errors);
limpbizkitb92f5402009-06-03 16:50:27 +0000647 errors.throwIfNewErrors(numErrorsBefore);
limpbizkit5fb9d922008-10-14 23:35:56 +0000648 initializeBinding(binding, errors);
649 return binding;
crazyboblee712705c2007-09-07 03:20:30 +0000650 }
651
limpbizkit9dc32d42008-06-15 11:29:10 +0000652 <T> InternalFactory<? extends T> getInternalFactory(Key<T> key, Errors errors)
limpbizkit163c48a2008-06-16 02:58:08 +0000653 throws ErrorsException {
limpbizkit76c24b12008-12-25 04:32:41 +0000654 return getBindingOrThrow(key, errors).getInternalFactory();
crazyboblee712705c2007-09-07 03:20:30 +0000655 }
656
kevinb9n225310e2007-02-20 04:12:01 +0000657 // not test-covered
crazybobleea6e73982007-02-02 00:21:07 +0000658 public Map<Key<?>, Binding<?>> getBindings() {
limpbizkit5fb9d922008-10-14 23:35:56 +0000659 return state.getExplicitBindingsThisLevel();
crazybobleea6e73982007-02-02 00:21:07 +0000660 }
661
kevinb9n48d13072007-02-12 18:21:26 +0000662 private static class BindingsMultimap {
limpbizkit53664a72009-02-21 00:25:27 +0000663 final Map<TypeLiteral<?>, List<Binding<?>>> multimap = Maps.newHashMap();
kevinb9n48d13072007-02-12 18:21:26 +0000664
limpbizkit5fb9d922008-10-14 23:35:56 +0000665 <T> void put(TypeLiteral<T> type, Binding<T> binding) {
limpbizkit53664a72009-02-21 00:25:27 +0000666 List<Binding<?>> bindingsForType = multimap.get(type);
667 if (bindingsForType == null) {
668 bindingsForType = Lists.newArrayList();
669 multimap.put(type, bindingsForType);
670 }
671 bindingsForType.add(binding);
kevinb9n48d13072007-02-12 18:21:26 +0000672 }
673
limpbizkit76c24b12008-12-25 04:32:41 +0000674
675 @SuppressWarnings("unchecked") // safe because we only put matching entries into the map
kevinb9n1601ae52008-06-03 22:21:04 +0000676 <T> List<Binding<T>> getAll(TypeLiteral<T> type) {
limpbizkit53664a72009-02-21 00:25:27 +0000677 List<Binding<?>> bindings = multimap.get(type);
678 return bindings != null
679 ? Collections.<Binding<T>>unmodifiableList((List) multimap.get(type))
680 : ImmutableList.<Binding<T>>of();
kevinb9n48d13072007-02-12 18:21:26 +0000681 }
682 }
683
crazyboblee66b415a2006-08-25 02:01:19 +0000684 /**
limpbizkita6e0e782008-09-03 06:19:56 +0000685 * Returns parameter injectors, or {@code null} if there are no parameters.
crazyboblee66b415a2006-08-25 02:01:19 +0000686 */
limpbizkite89c49e2009-05-06 01:02:14 +0000687 SingleParameterInjector<?>[] getParametersInjectors(
limpbizkit06898062008-11-02 05:14:55 +0000688 List<Dependency<?>> parameters, Errors errors) throws ErrorsException {
limpbizkita6e0e782008-09-03 06:19:56 +0000689 if (parameters.isEmpty()) {
690 return null;
limpbizkit185d2a22008-06-16 07:22:47 +0000691 }
692
limpbizkit72d11dd2008-11-02 07:59:13 +0000693 int numErrorsBefore = errors.size();
limpbizkit06898062008-11-02 05:14:55 +0000694 SingleParameterInjector<?>[] result = new SingleParameterInjector<?>[parameters.size()];
695 int i = 0;
limpbizkita98bc7a2008-08-29 16:52:44 +0000696 for (Dependency<?> parameter : parameters) {
limpbizkit9dc32d42008-06-15 11:29:10 +0000697 try {
limpbizkit06898062008-11-02 05:14:55 +0000698 result[i++] = createParameterInjector(parameter, errors.withSource(parameter));
limpbizkit163c48a2008-06-16 02:58:08 +0000699 } catch (ErrorsException rethrownBelow) {
limpbizkita6e0e782008-09-03 06:19:56 +0000700 // rethrown below
limpbizkit9dc32d42008-06-15 11:29:10 +0000701 }
crazyboblee66b415a2006-08-25 02:01:19 +0000702 }
limpbizkit9dc32d42008-06-15 11:29:10 +0000703
limpbizkit72d11dd2008-11-02 07:59:13 +0000704 errors.throwIfNewErrors(numErrorsBefore);
limpbizkite89c49e2009-05-06 01:02:14 +0000705 return result;
crazyboblee66b415a2006-08-25 02:01:19 +0000706 }
707
limpbizkita98bc7a2008-08-29 16:52:44 +0000708 <T> SingleParameterInjector<T> createParameterInjector(final Dependency<T> dependency,
limpbizkita6e0e782008-09-03 06:19:56 +0000709 final Errors errors) throws ErrorsException {
limpbizkit06898062008-11-02 05:14:55 +0000710 InternalFactory<? extends T> factory = getInternalFactory(dependency.getKey(), errors);
limpbizkita98bc7a2008-08-29 16:52:44 +0000711 return new SingleParameterInjector<T>(dependency, factory);
crazyboblee66b415a2006-08-25 02:01:19 +0000712 }
713
kevinb9n1601ae52008-06-03 22:21:04 +0000714 /** Invokes a method. */
crazyboblee0b3189c2007-02-24 00:14:51 +0000715 interface MethodInvoker {
kevinb9n1601ae52008-06-03 22:21:04 +0000716 Object invoke(Object target, Object... parameters)
717 throws IllegalAccessException, InvocationTargetException;
crazyboblee0b3189c2007-02-24 00:14:51 +0000718 }
719
limpbizkitb3a8f0b2008-09-05 22:30:40 +0000720 /** Cached constructor injectors for each type */
limpbizkita843a952009-04-08 22:24:55 +0000721 final ConstructorInjectorStore constructors = new ConstructorInjectorStore(this);
limpbizkit7cef5b02009-03-29 21:16:51 +0000722
723 /** Cached field and method injectors for each type. */
724 MembersInjectorStore membersInjectorStore;
crazyboblee66b415a2006-08-25 02:01:19 +0000725
limpbizkit97eac0f2009-03-28 18:25:35 +0000726 @SuppressWarnings("unchecked") // the members injector type is consistent with instance's type
727 public void injectMembers(Object instance) {
728 MembersInjector membersInjector = getMembersInjector(instance.getClass());
729 membersInjector.injectMembers(instance);
limpbizkit9dc32d42008-06-15 11:29:10 +0000730 }
731
limpbizkit03b81a62009-03-18 05:34:39 +0000732 public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
limpbizkit97eac0f2009-03-28 18:25:35 +0000733 Errors errors = new Errors(typeLiteral);
734 try {
limpbizkit7cef5b02009-03-29 21:16:51 +0000735 return membersInjectorStore.get(typeLiteral, errors);
limpbizkit97eac0f2009-03-28 18:25:35 +0000736 } catch (ErrorsException e) {
737 throw new ConfigurationException(errors.merge(e.getErrors()).getMessages());
738 }
limpbizkit03b81a62009-03-18 05:34:39 +0000739 }
740
741 public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
limpbizkit97eac0f2009-03-28 18:25:35 +0000742 return getMembersInjector(TypeLiteral.get(type));
limpbizkit03b81a62009-03-18 05:34:39 +0000743 }
744
crazybobleebd9544e2007-02-25 20:32:11 +0000745 public <T> Provider<T> getProvider(Class<T> type) {
746 return getProvider(Key.get(type));
crazybobleee5fbbb02007-02-05 07:00:27 +0000747 }
748
limpbizkitb3a8f0b2008-09-05 22:30:40 +0000749 <T> Provider<T> getProviderOrThrow(final Key<T> key, Errors errors) throws ErrorsException {
limpbizkit9dc32d42008-06-15 11:29:10 +0000750 final InternalFactory<? extends T> factory = getInternalFactory(key, errors);
limpbizkit06898062008-11-02 05:14:55 +0000751 final Dependency<T> dependency = Dependency.get(key);
crazyboblee66b415a2006-08-25 02:01:19 +0000752
crazybobleebd9544e2007-02-25 20:32:11 +0000753 return new Provider<T>() {
crazyboblee63b592b2007-01-25 02:45:24 +0000754 public T get() {
limpbizkit06898062008-11-02 05:14:55 +0000755 final Errors errors = new Errors(dependency);
limpbizkit9dc32d42008-06-15 11:29:10 +0000756 try {
757 T t = callInContext(new ContextualCallable<T>() {
limpbizkit163c48a2008-06-16 02:58:08 +0000758 public T call(InternalContext context) throws ErrorsException {
limpbizkita98bc7a2008-08-29 16:52:44 +0000759 context.setDependency(dependency);
limpbizkit9dc32d42008-06-15 11:29:10 +0000760 try {
limpbizkita98bc7a2008-08-29 16:52:44 +0000761 return factory.get(errors, context, dependency);
limpbizkit490833f2008-11-02 00:12:39 +0000762 } finally {
limpbizkita98bc7a2008-08-29 16:52:44 +0000763 context.setDependency(null);
limpbizkit9dc32d42008-06-15 11:29:10 +0000764 }
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000765 }
limpbizkit9dc32d42008-06-15 11:29:10 +0000766 });
limpbizkit72d11dd2008-11-02 07:59:13 +0000767 errors.throwIfNewErrors(0);
limpbizkit9dc32d42008-06-15 11:29:10 +0000768 return t;
limpbizkit163c48a2008-06-16 02:58:08 +0000769 } catch (ErrorsException e) {
limpbizkit490833f2008-11-02 00:12:39 +0000770 throw new ProvisionException(errors.merge(e.getErrors()).getMessages());
limpbizkit9dc32d42008-06-15 11:29:10 +0000771 }
crazyboblee66b415a2006-08-25 02:01:19 +0000772 }
crazybobleed7908e82007-02-16 01:04:53 +0000773
limpbizkit9dc32d42008-06-15 11:29:10 +0000774 @Override public String toString() {
crazybobleed7908e82007-02-16 01:04:53 +0000775 return factory.toString();
776 }
crazyboblee63b592b2007-01-25 02:45:24 +0000777 };
crazyboblee66b415a2006-08-25 02:01:19 +0000778 }
779
crazyboblee712705c2007-09-07 03:20:30 +0000780 public <T> Provider<T> getProvider(final Key<T> key) {
limpbizkit06898062008-11-02 05:14:55 +0000781 Errors errors = new Errors(key);
limpbizkit3b1cd582008-04-28 00:06:01 +0000782 try {
limpbizkit9dc32d42008-06-15 11:29:10 +0000783 Provider<T> result = getProviderOrThrow(key, errors);
limpbizkit72d11dd2008-11-02 07:59:13 +0000784 errors.throwIfNewErrors(0);
limpbizkit9dc32d42008-06-15 11:29:10 +0000785 return result;
limpbizkit490833f2008-11-02 00:12:39 +0000786 } catch (ErrorsException e) {
787 throw new ConfigurationException(errors.merge(e.getErrors()).getMessages());
crazyboblee712705c2007-09-07 03:20:30 +0000788 }
crazyboblee712705c2007-09-07 03:20:30 +0000789 }
790
kevinb9n27f8a582007-02-28 22:54:06 +0000791 public <T> T getInstance(Key<T> key) {
792 return getProvider(key).get();
793 }
794
795 public <T> T getInstance(Class<T> type) {
796 return getProvider(type).get();
797 }
798
limpbizkit833265f2009-05-06 18:14:32 +0000799 final ThreadLocal<Object[]> localContext;
crazyboblee66b415a2006-08-25 02:01:19 +0000800
kevinb9n1601ae52008-06-03 22:21:04 +0000801 /** Looks up thread local context. Creates (and removes) a new context if necessary. */
limpbizkit163c48a2008-06-16 02:58:08 +0000802 <T> T callInContext(ContextualCallable<T> callable) throws ErrorsException {
limpbizkit833265f2009-05-06 18:14:32 +0000803 Object[] reference = localContext.get();
804 if (reference[0] == null) {
805 reference[0] = new InternalContext();
806 try {
807 return callable.call((InternalContext)reference[0]);
808 } finally {
809 // Only clear the context if this call created it.
810 reference[0] = null;
811 }
812 } else {
813 // Someone else will clean up this context.
814 return callable.call((InternalContext)reference[0]);
crazyboblee66b415a2006-08-25 02:01:19 +0000815 }
816 }
817
crazybobleee3adfd62007-02-02 21:30:08 +0000818 public String toString() {
kevinb9na2915a92007-02-28 06:20:30 +0000819 return new ToStringBuilder(Injector.class)
limpbizkitc3f92842008-12-30 19:43:47 +0000820 .add("bindings", state.getExplicitBindingsThisLevel().values())
crazybobleee3adfd62007-02-02 21:30:08 +0000821 .toString();
822 }
limpbizkit7cef5b02009-03-29 21:16:51 +0000823
crazyboblee66b415a2006-08-25 02:01:19 +0000824}