blob: f5bbe8948174200b3845f60438d57ca632cac03c [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.spi;
18
sberlinb7a02b02011-07-08 00:34:16 +000019import static com.google.common.base.Preconditions.checkArgument;
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -070020import static com.google.inject.internal.InternalFlags.getIncludeStackTraceOption;
sberlinb7a02b02011-07-08 00:34:16 +000021
22import com.google.common.collect.ImmutableList;
23import com.google.common.collect.Lists;
sameb54da0e32015-02-19 18:36:52 -080024import com.google.common.collect.Maps;
sberlinb7a02b02011-07-08 00:34:16 +000025import com.google.common.collect.Sets;
limpbizkit477f9f92008-07-28 07:05:14 +000026import com.google.inject.AbstractModule;
27import com.google.inject.Binder;
limpbizkit76c24b12008-12-25 04:32:41 +000028import com.google.inject.Binding;
limpbizkit477f9f92008-07-28 07:05:14 +000029import com.google.inject.Key;
limpbizkit97eac0f2009-03-28 18:25:35 +000030import com.google.inject.MembersInjector;
limpbizkit477f9f92008-07-28 07:05:14 +000031import com.google.inject.Module;
limpbizkitbf0d8762009-02-19 09:06:22 +000032import com.google.inject.PrivateBinder;
limpbizkitfcbdf992008-11-26 02:37:35 +000033import com.google.inject.PrivateModule;
limpbizkit477f9f92008-07-28 07:05:14 +000034import com.google.inject.Provider;
35import com.google.inject.Scope;
36import com.google.inject.Stage;
37import com.google.inject.TypeLiteral;
38import com.google.inject.binder.AnnotatedBindingBuilder;
39import com.google.inject.binder.AnnotatedConstantBindingBuilder;
limpbizkit5ea4ab22008-11-25 08:43:49 +000040import com.google.inject.binder.AnnotatedElementBuilder;
limpbizkit76c24b12008-12-25 04:32:41 +000041import com.google.inject.internal.AbstractBindingBuilder;
42import com.google.inject.internal.BindingBuilder;
43import com.google.inject.internal.ConstantBindingBuilderImpl;
limpbizkit72d11dd2008-11-02 07:59:13 +000044import com.google.inject.internal.Errors;
limpbizkit@gmail.com9a227be2010-07-03 15:51:31 +000045import com.google.inject.internal.ExposureBuilder;
cgruber0910c1e2015-02-18 12:07:13 -080046import com.google.inject.internal.InternalFlags.IncludeStackTraceOption;
limpbizkitc3f92842008-12-30 19:43:47 +000047import com.google.inject.internal.PrivateElementsImpl;
limpbizkit86cb3bb2008-10-15 21:25:50 +000048import com.google.inject.internal.ProviderMethodsModule;
limpbizkit@gmail.com9a227be2010-07-03 15:51:31 +000049import com.google.inject.internal.util.SourceProvider;
Christian Edward Gruber605bd082013-08-09 11:04:00 -070050import com.google.inject.internal.util.StackTraceElements;
limpbizkit477f9f92008-07-28 07:05:14 +000051import com.google.inject.matcher.Matcher;
sberlinb7a02b02011-07-08 00:34:16 +000052
limpbizkit477f9f92008-07-28 07:05:14 +000053import java.lang.annotation.Annotation;
54import java.lang.reflect.Method;
55import java.util.Arrays;
limpbizkit5ea4ab22008-11-25 08:43:49 +000056import java.util.Collection;
limpbizkit477f9f92008-07-28 07:05:14 +000057import java.util.Collections;
58import java.util.List;
sameb54da0e32015-02-19 18:36:52 -080059import java.util.Map;
limpbizkit477f9f92008-07-28 07:05:14 +000060import java.util.Set;
limpbizkit477f9f92008-07-28 07:05:14 +000061
62/**
limpbizkitaa07ab02009-05-15 07:10:43 +000063 * Exposes elements of a module so they can be inspected, validated or {@link
64 * Element#applyTo(Binder) rewritten}.
limpbizkit477f9f92008-07-28 07:05:14 +000065 *
66 * @author jessewilson@google.com (Jesse Wilson)
limpbizkitc489adf2008-11-18 07:01:33 +000067 * @since 2.0
limpbizkit477f9f92008-07-28 07:05:14 +000068 */
69public final class Elements {
Christian Edward Gruber605bd082013-08-09 11:04:00 -070070
limpbizkitafa4b5d2008-08-02 18:40:47 +000071 private static final BindingTargetVisitor<Object, Object> GET_INSTANCE_VISITOR
72 = new DefaultBindingTargetVisitor<Object, Object>() {
limpbizkit03b81a62009-03-18 05:34:39 +000073 @Override public Object visit(InstanceBinding<?> binding) {
limpbizkit76c24b12008-12-25 04:32:41 +000074 return binding.getInstance();
limpbizkit477f9f92008-07-28 07:05:14 +000075 }
76
limpbizkit8996e802008-12-28 01:44:29 +000077 @Override protected Object visitOther(Binding<?> binding) {
limpbizkit477f9f92008-07-28 07:05:14 +000078 throw new IllegalArgumentException();
79 }
80 };
81
82 /**
83 * Records the elements executed by {@code modules}.
84 */
85 public static List<Element> getElements(Module... modules) {
86 return getElements(Stage.DEVELOPMENT, Arrays.asList(modules));
87 }
88
89 /**
90 * Records the elements executed by {@code modules}.
91 */
92 public static List<Element> getElements(Stage stage, Module... modules) {
93 return getElements(stage, Arrays.asList(modules));
94 }
95
96 /**
97 * Records the elements executed by {@code modules}.
98 */
99 public static List<Element> getElements(Iterable<? extends Module> modules) {
100 return getElements(Stage.DEVELOPMENT, modules);
101 }
102
103 /**
104 * Records the elements executed by {@code modules}.
105 */
106 public static List<Element> getElements(Stage stage, Iterable<? extends Module> modules) {
107 RecordingBinder binder = new RecordingBinder(stage);
108 for (Module module : modules) {
109 binder.install(module);
110 }
sameb54da0e32015-02-19 18:36:52 -0800111 binder.scanForAnnotatedMethods();
112 for (RecordingBinder child : binder.privateBinders) {
113 child.scanForAnnotatedMethods();
114 }
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700115 // Free the memory consumed by the stack trace elements cache
116 StackTraceElements.clearCache();
limpbizkit477f9f92008-07-28 07:05:14 +0000117 return Collections.unmodifiableList(binder.elements);
118 }
cgruber0910c1e2015-02-18 12:07:13 -0800119
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700120 private static class ElementsAsModule implements Module {
121 private final Iterable<? extends Element> elements;
122
123 ElementsAsModule(Iterable<? extends Element> elements) {
124 this.elements = elements;
125 }
126
cgruber0910c1e2015-02-18 12:07:13 -0800127 @Override
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700128 public void configure(Binder binder) {
129 for (Element element : elements) {
130 element.applyTo(binder);
131 }
132 }
133 }
134
limpbizkitaa07ab02009-05-15 07:10:43 +0000135 /**
136 * Returns the module composed of {@code elements}.
137 */
138 public static Module getModule(final Iterable<? extends Element> elements) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700139 return new ElementsAsModule(elements);
limpbizkitaa07ab02009-05-15 07:10:43 +0000140 }
141
limpbizkit477f9f92008-07-28 07:05:14 +0000142 @SuppressWarnings("unchecked")
limpbizkit7e1e4f72008-08-02 21:21:32 +0000143 static <T> BindingTargetVisitor<T, T> getInstanceVisitor() {
limpbizkitafa4b5d2008-08-02 18:40:47 +0000144 return (BindingTargetVisitor<T, T>) GET_INSTANCE_VISITOR;
limpbizkit477f9f92008-07-28 07:05:14 +0000145 }
146
sameb54da0e32015-02-19 18:36:52 -0800147 private static class ModuleInfo {
148 private final Binder binder;
149 private final ModuleSource moduleSource;
sameb02c489e2015-03-20 12:29:45 -0700150 private final boolean skipScanning;
sameb54da0e32015-02-19 18:36:52 -0800151
sameb02c489e2015-03-20 12:29:45 -0700152 private ModuleInfo(Binder binder, ModuleSource moduleSource, boolean skipScanning) {
sameb54da0e32015-02-19 18:36:52 -0800153 this.binder = binder;
154 this.moduleSource = moduleSource;
sameb02c489e2015-03-20 12:29:45 -0700155 this.skipScanning = skipScanning;
sameb54da0e32015-02-19 18:36:52 -0800156 }
157 }
158
Sam Berlinc34e0182014-08-06 11:56:26 -0400159 private static class RecordingBinder implements Binder, PrivateBinder {
limpbizkit477f9f92008-07-28 07:05:14 +0000160 private final Stage stage;
sameb54da0e32015-02-19 18:36:52 -0800161 private final Map<Module, ModuleInfo> modules;
limpbizkit477f9f92008-07-28 07:05:14 +0000162 private final List<Element> elements;
163 private final Object source;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700164 /** The current modules stack */
165 private ModuleSource moduleSource = null;
limpbizkit477f9f92008-07-28 07:05:14 +0000166 private final SourceProvider sourceProvider;
sameb54da0e32015-02-19 18:36:52 -0800167 private final Set<ModuleAnnotatedMethodScanner> scanners;
limpbizkitfcbdf992008-11-26 02:37:35 +0000168
169 /** The binder where exposed bindings will be created */
170 private final RecordingBinder parent;
limpbizkitc3f92842008-12-30 19:43:47 +0000171 private final PrivateElementsImpl privateElements;
limpbizkit477f9f92008-07-28 07:05:14 +0000172
sameb54da0e32015-02-19 18:36:52 -0800173 /** All children private binders, so we can scan through them. */
174 private final List<RecordingBinder> privateBinders;
175
limpbizkit477f9f92008-07-28 07:05:14 +0000176 private RecordingBinder(Stage stage) {
177 this.stage = stage;
sameb54da0e32015-02-19 18:36:52 -0800178 this.modules = Maps.newLinkedHashMap();
179 this.scanners = Sets.newLinkedHashSet();
limpbizkit477f9f92008-07-28 07:05:14 +0000180 this.elements = Lists.newArrayList();
181 this.source = null;
limpbizkit5ae41eb2009-06-06 17:51:27 +0000182 this.sourceProvider = SourceProvider.DEFAULT_INSTANCE.plusSkippedClasses(
limpbizkit76c24b12008-12-25 04:32:41 +0000183 Elements.class, RecordingBinder.class, AbstractModule.class,
184 ConstantBindingBuilderImpl.class, AbstractBindingBuilder.class, BindingBuilder.class);
limpbizkitfcbdf992008-11-26 02:37:35 +0000185 this.parent = null;
limpbizkitc3f92842008-12-30 19:43:47 +0000186 this.privateElements = null;
sameb54da0e32015-02-19 18:36:52 -0800187 this.privateBinders = Lists.newArrayList();
limpbizkit477f9f92008-07-28 07:05:14 +0000188 }
189
limpbizkitfcbdf992008-11-26 02:37:35 +0000190 /** Creates a recording binder that's backed by {@code prototype}. */
191 private RecordingBinder(
192 RecordingBinder prototype, Object source, SourceProvider sourceProvider) {
limpbizkit477f9f92008-07-28 07:05:14 +0000193 checkArgument(source == null ^ sourceProvider == null);
194
limpbizkitfcbdf992008-11-26 02:37:35 +0000195 this.stage = prototype.stage;
196 this.modules = prototype.modules;
197 this.elements = prototype.elements;
sameb54da0e32015-02-19 18:36:52 -0800198 this.scanners = prototype.scanners;
limpbizkit477f9f92008-07-28 07:05:14 +0000199 this.source = source;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700200 this.moduleSource = prototype.moduleSource;
limpbizkit477f9f92008-07-28 07:05:14 +0000201 this.sourceProvider = sourceProvider;
limpbizkitfcbdf992008-11-26 02:37:35 +0000202 this.parent = prototype.parent;
limpbizkitc3f92842008-12-30 19:43:47 +0000203 this.privateElements = prototype.privateElements;
sameb54da0e32015-02-19 18:36:52 -0800204 this.privateBinders = prototype.privateBinders;
limpbizkit5ea4ab22008-11-25 08:43:49 +0000205 }
206
207 /** Creates a private recording binder. */
limpbizkitc3f92842008-12-30 19:43:47 +0000208 private RecordingBinder(RecordingBinder parent, PrivateElementsImpl privateElements) {
limpbizkit5ea4ab22008-11-25 08:43:49 +0000209 this.stage = parent.stage;
sameb54da0e32015-02-19 18:36:52 -0800210 this.modules = Maps.newLinkedHashMap();
211 this.scanners = Sets.newLinkedHashSet(parent.scanners);
limpbizkitc3f92842008-12-30 19:43:47 +0000212 this.elements = privateElements.getElementsMutable();
limpbizkit5ea4ab22008-11-25 08:43:49 +0000213 this.source = parent.source;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700214 this.moduleSource = parent.moduleSource;
limpbizkit5ea4ab22008-11-25 08:43:49 +0000215 this.sourceProvider = parent.sourceProvider;
limpbizkitfcbdf992008-11-26 02:37:35 +0000216 this.parent = parent;
limpbizkitc3f92842008-12-30 19:43:47 +0000217 this.privateElements = privateElements;
sameb54da0e32015-02-19 18:36:52 -0800218 this.privateBinders = parent.privateBinders;
limpbizkit477f9f92008-07-28 07:05:14 +0000219 }
220
limpbizkitbf0d8762009-02-19 09:06:22 +0000221 /*if[AOP]*/
cgruber0910c1e2015-02-18 12:07:13 -0800222 @Override
limpbizkit477f9f92008-07-28 07:05:14 +0000223 public void bindInterceptor(
224 Matcher<? super Class<?>> classMatcher,
225 Matcher<? super Method> methodMatcher,
limpbizkit4f6274a2009-02-19 21:57:55 +0000226 org.aopalliance.intercept.MethodInterceptor... interceptors) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700227 elements.add(new InterceptorBinding(
228 getElementSource(), classMatcher, methodMatcher, interceptors));
limpbizkit477f9f92008-07-28 07:05:14 +0000229 }
limpbizkitbf0d8762009-02-19 09:06:22 +0000230 /*end[AOP]*/
limpbizkit477f9f92008-07-28 07:05:14 +0000231
cgruber0910c1e2015-02-18 12:07:13 -0800232 @Override
limpbizkit477f9f92008-07-28 07:05:14 +0000233 public void bindScope(Class<? extends Annotation> annotationType, Scope scope) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700234 elements.add(new ScopeBinding(getElementSource(), annotationType, scope));
limpbizkit477f9f92008-07-28 07:05:14 +0000235 }
236
cgruber0910c1e2015-02-18 12:07:13 -0800237 @Override
limpbizkit03b81a62009-03-18 05:34:39 +0000238 @SuppressWarnings("unchecked") // it is safe to use the type literal for the raw type
239 public void requestInjection(Object instance) {
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700240 requestInjection((TypeLiteral<Object>) TypeLiteral.get(instance.getClass()), instance);
limpbizkit03b81a62009-03-18 05:34:39 +0000241 }
242
cgruber0910c1e2015-02-18 12:07:13 -0800243 @Override
limpbizkit03b81a62009-03-18 05:34:39 +0000244 public <T> void requestInjection(TypeLiteral<T> type, T instance) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700245 elements.add(new InjectionRequest<T>(getElementSource(), type, instance));
limpbizkit03b81a62009-03-18 05:34:39 +0000246 }
247
cgruber0910c1e2015-02-18 12:07:13 -0800248 @Override
limpbizkit97eac0f2009-03-28 18:25:35 +0000249 public <T> MembersInjector<T> getMembersInjector(final TypeLiteral<T> typeLiteral) {
250 final MembersInjectorLookup<T> element
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700251 = new MembersInjectorLookup<T>(getElementSource(), typeLiteral);
limpbizkit97eac0f2009-03-28 18:25:35 +0000252 elements.add(element);
limpbizkit8d620752009-03-31 22:37:26 +0000253 return element.getMembersInjector();
limpbizkit03b81a62009-03-18 05:34:39 +0000254 }
255
256 public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
limpbizkit97eac0f2009-03-28 18:25:35 +0000257 return getMembersInjector(TypeLiteral.get(type));
limpbizkit03b81a62009-03-18 05:34:39 +0000258 }
259
limpbizkita843a952009-04-08 22:24:55 +0000260 public void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700261 elements.add(new TypeListenerBinding(getElementSource(), listener, typeMatcher));
limpbizkit477f9f92008-07-28 07:05:14 +0000262 }
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700263
Sam Berlind51292d2012-02-26 21:23:19 -0500264 public void bindListener(Matcher<? super Binding<?>> bindingMatcher,
265 ProvisionListener... listeners) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700266 elements.add(new ProvisionListenerBinding(getElementSource(), bindingMatcher, listeners));
sberlin132a5db2011-06-05 18:32:05 +0000267 }
limpbizkit477f9f92008-07-28 07:05:14 +0000268
269 public void requestStaticInjection(Class<?>... types) {
limpbizkitb3a8f0b2008-09-05 22:30:40 +0000270 for (Class<?> type : types) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700271 elements.add(new StaticInjectionRequest(getElementSource(), type));
limpbizkitb3a8f0b2008-09-05 22:30:40 +0000272 }
limpbizkit477f9f92008-07-28 07:05:14 +0000273 }
274
sameb02c489e2015-03-20 12:29:45 -0700275 /**
276 * Applies all scanners to the modules we've installed. We skip certain
277 * PrivateModules because store them in more than one Modules map and only
278 * want to process them through one of the maps. (They're stored in both
279 * maps to prevent a module from being installed more than once.)
280 */
sameb54da0e32015-02-19 18:36:52 -0800281 void scanForAnnotatedMethods() {
282 for (ModuleAnnotatedMethodScanner scanner : scanners) {
283 // Note: we must iterate over a copy of the modules because calling install(..)
284 // will mutate modules, otherwise causing a ConcurrentModificationException.
285 for (Map.Entry<Module, ModuleInfo> entry : Maps.newLinkedHashMap(modules).entrySet()) {
286 Module module = entry.getKey();
sameb02c489e2015-03-20 12:29:45 -0700287 ModuleInfo info = entry.getValue();
288 if (info.skipScanning) {
sameb54da0e32015-02-19 18:36:52 -0800289 continue;
290 }
291 moduleSource = entry.getValue().moduleSource;
292 try {
sameb02c489e2015-03-20 12:29:45 -0700293 info.binder.install(ProviderMethodsModule.forModule(module, scanner));
sameb54da0e32015-02-19 18:36:52 -0800294 } catch(RuntimeException e) {
295 Collection<Message> messages = Errors.getMessagesFromThrowable(e);
296 if (!messages.isEmpty()) {
297 elements.addAll(messages);
298 } else {
299 addError(e);
300 }
301 }
302 }
303 }
304 moduleSource = null;
305 }
306
limpbizkit477f9f92008-07-28 07:05:14 +0000307 public void install(Module module) {
sameb54da0e32015-02-19 18:36:52 -0800308 if (!modules.containsKey(module)) {
sameb02c489e2015-03-20 12:29:45 -0700309 RecordingBinder binder = this;
sameb7445e442015-02-10 15:37:44 -0800310 boolean unwrapModuleSource = false;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700311 // Update the module source for the new module
cgruber0910c1e2015-02-18 12:07:13 -0800312 if (module instanceof ProviderMethodsModule) {
sameb7445e442015-02-10 15:37:44 -0800313 // There are two reason's we'd want to get the module source in a ProviderMethodsModule.
314 // ModuleAnnotatedMethodScanner lets users scan their own modules for @Provides-like
315 // bindings. If they install the module at a top-level, then moduleSource can be null.
316 // Also, if they pass something other than 'this' to it, we'd have the wrong source.
cgruber0910c1e2015-02-18 12:07:13 -0800317 Object delegate = ((ProviderMethodsModule) module).getDelegateModule();
318 if (moduleSource == null
319 || !moduleSource.getModuleClassName().equals(delegate.getClass().getName())) {
sameb7445e442015-02-10 15:37:44 -0800320 moduleSource = getModuleSource(delegate);
321 unwrapModuleSource = true;
322 }
cgruber0910c1e2015-02-18 12:07:13 -0800323 } else {
324 moduleSource = getModuleSource(module);
325 unwrapModuleSource = true;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700326 }
sameb02c489e2015-03-20 12:29:45 -0700327 boolean skipScanning = false;
limpbizkitfcbdf992008-11-26 02:37:35 +0000328 if (module instanceof PrivateModule) {
sameb02c489e2015-03-20 12:29:45 -0700329 binder = (RecordingBinder) binder.newPrivateBinder();
330 // Store the module in the private binder too so we scan for it.
331 binder.modules.put(module, new ModuleInfo(binder, moduleSource, false));
332 skipScanning = true; // don't scan this module in the parent's module set.
sameb7445e442015-02-10 15:37:44 -0800333 }
sameb54da0e32015-02-19 18:36:52 -0800334 // Always store this in the parent binder (even if it was a private module)
335 // so that we know not to process it again, and so that scanners inherit down.
sameb02c489e2015-03-20 12:29:45 -0700336 modules.put(module, new ModuleInfo(binder, moduleSource, skipScanning));
limpbizkit477f9f92008-07-28 07:05:14 +0000337 try {
limpbizkitfcbdf992008-11-26 02:37:35 +0000338 module.configure(binder);
limpbizkit477f9f92008-07-28 07:05:14 +0000339 } catch (RuntimeException e) {
limpbizkit72d11dd2008-11-02 07:59:13 +0000340 Collection<Message> messages = Errors.getMessagesFromThrowable(e);
341 if (!messages.isEmpty()) {
342 elements.addAll(messages);
343 } else {
344 addError(e);
345 }
limpbizkit477f9f92008-07-28 07:05:14 +0000346 }
limpbizkitfcbdf992008-11-26 02:37:35 +0000347 binder.install(ProviderMethodsModule.forModule(module));
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700348 // We are done with this module, so undo module source change
sameb7445e442015-02-10 15:37:44 -0800349 if (unwrapModuleSource) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700350 moduleSource = moduleSource.getParent();
351 }
limpbizkit477f9f92008-07-28 07:05:14 +0000352 }
353 }
354
355 public Stage currentStage() {
356 return stage;
357 }
358
359 public void addError(String message, Object... arguments) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700360 elements.add(new Message(getElementSource(), Errors.format(message, arguments)));
limpbizkit477f9f92008-07-28 07:05:14 +0000361 }
362
363 public void addError(Throwable t) {
limpbizkitb3a8f0b2008-09-05 22:30:40 +0000364 String message = "An exception was caught and reported. Message: " + t.getMessage();
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700365 elements.add(new Message(ImmutableList.of((Object) getElementSource()), message, t));
limpbizkit477f9f92008-07-28 07:05:14 +0000366 }
367
368 public void addError(Message message) {
369 elements.add(message);
370 }
371
limpbizkitd1fe1302008-08-01 06:40:18 +0000372 public <T> AnnotatedBindingBuilder<T> bind(Key<T> key) {
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700373 BindingBuilder<T> builder = new BindingBuilder<T>(this, elements, getElementSource(), key);
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700374 return builder;
limpbizkit477f9f92008-07-28 07:05:14 +0000375 }
376
377 public <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
378 return bind(Key.get(typeLiteral));
379 }
380
381 public <T> AnnotatedBindingBuilder<T> bind(Class<T> type) {
382 return bind(Key.get(type));
383 }
384
385 public AnnotatedConstantBindingBuilder bindConstant() {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700386 return new ConstantBindingBuilderImpl<Void>(this, elements, getElementSource());
limpbizkit477f9f92008-07-28 07:05:14 +0000387 }
388
389 public <T> Provider<T> getProvider(final Key<T> key) {
sameb9867f9c2015-02-02 12:45:25 -0800390 return getProvider(Dependency.get(key));
391 }
392
393 public <T> Provider<T> getProvider(final Dependency<T> dependency) {
394 final ProviderLookup<T> element = new ProviderLookup<T>(getElementSource(), dependency);
limpbizkit97eac0f2009-03-28 18:25:35 +0000395 elements.add(element);
limpbizkit8d620752009-03-31 22:37:26 +0000396 return element.getProvider();
limpbizkit477f9f92008-07-28 07:05:14 +0000397 }
398
399 public <T> Provider<T> getProvider(Class<T> type) {
400 return getProvider(Key.get(type));
401 }
402
403 public void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
404 TypeConverter converter) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700405 elements.add(new TypeConverterBinding(getElementSource(), typeMatcher, converter));
limpbizkit477f9f92008-07-28 07:05:14 +0000406 }
407
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700408 public RecordingBinder withSource(final Object source) {
Sam Berlinc5848c02013-12-06 17:05:44 -0500409 return source == this.source ? this : new RecordingBinder(this, source, null);
limpbizkit477f9f92008-07-28 07:05:14 +0000410 }
411
limpbizkit5ea4ab22008-11-25 08:43:49 +0000412 public RecordingBinder skipSources(Class... classesToSkip) {
limpbizkit477f9f92008-07-28 07:05:14 +0000413 // if a source is specified explicitly, we don't need to skip sources
414 if (source != null) {
415 return this;
416 }
417
418 SourceProvider newSourceProvider = sourceProvider.plusSkippedClasses(classesToSkip);
419 return new RecordingBinder(this, null, newSourceProvider);
420 }
421
cgruber0910c1e2015-02-18 12:07:13 -0800422 @Override
limpbizkit5ea4ab22008-11-25 08:43:49 +0000423 public PrivateBinder newPrivateBinder() {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700424 PrivateElementsImpl privateElements = new PrivateElementsImpl(getElementSource());
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700425 RecordingBinder binder = new RecordingBinder(this, privateElements);
sameb54da0e32015-02-19 18:36:52 -0800426 privateBinders.add(binder);
limpbizkitc3f92842008-12-30 19:43:47 +0000427 elements.add(privateElements);
Christian Edward Gruber96e81ba2013-09-18 10:55:21 -0700428 return binder;
limpbizkit5ea4ab22008-11-25 08:43:49 +0000429 }
cgruber0910c1e2015-02-18 12:07:13 -0800430
431 @Override
sberlin8b64d452010-12-13 02:44:36 +0000432 public void disableCircularProxies() {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700433 elements.add(new DisableCircularProxiesOption(getElementSource()));
sberlin8b64d452010-12-13 02:44:36 +0000434 }
cgruber0910c1e2015-02-18 12:07:13 -0800435
436 @Override
sberlin8b64d452010-12-13 02:44:36 +0000437 public void requireExplicitBindings() {
cgruber0910c1e2015-02-18 12:07:13 -0800438 elements.add(new RequireExplicitBindingsOption(getElementSource()));
sberlin8b64d452010-12-13 02:44:36 +0000439 }
cgruber0910c1e2015-02-18 12:07:13 -0800440
441 @Override
Sam Berlinc7567772012-05-31 19:54:04 -0400442 public void requireAtInjectOnConstructors() {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700443 elements.add(new RequireAtInjectOnConstructorsOption(getElementSource()));
Sam Berlinc7567772012-05-31 19:54:04 -0400444 }
limpbizkit5ea4ab22008-11-25 08:43:49 +0000445
cgruber0910c1e2015-02-18 12:07:13 -0800446 @Override
Christian Edward Grubere3915852013-05-16 11:00:54 -0700447 public void requireExactBindingAnnotations() {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700448 elements.add(new RequireExactBindingAnnotationsOption(getElementSource()));
Christian Edward Grubere3915852013-05-16 11:00:54 -0700449 }
450
cgruber0910c1e2015-02-18 12:07:13 -0800451 @Override
sameb54da0e32015-02-19 18:36:52 -0800452 public void scanModulesForAnnotatedMethods(ModuleAnnotatedMethodScanner scanner) {
453 scanners.add(scanner);
454 elements.add(new ModuleAnnotatedMethodScannerBinding(getElementSource(), scanner));
455 }
456
limpbizkit4994bf62008-12-27 02:54:59 +0000457 public void expose(Key<?> key) {
458 exposeInternal(key);
limpbizkit5ea4ab22008-11-25 08:43:49 +0000459 }
460
cgruber0910c1e2015-02-18 12:07:13 -0800461 @Override
limpbizkit5ea4ab22008-11-25 08:43:49 +0000462 public AnnotatedElementBuilder expose(Class<?> type) {
463 return exposeInternal(Key.get(type));
464 }
465
cgruber0910c1e2015-02-18 12:07:13 -0800466 @Override
limpbizkit5ea4ab22008-11-25 08:43:49 +0000467 public AnnotatedElementBuilder expose(TypeLiteral<?> type) {
468 return exposeInternal(Key.get(type));
469 }
470
limpbizkitfcbdf992008-11-26 02:37:35 +0000471 private <T> AnnotatedElementBuilder exposeInternal(Key<T> key) {
limpbizkitc3f92842008-12-30 19:43:47 +0000472 if (privateElements == null) {
limpbizkitb1f42f52008-11-26 07:44:53 +0000473 addError("Cannot expose %s on a standard binder. "
474 + "Exposed bindings are only applicable to private binders.", key);
475 return new AnnotatedElementBuilder() {
cgruber0910c1e2015-02-18 12:07:13 -0800476 @Override
limpbizkitb1f42f52008-11-26 07:44:53 +0000477 public void annotatedWith(Class<? extends Annotation> annotationType) {}
cgruber0910c1e2015-02-18 12:07:13 -0800478 @Override
limpbizkitb1f42f52008-11-26 07:44:53 +0000479 public void annotatedWith(Annotation annotation) {}
480 };
limpbizkit5ea4ab22008-11-25 08:43:49 +0000481 }
482
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700483 ExposureBuilder<T> builder = new ExposureBuilder<T>(this, getElementSource(), key);
limpbizkitc3f92842008-12-30 19:43:47 +0000484 privateElements.addExposureBuilder(builder);
limpbizkitfcbdf992008-11-26 02:37:35 +0000485 return builder;
limpbizkit5ea4ab22008-11-25 08:43:49 +0000486 }
487
cgruber0910c1e2015-02-18 12:07:13 -0800488 private ModuleSource getModuleSource(Object module) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700489 StackTraceElement[] partialCallStack;
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700490 if (getIncludeStackTraceOption() == IncludeStackTraceOption.COMPLETE) {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700491 partialCallStack = getPartialCallStack(new Throwable().getStackTrace());
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700492 } else {
493 partialCallStack = new StackTraceElement[0];
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700494 }
495 if (moduleSource == null) {
496 return new ModuleSource(module, partialCallStack);
497 }
498 return moduleSource.createChild(module, partialCallStack);
499 }
500
501 private ElementSource getElementSource() {
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700502 // Full call stack
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700503 StackTraceElement[] callStack = null;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700504 // The call stack starts from current top module configure and ends at this method caller
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700505 StackTraceElement[] partialCallStack = new StackTraceElement[0];
506 // The element original source
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700507 ElementSource originalSource = null;
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700508 // The element declaring source
509 Object declaringSource = source;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700510 if (declaringSource instanceof ElementSource) {
511 originalSource = (ElementSource) declaringSource;
512 declaringSource = originalSource.getDeclaringSource();
513 }
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700514 IncludeStackTraceOption stackTraceOption = getIncludeStackTraceOption();
515 if (stackTraceOption == IncludeStackTraceOption.COMPLETE ||
cgruber0910c1e2015-02-18 12:07:13 -0800516 (stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700517 && declaringSource == null)) {
518 callStack = new Throwable().getStackTrace();
519 }
520 if (stackTraceOption == IncludeStackTraceOption.COMPLETE) {
521 partialCallStack = getPartialCallStack(callStack);
522 }
523 if (declaringSource == null) {
524 // So 'source' and 'originalSource' are null otherwise declaringSource has some value
525 if (stackTraceOption == IncludeStackTraceOption.COMPLETE ||
526 stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE) {
527 // With the above conditions and assignments 'callStack' is non-null
528 declaringSource = sourceProvider.get(callStack);
529 } else { // or if (stackTraceOption == IncludeStackTraceOptions.OFF)
530 // As neither 'declaring source' nor 'call stack' is available use 'module source'
531 declaringSource = sourceProvider.getFromClassNames(moduleSource.getModuleClassNames());
532 }
533 }
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700534 // Build the binding call stack
535 return new ElementSource(
536 originalSource, declaringSource, moduleSource, partialCallStack);
537 }
538
539 /**
cgruber0910c1e2015-02-18 12:07:13 -0800540 * Removes the {@link #moduleSource} call stack from the beginning of current call stack. It
541 * also removes the last two elements in order to make {@link #install(Module)} the last call
542 * in the call stack.
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700543 */
544 private StackTraceElement[] getPartialCallStack(StackTraceElement[] callStack) {
545 int toSkip = 0;
546 if (moduleSource != null) {
547 toSkip = moduleSource.getStackTraceSize();
548 }
549 // -1 for skipping 'getModuleSource' and 'getElementSource' calls
550 int chunkSize = callStack.length - toSkip - 1;
551
552 StackTraceElement[] partialCallStack = new StackTraceElement[chunkSize];
553 System.arraycopy(callStack, 1, partialCallStack, 0, chunkSize);
554 return partialCallStack;
limpbizkit477f9f92008-07-28 07:05:14 +0000555 }
cgruber0910c1e2015-02-18 12:07:13 -0800556
limpbizkit477f9f92008-07-28 07:05:14 +0000557 @Override public String toString() {
558 return "Binder";
559 }
560 }
561}