crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 1 | /** |
| 2 | * Copyright (C) 2006 Google Inc. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.google.inject; |
| 18 | |
limpbizkit | b3a8f0b | 2008-09-05 22:30:40 +0000 | [diff] [blame] | 19 | import com.google.inject.internal.Annotations; |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 20 | import static com.google.inject.internal.Annotations.findScopeAnnotation; |
| 21 | import com.google.inject.internal.BindingImpl; |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 22 | import com.google.inject.internal.Classes; |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 23 | import com.google.inject.internal.Errors; |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 24 | import com.google.inject.internal.ErrorsException; |
limpbizkit | 53664a7 | 2009-02-21 00:25:27 +0000 | [diff] [blame] | 25 | import com.google.inject.internal.ImmutableList; |
| 26 | import com.google.inject.internal.ImmutableSet; |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 27 | import com.google.inject.internal.InstanceBindingImpl; |
| 28 | import com.google.inject.internal.InternalContext; |
| 29 | import com.google.inject.internal.InternalFactory; |
| 30 | import com.google.inject.internal.LinkedBindingImpl; |
| 31 | import com.google.inject.internal.LinkedProviderBindingImpl; |
limpbizkit | 53664a7 | 2009-02-21 00:25:27 +0000 | [diff] [blame] | 32 | import com.google.inject.internal.Lists; |
| 33 | import com.google.inject.internal.Maps; |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 34 | import com.google.inject.internal.MatcherAndConverter; |
limpbizkit | 53664a7 | 2009-02-21 00:25:27 +0000 | [diff] [blame] | 35 | import com.google.inject.internal.Nullable; |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 36 | import com.google.inject.internal.Scoping; |
limpbizkit | b0f3c9b | 2008-11-15 09:19:28 +0000 | [diff] [blame] | 37 | import com.google.inject.internal.SourceProvider; |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 38 | import com.google.inject.internal.ToStringBuilder; |
limpbizkit | afa4b5d | 2008-08-02 18:40:47 +0000 | [diff] [blame] | 39 | import com.google.inject.spi.BindingTargetVisitor; |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 40 | import com.google.inject.spi.ConvertedConstantBinding; |
limpbizkit | a98bc7a | 2008-08-29 16:52:44 +0000 | [diff] [blame] | 41 | import com.google.inject.spi.Dependency; |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 42 | import com.google.inject.spi.InjectionPoint; |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 43 | import com.google.inject.spi.ProviderBinding; |
limpbizkit | c3f9284 | 2008-12-30 19:43:47 +0000 | [diff] [blame] | 44 | import com.google.inject.spi.ProviderKeyBinding; |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 45 | import com.google.inject.util.Providers; |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 46 | import java.lang.annotation.Annotation; |
limpbizkit | b0f3c9b | 2008-11-15 09:19:28 +0000 | [diff] [blame] | 47 | import java.lang.reflect.GenericArrayType; |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 48 | import java.lang.reflect.InvocationTargetException; |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 49 | import java.lang.reflect.Modifier; |
| 50 | import java.lang.reflect.ParameterizedType; |
| 51 | import java.lang.reflect.Type; |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 52 | import java.util.Collections; |
| 53 | import java.util.List; |
| 54 | import java.util.Map; |
limpbizkit | 3a8c155 | 2008-11-16 21:43:01 +0000 | [diff] [blame] | 55 | import java.util.Set; |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 56 | |
| 57 | /** |
kevinb9n | a2915a9 | 2007-02-28 06:20:30 +0000 | [diff] [blame] | 58 | * Default {@link Injector} implementation. |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 59 | * |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 60 | * @author crazybob@google.com (Bob Lee) |
limpbizkit | 3d58d6b | 2008-03-08 16:11:47 +0000 | [diff] [blame] | 61 | * @see InjectorBuilder |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 62 | */ |
limpbizkit | 8d62075 | 2009-03-31 22:37:26 +0000 | [diff] [blame] | 63 | class InjectorImpl implements Injector, Lookups { |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 64 | final State state; |
| 65 | final InjectorImpl parent; |
limpbizkit | 3d58d6b | 2008-03-08 16:11:47 +0000 | [diff] [blame] | 66 | final BindingsMultimap bindingsMultimap = new BindingsMultimap(); |
limpbizkit | fcbdf99 | 2008-11-26 02:37:35 +0000 | [diff] [blame] | 67 | final Initializer initializer; |
crazyboblee | 4727ee2 | 2007-01-30 03:13:38 +0000 | [diff] [blame] | 68 | |
limpbizkit | 79dc99b | 2008-12-09 19:02:12 +0000 | [diff] [blame] | 69 | /** Just-in-time binding cache. Guarded by state.lock() */ |
| 70 | final Map<Key<?>, BindingImpl<?>> jitBindings = Maps.newHashMap(); |
| 71 | |
limpbizkit | 8d62075 | 2009-03-31 22:37:26 +0000 | [diff] [blame] | 72 | Lookups lookups = new DeferredLookups(this); |
| 73 | |
limpbizkit | fcbdf99 | 2008-11-26 02:37:35 +0000 | [diff] [blame] | 74 | InjectorImpl(@Nullable InjectorImpl parent, State state, Initializer initializer) { |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 75 | this.parent = parent; |
limpbizkit | fcbdf99 | 2008-11-26 02:37:35 +0000 | [diff] [blame] | 76 | this.state = state; |
| 77 | this.initializer = initializer; |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 78 | |
| 79 | if (parent != null) { |
| 80 | localContext = parent.localContext; |
| 81 | } else { |
limpbizkit | 833265f | 2009-05-06 18:14:32 +0000 | [diff] [blame] | 82 | localContext = new ThreadLocal<Object[]>() { |
| 83 | protected Object[] initialValue() { |
| 84 | return new Object[1]; |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 85 | } |
| 86 | }; |
| 87 | } |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 88 | } |
| 89 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 90 | /** Indexes bindings by type. */ |
crazyboblee | 62fcdde | 2007-02-03 02:10:13 +0000 | [diff] [blame] | 91 | void index() { |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 92 | for (Binding<?> binding : state.getExplicitBindingsThisLevel().values()) { |
crazyboblee | 62fcdde | 2007-02-03 02:10:13 +0000 | [diff] [blame] | 93 | index(binding); |
| 94 | } |
| 95 | } |
| 96 | |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 97 | <T> void index(Binding<T> binding) { |
crazyboblee | c3e8849 | 2007-02-25 22:36:58 +0000 | [diff] [blame] | 98 | bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding); |
crazyboblee | 62fcdde | 2007-02-03 02:10:13 +0000 | [diff] [blame] | 99 | } |
| 100 | |
crazyboblee | 62fcdde | 2007-02-03 02:10:13 +0000 | [diff] [blame] | 101 | public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) { |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 102 | return bindingsMultimap.getAll(type); |
crazyboblee | 62fcdde | 2007-02-03 02:10:13 +0000 | [diff] [blame] | 103 | } |
| 104 | |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 105 | /** Returns the binding for {@code key} */ |
limpbizkit | 3b1cd58 | 2008-04-28 00:06:01 +0000 | [diff] [blame] | 106 | public <T> BindingImpl<T> getBinding(Key<T> key) { |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 107 | Errors errors = new Errors(key); |
limpbizkit | 3b1cd58 | 2008-04-28 00:06:01 +0000 | [diff] [blame] | 108 | try { |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 109 | BindingImpl<T> result = getBindingOrThrow(key, errors); |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 110 | errors.throwConfigurationExceptionIfErrorsExist(); |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 111 | return result; |
limpbizkit | 490833f | 2008-11-02 00:12:39 +0000 | [diff] [blame] | 112 | } catch (ErrorsException e) { |
| 113 | throw new ConfigurationException(errors.merge(e.getErrors()).getMessages()); |
limpbizkit | 3b1cd58 | 2008-04-28 00:06:01 +0000 | [diff] [blame] | 114 | } |
| 115 | } |
| 116 | |
| 117 | /** |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 118 | * 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. |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 122 | */ |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 123 | public <T> BindingImpl<T> getBindingOrThrow(Key<T> key, Errors errors) |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 124 | throws ErrorsException { |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 125 | // Check explicit bindings, i.e. bindings created by modules. |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 126 | BindingImpl<T> binding = state.getExplicitBinding(key); |
crazyboblee | a6e7398 | 2007-02-02 00:21:07 +0000 | [diff] [blame] | 127 | if (binding != null) { |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 128 | return binding; |
crazyboblee | 07e4182 | 2006-11-21 01:27:08 +0000 | [diff] [blame] | 129 | } |
| 130 | |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 131 | // Look for an on-demand binding. |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 132 | return getJustInTimeBinding(key, errors); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 133 | } |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame] | 134 | |
crazyboblee | 552472f | 2007-09-07 16:52:39 +0000 | [diff] [blame] | 135 | public <T> Binding<T> getBinding(Class<T> type) { |
| 136 | return getBinding(Key.get(type)); |
| 137 | } |
| 138 | |
limpbizkit | edd8d64 | 2008-10-18 19:50:49 +0000 | [diff] [blame] | 139 | public Injector getParent() { |
| 140 | return parent; |
| 141 | } |
| 142 | |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 143 | public Injector createChildInjector(Iterable<? extends Module> modules) { |
| 144 | return new InjectorBuilder() |
| 145 | .parentInjector(this) |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 146 | .addModules(modules) |
| 147 | .build(); |
| 148 | } |
| 149 | |
| 150 | public Injector createChildInjector(Module... modules) { |
| 151 | return createChildInjector(ImmutableList.of(modules)); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 152 | } |
| 153 | |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 154 | /** |
| 155 | * Returns a just-in-time binding for {@code key}, creating it if necessary. |
| 156 | * |
limpbizkit | 79dc99b | 2008-12-09 19:02:12 +0000 | [diff] [blame] | 157 | * @throws ErrorsException if the binding could not be created. |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 158 | */ |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 159 | private <T> BindingImpl<T> getJustInTimeBinding(Key<T> key, Errors errors) |
| 160 | throws ErrorsException { |
limpbizkit | a8dccb3 | 2008-11-11 22:41:56 +0000 | [diff] [blame] | 161 | synchronized (state.lock()) { |
limpbizkit | 79dc99b | 2008-12-09 19:02:12 +0000 | [diff] [blame] | 162 | // 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; |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 169 | } |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 170 | } |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 171 | |
limpbizkit | 79dc99b | 2008-12-09 19:02:12 +0000 | [diff] [blame] | 172 | return createJustInTimeBindingRecursive(key, errors); |
limpbizkit | c808df0 | 2007-08-25 03:25:13 +0000 | [diff] [blame] | 173 | } |
crazyboblee | 07e4182 | 2006-11-21 01:27:08 +0000 | [diff] [blame] | 174 | } |
| 175 | |
limpbizkit | 0ca7f91 | 2009-03-28 19:11:40 +0000 | [diff] [blame] | 176 | /** Returns true if the key type is Provider (but not a subclass of Provider). */ |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 177 | static boolean isProvider(Key<?> key) { |
| 178 | return key.getTypeLiteral().getRawType().equals(Provider.class); |
| 179 | } |
| 180 | |
limpbizkit | 0ca7f91 | 2009-03-28 19:11:40 +0000 | [diff] [blame] | 181 | /** 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]); |
limpbizkit | 7cef5b0 | 2009-03-29 21:16:51 +0000 | [diff] [blame] | 197 | MembersInjector<T> membersInjector = membersInjectorStore.get(instanceType, errors); |
limpbizkit | 0ca7f91 | 2009-03-28 19:11:40 +0000 | [diff] [blame] | 198 | |
| 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 | */ |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 211 | private <T> BindingImpl<Provider<T>> createProviderBinding(Key<Provider<T>> key, Errors errors) |
| 212 | throws ErrorsException { |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 213 | Type providerType = key.getTypeLiteral().getType(); |
| 214 | |
| 215 | // If the Provider has no type parameter (raw Provider)... |
| 216 | if (!(providerType instanceof ParameterizedType)) { |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 217 | throw errors.cannotInjectRawProvider().toException(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 218 | } |
| 219 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 220 | Type entryType = ((ParameterizedType) providerType).getActualTypeArguments()[0]; |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 221 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 222 | @SuppressWarnings("unchecked") // safe because T came from Key<Provider<T>> |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 223 | Key<T> providedKey = (Key<T>) key.ofType(entryType); |
| 224 | |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 225 | BindingImpl<T> delegate = getBindingOrThrow(providedKey, errors); |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 226 | return new ProviderBindingImpl<T>(this, key, delegate); |
limpbizkit | 916f548 | 2008-04-16 20:51:14 +0000 | [diff] [blame] | 227 | } |
| 228 | |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 229 | static class ProviderBindingImpl<T> extends BindingImpl<Provider<T>> |
limpbizkit | 8996e80 | 2008-12-28 01:44:29 +0000 | [diff] [blame] | 230 | implements ProviderBinding<Provider<T>> { |
limpbizkit | a886599 | 2008-08-21 07:09:59 +0000 | [diff] [blame] | 231 | final BindingImpl<T> providedBinding; |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 232 | |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 233 | ProviderBindingImpl(InjectorImpl injector, Key<Provider<T>> key, Binding<T> providedBinding) { |
| 234 | super(injector, key, providedBinding.getSource(), createInternalFactory(providedBinding), |
| 235 | Scoping.UNSCOPED); |
limpbizkit | a886599 | 2008-08-21 07:09:59 +0000 | [diff] [blame] | 236 | this.providedBinding = (BindingImpl<T>) providedBinding; |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 237 | } |
| 238 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 239 | static <T> InternalFactory<Provider<T>> createInternalFactory(Binding<T> providedBinding) { |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 240 | final Provider<T> provider = providedBinding.getProvider(); |
| 241 | return new InternalFactory<Provider<T>>() { |
limpbizkit | a98bc7a | 2008-08-29 16:52:44 +0000 | [diff] [blame] | 242 | public Provider<T> get(Errors errors, InternalContext context, Dependency dependency) { |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 243 | return provider; |
| 244 | } |
| 245 | }; |
| 246 | } |
| 247 | |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 248 | public Key<? extends T> getProvidedKey() { |
| 249 | return providedBinding.getKey(); |
| 250 | } |
| 251 | |
limpbizkit | 8996e80 | 2008-12-28 01:44:29 +0000 | [diff] [blame] | 252 | public <V> V acceptTargetVisitor(BindingTargetVisitor<? super Provider<T>, V> visitor) { |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 253 | return visitor.visit(this); |
| 254 | } |
| 255 | |
| 256 | public void applyTo(Binder binder) { |
| 257 | throw new UnsupportedOperationException("This element represents a synthetic binding."); |
limpbizkit | 477f9f9 | 2008-07-28 07:05:14 +0000 | [diff] [blame] | 258 | } |
limpbizkit | c3f9284 | 2008-12-30 19:43:47 +0000 | [diff] [blame] | 259 | |
| 260 | @Override public String toString() { |
| 261 | return new ToStringBuilder(ProviderKeyBinding.class) |
| 262 | .add("key", getKey()) |
| 263 | .add("providedKey", getProvidedKey()) |
| 264 | .toString(); |
| 265 | } |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 266 | } |
| 267 | |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 268 | /** |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 269 | * Converts a constant string binding to the required type. |
| 270 | * |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 271 | * @return the binding if it could be resolved, or null if the binding doesn't exist |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 272 | * @throws com.google.inject.internal.ErrorsException if there was an error resolving the binding |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 273 | */ |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 274 | private <T> BindingImpl<T> convertConstantStringBinding(Key<T> key, Errors errors) |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 275 | throws ErrorsException { |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 276 | // Find a constant string binding. |
| 277 | Key<String> stringKey = key.ofType(String.class); |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 278 | BindingImpl<String> stringBinding = state.getExplicitBinding(stringKey); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 279 | if (stringBinding == null || !stringBinding.isConstant()) { |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 280 | return null; |
| 281 | } |
| 282 | |
crazyboblee | 7c9d779 | 2007-09-09 03:41:05 +0000 | [diff] [blame] | 283 | String stringValue = stringBinding.getProvider().get(); |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 284 | Object source = stringBinding.getSource(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 285 | |
crazyboblee | 7c9d779 | 2007-09-09 03:41:05 +0000 | [diff] [blame] | 286 | // Find a matching type converter. |
| 287 | TypeLiteral<T> type = key.getTypeLiteral(); |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 288 | MatcherAndConverter matchingConverter = state.getConverter(stringValue, type, errors, source); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 289 | |
crazyboblee | 7c9d779 | 2007-09-09 03:41:05 +0000 | [diff] [blame] | 290 | if (matchingConverter == null) { |
| 291 | // No converter can handle the given type. |
| 292 | return null; |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 293 | } |
| 294 | |
crazyboblee | 7c9d779 | 2007-09-09 03:41:05 +0000 | [diff] [blame] | 295 | // Try to convert the string. A failed conversion results in an error. |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 296 | try { |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 297 | @SuppressWarnings("unchecked") // This cast is safe because we double check below. |
limpbizkit | c5c488e | 2008-06-16 01:42:25 +0000 | [diff] [blame] | 298 | T converted = (T) matchingConverter.getTypeConverter().convert(stringValue, type); |
crazyboblee | 7c9d779 | 2007-09-09 03:41:05 +0000 | [diff] [blame] | 299 | |
| 300 | if (converted == null) { |
limpbizkit | c5c488e | 2008-06-16 01:42:25 +0000 | [diff] [blame] | 301 | throw errors.converterReturnedNull(stringValue, source, type, matchingConverter) |
| 302 | .toException(); |
crazyboblee | 7c9d779 | 2007-09-09 03:41:05 +0000 | [diff] [blame] | 303 | } |
| 304 | |
limpbizkit | c0fe03b | 2008-06-02 04:46:53 +0000 | [diff] [blame] | 305 | if (!type.getRawType().isInstance(converted)) { |
limpbizkit | c5c488e | 2008-06-16 01:42:25 +0000 | [diff] [blame] | 306 | throw errors.conversionTypeError(stringValue, source, type, matchingConverter, converted) |
| 307 | .toException(); |
crazyboblee | 7c9d779 | 2007-09-09 03:41:05 +0000 | [diff] [blame] | 308 | } |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 309 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 310 | return new ConvertedConstantBindingImpl<T>(this, key, converted, stringBinding); |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 311 | } catch (ErrorsException e) { |
limpbizkit | 3b1cd58 | 2008-04-28 00:06:01 +0000 | [diff] [blame] | 312 | throw e; |
limpbizkit | 516e2ab | 2009-03-26 22:01:18 +0000 | [diff] [blame] | 313 | } catch (RuntimeException e) { |
limpbizkit | c5c488e | 2008-06-16 01:42:25 +0000 | [diff] [blame] | 314 | throw errors.conversionError(stringValue, source, type, matchingConverter, e) |
| 315 | .toException(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 316 | } |
| 317 | } |
| 318 | |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 319 | private static class ConvertedConstantBindingImpl<T> |
| 320 | extends BindingImpl<T> implements ConvertedConstantBinding<T> { |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 321 | final T value; |
| 322 | final Provider<T> provider; |
| 323 | final Binding<String> originalBinding; |
| 324 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 325 | ConvertedConstantBindingImpl( |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 326 | Injector injector, Key<T> key, T value, Binding<String> originalBinding) { |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 327 | super(injector, key, originalBinding.getSource(), |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 328 | new ConstantFactory<T>(Initializables.of(value)), Scoping.UNSCOPED); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 329 | this.value = value; |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 330 | provider = Providers.of(value); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 331 | this.originalBinding = originalBinding; |
| 332 | } |
| 333 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 334 | @Override public Provider<T> getProvider() { |
| 335 | return provider; |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 336 | } |
| 337 | |
limpbizkit | 8996e80 | 2008-12-28 01:44:29 +0000 | [diff] [blame] | 338 | public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) { |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 339 | return visitor.visit(this); |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 340 | } |
| 341 | |
| 342 | public T getValue() { |
| 343 | return value; |
| 344 | } |
| 345 | |
limpbizkit | c45600e | 2008-12-27 02:57:04 +0000 | [diff] [blame] | 346 | public Key<String> getSourceKey() { |
| 347 | return originalBinding.getKey(); |
| 348 | } |
| 349 | |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 350 | public Set<Dependency<?>> getDependencies() { |
limpbizkit | c45600e | 2008-12-27 02:57:04 +0000 | [diff] [blame] | 351 | return ImmutableSet.<Dependency<?>>of(Dependency.get(getSourceKey())); |
limpbizkit | 477f9f9 | 2008-07-28 07:05:14 +0000 | [diff] [blame] | 352 | } |
| 353 | |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 354 | public void applyTo(Binder binder) { |
| 355 | throw new UnsupportedOperationException("This element represents a synthetic binding."); |
| 356 | } |
| 357 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 358 | @Override public String toString() { |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 359 | return new ToStringBuilder(ConvertedConstantBinding.class) |
| 360 | .add("key", getKey()) |
limpbizkit | c45600e | 2008-12-27 02:57:04 +0000 | [diff] [blame] | 361 | .add("sourceKey", getSourceKey()) |
limpbizkit | c3f9284 | 2008-12-30 19:43:47 +0000 | [diff] [blame] | 362 | .add("value", value) |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 363 | .toString(); |
| 364 | } |
| 365 | } |
| 366 | |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 367 | <T> void initializeBinding(BindingImpl<T> binding, Errors errors) throws ErrorsException { |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 368 | // Put the partially constructed binding in the map a little early. This enables us to handle |
| 369 | // circular dependencies. Example: FooImpl -> BarImpl -> FooImpl. |
limpbizkit | a8dccb3 | 2008-11-11 22:41:56 +0000 | [diff] [blame] | 370 | // Note: We don't need to synchronize on state.lock() during injector creation. |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 371 | // TODO: for the above example, remove the binding for BarImpl if the binding for FooImpl fails |
| 372 | if (binding instanceof ConstructorBindingImpl<?>) { |
limpbizkit | 5141187 | 2008-05-13 22:15:29 +0000 | [diff] [blame] | 373 | Key<T> key = binding.getKey(); |
| 374 | jitBindings.put(key, binding); |
| 375 | boolean successful = false; |
| 376 | try { |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 377 | ((ConstructorBindingImpl) binding).initialize(this, errors); |
limpbizkit | 5141187 | 2008-05-13 22:15:29 +0000 | [diff] [blame] | 378 | successful = true; |
limpbizkit | 72d11dd | 2008-11-02 07:59:13 +0000 | [diff] [blame] | 379 | } finally { |
limpbizkit | 5141187 | 2008-05-13 22:15:29 +0000 | [diff] [blame] | 380 | if (!successful) { |
| 381 | jitBindings.remove(key); |
| 382 | } |
| 383 | } |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | /** |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 388 | * Creates a binding for an injectable type with the given scope. Looks for a scope on the type if |
| 389 | * none is specified. |
limpbizkit | 5141187 | 2008-05-13 22:15:29 +0000 | [diff] [blame] | 390 | */ |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 391 | <T> BindingImpl<T> createUnitializedBinding(Key<T> key, Scoping scoping, Object source, |
| 392 | Errors errors) throws ErrorsException { |
limpbizkit | 4272aef | 2008-11-23 08:10:09 +0000 | [diff] [blame] | 393 | Class<?> rawType = key.getTypeLiteral().getRawType(); |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 394 | |
limpbizkit | c0fe03b | 2008-06-02 04:46:53 +0000 | [diff] [blame] | 395 | // Don't try to inject arrays, or enums. |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 396 | if (rawType.isArray() || rawType.isEnum()) { |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 397 | throw errors.missingImplementation(key).toException(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 398 | } |
| 399 | |
limpbizkit | b0f3c9b | 2008-11-15 09:19:28 +0000 | [diff] [blame] | 400 | // 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 | |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 408 | // Handle @ImplementedBy |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 409 | ImplementedBy implementedBy = rawType.getAnnotation(ImplementedBy.class); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 410 | if (implementedBy != null) { |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 411 | Annotations.checkForMisplacedScopeAnnotations(rawType, source, errors); |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 412 | return createImplementedByBinding(key, scoping, implementedBy, errors); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 413 | } |
| 414 | |
| 415 | // Handle @ProvidedBy. |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 416 | ProvidedBy providedBy = rawType.getAnnotation(ProvidedBy.class); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 417 | if (providedBy != null) { |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 418 | Annotations.checkForMisplacedScopeAnnotations(rawType, source, errors); |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 419 | return createProvidedByBinding(key, scoping, providedBy, errors); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 420 | } |
| 421 | |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 422 | // We can't inject abstract classes. |
| 423 | // TODO: Method interceptors could actually enable us to implement |
| 424 | // abstract types. Should we remove this restriction? |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 425 | if (Modifier.isAbstract(rawType.getModifiers())) { |
limpbizkit | 4a89ad3 | 2008-07-24 21:32:33 +0000 | [diff] [blame] | 426 | throw errors.missingImplementation(key).toException(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 427 | } |
| 428 | |
| 429 | // Error: Inner class. |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 430 | if (Classes.isInnerClass(rawType)) { |
| 431 | throw errors.cannotInjectInnerClass(rawType).toException(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 432 | } |
| 433 | |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 434 | if (!scoping.isExplicitlyScoped()) { |
| 435 | Class<? extends Annotation> scopeAnnotation = findScopeAnnotation(errors, rawType); |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 436 | if (scopeAnnotation != null) { |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 437 | scoping = Scopes.makeInjectable(Scoping.forAnnotation(scopeAnnotation), |
| 438 | this, errors.withSource(rawType)); |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 439 | } |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 440 | } |
| 441 | |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 442 | return ConstructorBindingImpl.create(this, key, source, scoping); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 443 | } |
| 444 | |
limpbizkit | b0f3c9b | 2008-11-15 09:19:28 +0000 | [diff] [blame] | 445 | /** |
| 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 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 475 | /** Creates a binding for a type annotated with @ProvidedBy. */ |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 476 | <T> BindingImpl<T> createProvidedByBinding(Key<T> key, Scoping scoping, |
| 477 | ProvidedBy providedBy, Errors errors) throws ErrorsException { |
limpbizkit | 4272aef | 2008-11-23 08:10:09 +0000 | [diff] [blame] | 478 | final Class<?> rawType = key.getTypeLiteral().getRawType(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 479 | final Class<? extends Provider<?>> providerType = providedBy.value(); |
| 480 | |
| 481 | // Make sure it's not the same type. TODO: Can we check for deeper loops? |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 482 | if (providerType == rawType) { |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 483 | throw errors.recursiveProviderType().toException(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 484 | } |
| 485 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 486 | // Assume the provider provides an appropriate type. We double check at runtime. |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 487 | @SuppressWarnings("unchecked") |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 488 | final Key<? extends Provider<T>> providerKey |
| 489 | = (Key<? extends Provider<T>>) Key.get(providerType); |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 490 | final BindingImpl<? extends Provider<?>> providerBinding |
| 491 | = getBindingOrThrow(providerKey, errors); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 492 | |
| 493 | InternalFactory<T> internalFactory = new InternalFactory<T>() { |
limpbizkit | a98bc7a | 2008-08-29 16:52:44 +0000 | [diff] [blame] | 494 | public T get(Errors errors, InternalContext context, Dependency dependency) |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 495 | throws ErrorsException { |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 496 | errors = errors.withSource(providerKey); |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 497 | Provider<?> provider = providerBinding.getInternalFactory().get( |
| 498 | errors, context, dependency); |
limpbizkit | 1490c5b | 2008-09-01 16:03:43 +0000 | [diff] [blame] | 499 | try { |
| 500 | Object o = provider.get(); |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 501 | if (o != null && !rawType.isInstance(o)) { |
| 502 | throw errors.subtypeNotProvided(providerType, rawType).toException(); |
limpbizkit | 1490c5b | 2008-09-01 16:03:43 +0000 | [diff] [blame] | 503 | } |
| 504 | @SuppressWarnings("unchecked") // protected by isInstance() check above |
| 505 | T t = (T) o; |
| 506 | return t; |
| 507 | } catch (RuntimeException e) { |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 508 | throw errors.errorInProvider(e).toException(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 509 | } |
| 510 | } |
| 511 | }; |
| 512 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 513 | return new LinkedProviderBindingImpl<T>( |
| 514 | this, |
limpbizkit | 27fc50d | 2008-08-08 07:43:39 +0000 | [diff] [blame] | 515 | key, |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 516 | rawType /* source */, |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 517 | Scopes.<T>scope(key, this, internalFactory, scoping), |
| 518 | scoping, |
| 519 | providerKey); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 520 | } |
| 521 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 522 | /** Creates a binding for a type annotated with @ImplementedBy. */ |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 523 | <T> BindingImpl<T> createImplementedByBinding(Key<T> key, Scoping scoping, |
| 524 | ImplementedBy implementedBy, Errors errors) |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 525 | throws ErrorsException { |
limpbizkit | 4272aef | 2008-11-23 08:10:09 +0000 | [diff] [blame] | 526 | Class<?> rawType = key.getTypeLiteral().getRawType(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 527 | Class<?> implementationType = implementedBy.value(); |
| 528 | |
| 529 | // Make sure it's not the same type. TODO: Can we check for deeper cycles? |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 530 | if (implementationType == rawType) { |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 531 | throw errors.recursiveImplementationType().toException(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 532 | } |
| 533 | |
| 534 | // Make sure implementationType extends type. |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 535 | if (!rawType.isAssignableFrom(implementationType)) { |
| 536 | throw errors.notASubtype(implementationType, rawType).toException(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 537 | } |
| 538 | |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 539 | @SuppressWarnings("unchecked") // After the preceding check, this cast is safe. |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 540 | Class<? extends T> subclass = (Class<? extends T>) implementationType; |
| 541 | |
| 542 | // Look up the target binding. |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 543 | final Key<? extends T> targetKey = Key.get(subclass); |
| 544 | final BindingImpl<? extends T> targetBinding = getBindingOrThrow(targetKey, errors); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 545 | |
| 546 | InternalFactory<T> internalFactory = new InternalFactory<T>() { |
limpbizkit | a98bc7a | 2008-08-29 16:52:44 +0000 | [diff] [blame] | 547 | public T get(Errors errors, InternalContext context, Dependency<?> dependency) |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 548 | throws ErrorsException { |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 549 | return targetBinding.getInternalFactory().get( |
| 550 | errors.withSource(targetKey), context, dependency); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 551 | } |
| 552 | }; |
| 553 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 554 | return new LinkedBindingImpl<T>( |
| 555 | this, |
limpbizkit | 27fc50d | 2008-08-08 07:43:39 +0000 | [diff] [blame] | 556 | key, |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 557 | rawType /* source */, |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 558 | Scopes.<T>scope(key, this, internalFactory, scoping), |
| 559 | scoping, |
| 560 | targetKey); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 561 | } |
| 562 | |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 563 | /** |
limpbizkit | 79dc99b | 2008-12-09 19:02:12 +0000 | [diff] [blame] | 564 | * 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 | /** |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 588 | * 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> |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 597 | * |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 598 | * @throws com.google.inject.internal.ErrorsException if the binding cannot be created. |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 599 | */ |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 600 | <T> BindingImpl<T> createJustInTimeBinding(Key<T> key, Errors errors) throws ErrorsException { |
limpbizkit | b92f540 | 2009-06-03 16:50:27 +0000 | [diff] [blame] | 601 | int numErrorsBefore = errors.size(); |
| 602 | |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 603 | if (state.isBlacklisted(key)) { |
| 604 | throw errors.childBindingAlreadySet(key).toException(); |
| 605 | } |
| 606 | |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 607 | // Handle cases where T is a Provider<?>. |
| 608 | if (isProvider(key)) { |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 609 | // 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") |
limpbizkit | 8996e80 | 2008-12-28 01:44:29 +0000 | [diff] [blame] | 612 | BindingImpl binding = createProviderBinding((Key) key, errors); |
crazyboblee | 5d57569 | 2007-09-07 17:42:28 +0000 | [diff] [blame] | 613 | return binding; |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 614 | } |
| 615 | |
limpbizkit | 0ca7f91 | 2009-03-28 19:11:40 +0000 | [diff] [blame] | 616 | // 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 | |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 625 | // Try to convert a constant string binding to the requested type. |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 626 | BindingImpl<T> convertedBinding = convertConstantStringBinding(key, errors); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 627 | 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. |
limpbizkit | 3b1cd58 | 2008-04-28 00:06:01 +0000 | [diff] [blame] | 634 | if (key.hasAttributes()) { |
| 635 | try { |
limpbizkit | 2c2c610 | 2008-06-20 13:34:36 +0000 | [diff] [blame] | 636 | Errors ignored = new Errors(); |
| 637 | return getBindingOrThrow(key.withoutAttributes(), ignored); |
| 638 | } catch (ErrorsException ignored) { |
limpbizkit | 3b1cd58 | 2008-04-28 00:06:01 +0000 | [diff] [blame] | 639 | // throw with a more appropriate message below |
| 640 | } |
| 641 | } |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 642 | throw errors.missingImplementation(key).toException(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 643 | } |
| 644 | |
limpbizkit | 4272aef | 2008-11-23 08:10:09 +0000 | [diff] [blame] | 645 | Object source = key.getTypeLiteral().getRawType(); |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 646 | BindingImpl<T> binding = createUnitializedBinding(key, Scoping.UNSCOPED, source, errors); |
limpbizkit | b92f540 | 2009-06-03 16:50:27 +0000 | [diff] [blame] | 647 | errors.throwIfNewErrors(numErrorsBefore); |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 648 | initializeBinding(binding, errors); |
| 649 | return binding; |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 650 | } |
| 651 | |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 652 | <T> InternalFactory<? extends T> getInternalFactory(Key<T> key, Errors errors) |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 653 | throws ErrorsException { |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 654 | return getBindingOrThrow(key, errors).getInternalFactory(); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 655 | } |
| 656 | |
kevinb9n | 225310e | 2007-02-20 04:12:01 +0000 | [diff] [blame] | 657 | // not test-covered |
crazyboblee | a6e7398 | 2007-02-02 00:21:07 +0000 | [diff] [blame] | 658 | public Map<Key<?>, Binding<?>> getBindings() { |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 659 | return state.getExplicitBindingsThisLevel(); |
crazyboblee | a6e7398 | 2007-02-02 00:21:07 +0000 | [diff] [blame] | 660 | } |
| 661 | |
kevinb9n | 48d1307 | 2007-02-12 18:21:26 +0000 | [diff] [blame] | 662 | private static class BindingsMultimap { |
limpbizkit | 53664a7 | 2009-02-21 00:25:27 +0000 | [diff] [blame] | 663 | final Map<TypeLiteral<?>, List<Binding<?>>> multimap = Maps.newHashMap(); |
kevinb9n | 48d1307 | 2007-02-12 18:21:26 +0000 | [diff] [blame] | 664 | |
limpbizkit | 5fb9d92 | 2008-10-14 23:35:56 +0000 | [diff] [blame] | 665 | <T> void put(TypeLiteral<T> type, Binding<T> binding) { |
limpbizkit | 53664a7 | 2009-02-21 00:25:27 +0000 | [diff] [blame] | 666 | List<Binding<?>> bindingsForType = multimap.get(type); |
| 667 | if (bindingsForType == null) { |
| 668 | bindingsForType = Lists.newArrayList(); |
| 669 | multimap.put(type, bindingsForType); |
| 670 | } |
| 671 | bindingsForType.add(binding); |
kevinb9n | 48d1307 | 2007-02-12 18:21:26 +0000 | [diff] [blame] | 672 | } |
| 673 | |
limpbizkit | 76c24b1 | 2008-12-25 04:32:41 +0000 | [diff] [blame] | 674 | |
| 675 | @SuppressWarnings("unchecked") // safe because we only put matching entries into the map |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 676 | <T> List<Binding<T>> getAll(TypeLiteral<T> type) { |
limpbizkit | 53664a7 | 2009-02-21 00:25:27 +0000 | [diff] [blame] | 677 | List<Binding<?>> bindings = multimap.get(type); |
| 678 | return bindings != null |
| 679 | ? Collections.<Binding<T>>unmodifiableList((List) multimap.get(type)) |
| 680 | : ImmutableList.<Binding<T>>of(); |
kevinb9n | 48d1307 | 2007-02-12 18:21:26 +0000 | [diff] [blame] | 681 | } |
| 682 | } |
| 683 | |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 684 | /** |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 685 | * Returns parameter injectors, or {@code null} if there are no parameters. |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 686 | */ |
limpbizkit | e89c49e | 2009-05-06 01:02:14 +0000 | [diff] [blame] | 687 | SingleParameterInjector<?>[] getParametersInjectors( |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 688 | List<Dependency<?>> parameters, Errors errors) throws ErrorsException { |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 689 | if (parameters.isEmpty()) { |
| 690 | return null; |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 691 | } |
| 692 | |
limpbizkit | 72d11dd | 2008-11-02 07:59:13 +0000 | [diff] [blame] | 693 | int numErrorsBefore = errors.size(); |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 694 | SingleParameterInjector<?>[] result = new SingleParameterInjector<?>[parameters.size()]; |
| 695 | int i = 0; |
limpbizkit | a98bc7a | 2008-08-29 16:52:44 +0000 | [diff] [blame] | 696 | for (Dependency<?> parameter : parameters) { |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 697 | try { |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 698 | result[i++] = createParameterInjector(parameter, errors.withSource(parameter)); |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 699 | } catch (ErrorsException rethrownBelow) { |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 700 | // rethrown below |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 701 | } |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 702 | } |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 703 | |
limpbizkit | 72d11dd | 2008-11-02 07:59:13 +0000 | [diff] [blame] | 704 | errors.throwIfNewErrors(numErrorsBefore); |
limpbizkit | e89c49e | 2009-05-06 01:02:14 +0000 | [diff] [blame] | 705 | return result; |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 706 | } |
| 707 | |
limpbizkit | a98bc7a | 2008-08-29 16:52:44 +0000 | [diff] [blame] | 708 | <T> SingleParameterInjector<T> createParameterInjector(final Dependency<T> dependency, |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 709 | final Errors errors) throws ErrorsException { |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 710 | InternalFactory<? extends T> factory = getInternalFactory(dependency.getKey(), errors); |
limpbizkit | a98bc7a | 2008-08-29 16:52:44 +0000 | [diff] [blame] | 711 | return new SingleParameterInjector<T>(dependency, factory); |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 712 | } |
| 713 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 714 | /** Invokes a method. */ |
crazyboblee | 0b3189c | 2007-02-24 00:14:51 +0000 | [diff] [blame] | 715 | interface MethodInvoker { |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 716 | Object invoke(Object target, Object... parameters) |
| 717 | throws IllegalAccessException, InvocationTargetException; |
crazyboblee | 0b3189c | 2007-02-24 00:14:51 +0000 | [diff] [blame] | 718 | } |
| 719 | |
limpbizkit | b3a8f0b | 2008-09-05 22:30:40 +0000 | [diff] [blame] | 720 | /** Cached constructor injectors for each type */ |
limpbizkit | a843a95 | 2009-04-08 22:24:55 +0000 | [diff] [blame] | 721 | final ConstructorInjectorStore constructors = new ConstructorInjectorStore(this); |
limpbizkit | 7cef5b0 | 2009-03-29 21:16:51 +0000 | [diff] [blame] | 722 | |
| 723 | /** Cached field and method injectors for each type. */ |
| 724 | MembersInjectorStore membersInjectorStore; |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 725 | |
limpbizkit | 97eac0f | 2009-03-28 18:25:35 +0000 | [diff] [blame] | 726 | @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); |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 730 | } |
| 731 | |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 732 | public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) { |
limpbizkit | 97eac0f | 2009-03-28 18:25:35 +0000 | [diff] [blame] | 733 | Errors errors = new Errors(typeLiteral); |
| 734 | try { |
limpbizkit | 7cef5b0 | 2009-03-29 21:16:51 +0000 | [diff] [blame] | 735 | return membersInjectorStore.get(typeLiteral, errors); |
limpbizkit | 97eac0f | 2009-03-28 18:25:35 +0000 | [diff] [blame] | 736 | } catch (ErrorsException e) { |
| 737 | throw new ConfigurationException(errors.merge(e.getErrors()).getMessages()); |
| 738 | } |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 739 | } |
| 740 | |
| 741 | public <T> MembersInjector<T> getMembersInjector(Class<T> type) { |
limpbizkit | 97eac0f | 2009-03-28 18:25:35 +0000 | [diff] [blame] | 742 | return getMembersInjector(TypeLiteral.get(type)); |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 743 | } |
| 744 | |
crazyboblee | bd9544e | 2007-02-25 20:32:11 +0000 | [diff] [blame] | 745 | public <T> Provider<T> getProvider(Class<T> type) { |
| 746 | return getProvider(Key.get(type)); |
crazyboblee | e5fbbb0 | 2007-02-05 07:00:27 +0000 | [diff] [blame] | 747 | } |
| 748 | |
limpbizkit | b3a8f0b | 2008-09-05 22:30:40 +0000 | [diff] [blame] | 749 | <T> Provider<T> getProviderOrThrow(final Key<T> key, Errors errors) throws ErrorsException { |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 750 | final InternalFactory<? extends T> factory = getInternalFactory(key, errors); |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 751 | final Dependency<T> dependency = Dependency.get(key); |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 752 | |
crazyboblee | bd9544e | 2007-02-25 20:32:11 +0000 | [diff] [blame] | 753 | return new Provider<T>() { |
crazyboblee | 63b592b | 2007-01-25 02:45:24 +0000 | [diff] [blame] | 754 | public T get() { |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 755 | final Errors errors = new Errors(dependency); |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 756 | try { |
| 757 | T t = callInContext(new ContextualCallable<T>() { |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 758 | public T call(InternalContext context) throws ErrorsException { |
limpbizkit | a98bc7a | 2008-08-29 16:52:44 +0000 | [diff] [blame] | 759 | context.setDependency(dependency); |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 760 | try { |
limpbizkit | a98bc7a | 2008-08-29 16:52:44 +0000 | [diff] [blame] | 761 | return factory.get(errors, context, dependency); |
limpbizkit | 490833f | 2008-11-02 00:12:39 +0000 | [diff] [blame] | 762 | } finally { |
limpbizkit | a98bc7a | 2008-08-29 16:52:44 +0000 | [diff] [blame] | 763 | context.setDependency(null); |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 764 | } |
limpbizkit | fcf2b8c | 2007-10-21 18:23:43 +0000 | [diff] [blame] | 765 | } |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 766 | }); |
limpbizkit | 72d11dd | 2008-11-02 07:59:13 +0000 | [diff] [blame] | 767 | errors.throwIfNewErrors(0); |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 768 | return t; |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 769 | } catch (ErrorsException e) { |
limpbizkit | 490833f | 2008-11-02 00:12:39 +0000 | [diff] [blame] | 770 | throw new ProvisionException(errors.merge(e.getErrors()).getMessages()); |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 771 | } |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 772 | } |
crazyboblee | d7908e8 | 2007-02-16 01:04:53 +0000 | [diff] [blame] | 773 | |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 774 | @Override public String toString() { |
crazyboblee | d7908e8 | 2007-02-16 01:04:53 +0000 | [diff] [blame] | 775 | return factory.toString(); |
| 776 | } |
crazyboblee | 63b592b | 2007-01-25 02:45:24 +0000 | [diff] [blame] | 777 | }; |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 778 | } |
| 779 | |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 780 | public <T> Provider<T> getProvider(final Key<T> key) { |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 781 | Errors errors = new Errors(key); |
limpbizkit | 3b1cd58 | 2008-04-28 00:06:01 +0000 | [diff] [blame] | 782 | try { |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 783 | Provider<T> result = getProviderOrThrow(key, errors); |
limpbizkit | 72d11dd | 2008-11-02 07:59:13 +0000 | [diff] [blame] | 784 | errors.throwIfNewErrors(0); |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 785 | return result; |
limpbizkit | 490833f | 2008-11-02 00:12:39 +0000 | [diff] [blame] | 786 | } catch (ErrorsException e) { |
| 787 | throw new ConfigurationException(errors.merge(e.getErrors()).getMessages()); |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 788 | } |
crazyboblee | 712705c | 2007-09-07 03:20:30 +0000 | [diff] [blame] | 789 | } |
| 790 | |
kevinb9n | 27f8a58 | 2007-02-28 22:54:06 +0000 | [diff] [blame] | 791 | 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 | |
limpbizkit | 833265f | 2009-05-06 18:14:32 +0000 | [diff] [blame] | 799 | final ThreadLocal<Object[]> localContext; |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 800 | |
kevinb9n | 1601ae5 | 2008-06-03 22:21:04 +0000 | [diff] [blame] | 801 | /** Looks up thread local context. Creates (and removes) a new context if necessary. */ |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 802 | <T> T callInContext(ContextualCallable<T> callable) throws ErrorsException { |
limpbizkit | 833265f | 2009-05-06 18:14:32 +0000 | [diff] [blame] | 803 | 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]); |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 815 | } |
| 816 | } |
| 817 | |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 818 | public String toString() { |
kevinb9n | a2915a9 | 2007-02-28 06:20:30 +0000 | [diff] [blame] | 819 | return new ToStringBuilder(Injector.class) |
limpbizkit | c3f9284 | 2008-12-30 19:43:47 +0000 | [diff] [blame] | 820 | .add("bindings", state.getExplicitBindingsThisLevel().values()) |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 821 | .toString(); |
| 822 | } |
limpbizkit | 7cef5b0 | 2009-03-29 21:16:51 +0000 | [diff] [blame] | 823 | |
crazyboblee | 66b415a | 2006-08-25 02:01:19 +0000 | [diff] [blame] | 824 | } |