blob: 6ceb020333c599a92ab1a5f540cff1e83d2320e4 [file] [log] [blame]
limpbizkit477f9f92008-07-28 07:05:14 +00001/**
2 * Copyright (C) 2008 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 com.google.inject.internal.BindingImpl;
limpbizkit477f9f92008-07-28 07:05:14 +000021import com.google.inject.internal.Errors;
22import com.google.inject.internal.ErrorsException;
limpbizkit76c24b12008-12-25 04:32:41 +000023import com.google.inject.internal.ExposedBindingImpl;
limpbizkit53664a72009-02-21 00:25:27 +000024import com.google.inject.internal.ImmutableSet;
limpbizkit76c24b12008-12-25 04:32:41 +000025import com.google.inject.internal.InstanceBindingImpl;
26import com.google.inject.internal.InternalFactory;
27import com.google.inject.internal.LinkedBindingImpl;
28import com.google.inject.internal.LinkedProviderBindingImpl;
limpbizkit53664a72009-02-21 00:25:27 +000029import com.google.inject.internal.Lists;
limpbizkit76c24b12008-12-25 04:32:41 +000030import com.google.inject.internal.ProviderInstanceBindingImpl;
limpbizkit759662b2009-04-26 21:00:24 +000031import com.google.inject.internal.ProviderMethod;
limpbizkit76c24b12008-12-25 04:32:41 +000032import com.google.inject.internal.Scoping;
33import com.google.inject.internal.UntargettedBindingImpl;
limpbizkitafa4b5d2008-08-02 18:40:47 +000034import com.google.inject.spi.BindingTargetVisitor;
limpbizkit76c24b12008-12-25 04:32:41 +000035import com.google.inject.spi.ConstructorBinding;
36import com.google.inject.spi.ConvertedConstantBinding;
37import com.google.inject.spi.ExposedBinding;
limpbizkitb3a8f0b2008-09-05 22:30:40 +000038import com.google.inject.spi.InjectionPoint;
limpbizkit76c24b12008-12-25 04:32:41 +000039import com.google.inject.spi.InstanceBinding;
40import com.google.inject.spi.LinkedKeyBinding;
limpbizkitc3f92842008-12-30 19:43:47 +000041import com.google.inject.spi.PrivateElements;
limpbizkit76c24b12008-12-25 04:32:41 +000042import com.google.inject.spi.ProviderBinding;
43import com.google.inject.spi.ProviderInstanceBinding;
44import com.google.inject.spi.ProviderKeyBinding;
45import com.google.inject.spi.UntargettedBinding;
limpbizkit477f9f92008-07-28 07:05:14 +000046import java.util.List;
limpbizkit477f9f92008-07-28 07:05:14 +000047import java.util.Set;
48
49/**
50 * Handles {@link Binder#bind} and {@link Binder#bindConstant} elements.
51 *
52 * @author crazybob@google.com (Bob Lee)
53 * @author jessewilson@google.com (Jesse Wilson)
54 */
limpbizkit00ca9f72008-08-02 17:56:17 +000055class BindingProcessor extends AbstractProcessor {
limpbizkit477f9f92008-07-28 07:05:14 +000056
limpbizkit477f9f92008-07-28 07:05:14 +000057 private final List<CreationListener> creationListeners = Lists.newArrayList();
limpbizkit5fb9d922008-10-14 23:35:56 +000058 private final Initializer initializer;
limpbizkitfcbdf992008-11-26 02:37:35 +000059 private final List<Runnable> uninitializedBindings = Lists.newArrayList();
limpbizkit477f9f92008-07-28 07:05:14 +000060
limpbizkitc3f92842008-12-30 19:43:47 +000061 BindingProcessor(Errors errors, Initializer initializer) {
limpbizkit477f9f92008-07-28 07:05:14 +000062 super(errors);
limpbizkit5fb9d922008-10-14 23:35:56 +000063 this.initializer = initializer;
limpbizkit477f9f92008-07-28 07:05:14 +000064 }
65
limpbizkit03b81a62009-03-18 05:34:39 +000066 @Override public <T> Boolean visit(Binding<T> command) {
limpbizkit477f9f92008-07-28 07:05:14 +000067 final Object source = command.getSource();
68
limpbizkitd1fe1302008-08-01 06:40:18 +000069 if (Void.class.equals(command.getKey().getRawType())) {
limpbizkit759662b2009-04-26 21:00:24 +000070 if (command instanceof ProviderInstanceBinding
71 && ((ProviderInstanceBinding) command).getProviderInstance() instanceof ProviderMethod) {
72 errors.voidProviderMethod();
73 } else {
74 errors.missingConstantValues();
75 }
limpbizkitd1fe1302008-08-01 06:40:18 +000076 return true;
77 }
78
limpbizkit477f9f92008-07-28 07:05:14 +000079 final Key<T> key = command.getKey();
80 Class<? super T> rawType = key.getTypeLiteral().getRawType();
81
82 if (rawType == Provider.class) {
83 errors.bindingToProvider();
84 return true;
85 }
86
87 validateKey(command.getSource(), command.getKey());
88
limpbizkit76c24b12008-12-25 04:32:41 +000089 final Scoping scoping = Scopes.makeInjectable(
90 ((BindingImpl<?>) command).getScoping(), injector, errors);
limpbizkit477f9f92008-07-28 07:05:14 +000091
limpbizkitafa4b5d2008-08-02 18:40:47 +000092 command.acceptTargetVisitor(new BindingTargetVisitor<T, Void>() {
limpbizkit76c24b12008-12-25 04:32:41 +000093
limpbizkit03b81a62009-03-18 05:34:39 +000094 public Void visit(InstanceBinding<? extends T> binding) {
limpbizkit76c24b12008-12-25 04:32:41 +000095 Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
96 T instance = binding.getInstance();
limpbizkitfcbdf992008-11-26 02:37:35 +000097 Initializable<T> ref = initializer.requestInjection(
98 injector, instance, source, injectionPoints);
limpbizkit5fb9d922008-10-14 23:35:56 +000099 ConstantFactory<? extends T> factory = new ConstantFactory<T>(ref);
limpbizkit76c24b12008-12-25 04:32:41 +0000100 InternalFactory<? extends T> scopedFactory = Scopes.scope(key, injector, factory, scoping);
limpbizkitb3a8f0b2008-09-05 22:30:40 +0000101 putBinding(new InstanceBindingImpl<T>(injector, key, source, scopedFactory, injectionPoints,
102 instance));
limpbizkit477f9f92008-07-28 07:05:14 +0000103 return null;
104 }
105
limpbizkit03b81a62009-03-18 05:34:39 +0000106 public Void visit(ProviderInstanceBinding<? extends T> binding) {
limpbizkit76c24b12008-12-25 04:32:41 +0000107 Provider<? extends T> provider = binding.getProviderInstance();
108 Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
limpbizkit5fb9d922008-10-14 23:35:56 +0000109 Initializable<Provider<? extends T>> initializable = initializer
limpbizkitfcbdf992008-11-26 02:37:35 +0000110 .<Provider<? extends T>>requestInjection(injector, provider, source, injectionPoints);
limpbizkit5fb9d922008-10-14 23:35:56 +0000111 InternalFactory<T> factory = new InternalFactoryToProviderAdapter<T>(initializable, source);
limpbizkit76c24b12008-12-25 04:32:41 +0000112 InternalFactory<? extends T> scopedFactory = Scopes.scope(key, injector, factory, scoping);
113 putBinding(new ProviderInstanceBindingImpl<T>(injector, key, source, scopedFactory, scoping,
114 provider, injectionPoints));
limpbizkit477f9f92008-07-28 07:05:14 +0000115 return null;
116 }
117
limpbizkit03b81a62009-03-18 05:34:39 +0000118 public Void visit(ProviderKeyBinding<? extends T> binding) {
limpbizkit76c24b12008-12-25 04:32:41 +0000119 Key<? extends Provider<? extends T>> providerKey = binding.getProviderKey();
limpbizkitfcbdf992008-11-26 02:37:35 +0000120 BoundProviderFactory<T> boundProviderFactory
121 = new BoundProviderFactory<T>(injector, providerKey, source);
limpbizkit477f9f92008-07-28 07:05:14 +0000122 creationListeners.add(boundProviderFactory);
123 InternalFactory<? extends T> scopedFactory = Scopes.scope(
limpbizkit76c24b12008-12-25 04:32:41 +0000124 key, injector, (InternalFactory<? extends T>) boundProviderFactory, scoping);
limpbizkit477f9f92008-07-28 07:05:14 +0000125 putBinding(new LinkedProviderBindingImpl<T>(
limpbizkit76c24b12008-12-25 04:32:41 +0000126 injector, key, source, scopedFactory, scoping, providerKey));
limpbizkit477f9f92008-07-28 07:05:14 +0000127 return null;
128 }
129
limpbizkit03b81a62009-03-18 05:34:39 +0000130 public Void visit(LinkedKeyBinding<? extends T> binding) {
limpbizkit76c24b12008-12-25 04:32:41 +0000131 Key<? extends T> linkedKey = binding.getLinkedKey();
132 if (key.equals(linkedKey)) {
limpbizkit477f9f92008-07-28 07:05:14 +0000133 errors.recursiveBinding();
134 }
135
limpbizkit76c24b12008-12-25 04:32:41 +0000136 FactoryProxy<T> factory = new FactoryProxy<T>(injector, key, linkedKey, source);
limpbizkit477f9f92008-07-28 07:05:14 +0000137 creationListeners.add(factory);
limpbizkit76c24b12008-12-25 04:32:41 +0000138 InternalFactory<? extends T> scopedFactory = Scopes.scope(key, injector, factory, scoping);
139 putBinding(
140 new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey));
limpbizkit477f9f92008-07-28 07:05:14 +0000141 return null;
142 }
143
limpbizkit03b81a62009-03-18 05:34:39 +0000144 public Void visit(UntargettedBinding<? extends T> untargetted) {
limpbizkit477f9f92008-07-28 07:05:14 +0000145 // Error: Missing implementation.
146 // Example: bind(Date.class).annotatedWith(Red.class);
147 // We can't assume abstract types aren't injectable. They may have an
148 // @ImplementedBy annotation or something.
limpbizkit8ba97882008-11-04 02:52:54 +0000149 if (key.hasAnnotationType()) {
limpbizkit477f9f92008-07-28 07:05:14 +0000150 errors.missingImplementation(key);
151 putBinding(invalidBinding(injector, key, source));
152 return null;
153 }
154
155 // This cast is safe after the preceeding check.
limpbizkit477f9f92008-07-28 07:05:14 +0000156 final BindingImpl<T> binding;
157 try {
limpbizkit76c24b12008-12-25 04:32:41 +0000158 binding = injector.createUnitializedBinding(key, scoping, source, errors);
limpbizkit477f9f92008-07-28 07:05:14 +0000159 putBinding(binding);
160 } catch (ErrorsException e) {
161 errors.merge(e.getErrors());
162 putBinding(invalidBinding(injector, key, source));
163 return null;
164 }
165
limpbizkitfcbdf992008-11-26 02:37:35 +0000166 uninitializedBindings.add(new Runnable() {
limpbizkit477f9f92008-07-28 07:05:14 +0000167 public void run() {
168 try {
limpbizkit76c24b12008-12-25 04:32:41 +0000169 ((InjectorImpl) binding.getInjector()).initializeBinding(
170 binding, errors.withSource(source));
limpbizkit477f9f92008-07-28 07:05:14 +0000171 } catch (ErrorsException e) {
172 errors.merge(e.getErrors());
173 }
174 }
175 });
176
177 return null;
178 }
179
limpbizkit03b81a62009-03-18 05:34:39 +0000180 public Void visit(ExposedBinding<? extends T> binding) {
limpbizkitaa07ab02009-05-15 07:10:43 +0000181 throw new IllegalArgumentException("Cannot apply a non-module element");
limpbizkitfcbdf992008-11-26 02:37:35 +0000182 }
183
limpbizkit03b81a62009-03-18 05:34:39 +0000184 public Void visit(ConvertedConstantBinding<? extends T> binding) {
limpbizkit477f9f92008-07-28 07:05:14 +0000185 throw new IllegalArgumentException("Cannot apply a non-module element");
186 }
187
limpbizkit03b81a62009-03-18 05:34:39 +0000188 public Void visit(ConstructorBinding<? extends T> binding) {
limpbizkit477f9f92008-07-28 07:05:14 +0000189 throw new IllegalArgumentException("Cannot apply a non-module element");
190 }
191
limpbizkit03b81a62009-03-18 05:34:39 +0000192 public Void visit(ProviderBinding<? extends T> binding) {
limpbizkit477f9f92008-07-28 07:05:14 +0000193 throw new IllegalArgumentException("Cannot apply a non-module element");
194 }
195 });
196
197 return true;
198 }
199
limpbizkitaa07ab02009-05-15 07:10:43 +0000200 @Override public Boolean visit(PrivateElements privateElements) {
201 for (Key<?> key : privateElements.getExposedKeys()) {
202 bindExposed(privateElements, key);
203 }
204 return false; // leave the private elements for the PrivateElementsProcessor to handle
205 }
206
207 private <T> void bindExposed(PrivateElements privateElements, Key<T> key) {
208 ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateElements);
209 creationListeners.add(exposedKeyFactory);
210 putBinding(new ExposedBindingImpl<T>(
211 injector, privateElements.getExposedSource(key), key, exposedKeyFactory, privateElements));
212 }
213
limpbizkit477f9f92008-07-28 07:05:14 +0000214 private <T> void validateKey(Object source, Key<T> key) {
limpbizkitb3a8f0b2008-09-05 22:30:40 +0000215 Annotations.checkForMisplacedScopeAnnotations(key.getRawType(), source, errors);
limpbizkit477f9f92008-07-28 07:05:14 +0000216 }
217
limpbizkit76c24b12008-12-25 04:32:41 +0000218 <T> UntargettedBindingImpl<T> invalidBinding(InjectorImpl injector, Key<T> key, Object source) {
219 return new UntargettedBindingImpl<T>(injector, key, source);
limpbizkit477f9f92008-07-28 07:05:14 +0000220 }
221
limpbizkitfcbdf992008-11-26 02:37:35 +0000222 public void initializeBindings() {
223 for (Runnable initializer : uninitializedBindings) {
224 initializer.run();
limpbizkit477f9f92008-07-28 07:05:14 +0000225 }
226 }
227
limpbizkitc3f92842008-12-30 19:43:47 +0000228 public void runCreationListeners() {
limpbizkit477f9f92008-07-28 07:05:14 +0000229 for (CreationListener creationListener : creationListeners) {
limpbizkitc3f92842008-12-30 19:43:47 +0000230 creationListener.notify(errors);
limpbizkit477f9f92008-07-28 07:05:14 +0000231 }
232 }
233
234 private void putBinding(BindingImpl<?> binding) {
235 Key<?> key = binding.getKey();
limpbizkit477f9f92008-07-28 07:05:14 +0000236
237 Class<?> rawType = key.getRawType();
238 if (FORBIDDEN_TYPES.contains(rawType)) {
239 errors.cannotBindToGuiceType(rawType.getSimpleName());
240 return;
241 }
242
limpbizkitfcbdf992008-11-26 02:37:35 +0000243 Binding<?> original = injector.state.getExplicitBinding(key);
244 if (original != null && !isOkayDuplicate(original, binding)) {
245 errors.bindingAlreadySet(key, original.getSource());
246 return;
limpbizkit477f9f92008-07-28 07:05:14 +0000247 }
limpbizkit5fb9d922008-10-14 23:35:56 +0000248
limpbizkit5fb9d922008-10-14 23:35:56 +0000249 // prevent the parent from creating a JIT binding for this key
limpbizkitfcbdf992008-11-26 02:37:35 +0000250 injector.state.parent().blacklist(key);
251 injector.state.putBinding(key, binding);
252 }
253
254 /**
255 * We tolerate duplicate bindings only if one exposes the other.
256 *
257 * @param original the binding in the parent injector (candidate for an exposing binding)
258 * @param binding the binding to check (candidate for the exposed binding)
259 */
260 private boolean isOkayDuplicate(Binding<?> original, BindingImpl<?> binding) {
261 if (original instanceof ExposedBindingImpl) {
262 ExposedBindingImpl exposed = (ExposedBindingImpl) original;
limpbizkitc3f92842008-12-30 19:43:47 +0000263 InjectorImpl exposedFrom = (InjectorImpl) exposed.getPrivateElements().getInjector();
limpbizkit76c24b12008-12-25 04:32:41 +0000264 return (exposedFrom == binding.getInjector());
limpbizkitfcbdf992008-11-26 02:37:35 +0000265 }
266 return false;
limpbizkit477f9f92008-07-28 07:05:14 +0000267 }
268
limpbizkit5789ef42008-08-04 06:44:30 +0000269 // It's unfortunate that we have to maintain a blacklist of specific
270 // classes, but we can't easily block the whole package because of
271 // all our unit tests.
272 private static final Set<Class<?>> FORBIDDEN_TYPES = ImmutableSet.of(
273 AbstractModule.class,
274 Binder.class,
275 Binding.class,
limpbizkit86cb3bb2008-10-15 21:25:50 +0000276 Injector.class,
limpbizkit5789ef42008-08-04 06:44:30 +0000277 Key.class,
limpbizkit0ca7f912009-03-28 19:11:40 +0000278 MembersInjector.class,
limpbizkit5789ef42008-08-04 06:44:30 +0000279 Module.class,
limpbizkit0ca7f912009-03-28 19:11:40 +0000280 Provider.class,
limpbizkit5789ef42008-08-04 06:44:30 +0000281 Scope.class,
282 TypeLiteral.class);
limpbizkit86cb3bb2008-10-15 21:25:50 +0000283 // TODO(jessewilson): fix BuiltInModule, then add Stage
limpbizkit477f9f92008-07-28 07:05:14 +0000284
285 interface CreationListener {
limpbizkitc3f92842008-12-30 19:43:47 +0000286 void notify(Errors errors);
limpbizkit477f9f92008-07-28 07:05:14 +0000287 }
288}