blob: 87e0cc876cf7b2bf23ae2681f31cc9e1177f469d [file] [log] [blame]
limpbizkit564053f2008-06-15 11:21:18 +00001/**
2 * Copyright (C) 2006 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.inject.internal;
18
sberlinb7a02b02011-07-08 00:34:16 +000019import com.google.common.collect.ImmutableList;
20import com.google.common.collect.ImmutableSet;
21import com.google.common.collect.Lists;
Sam Berlinc00df282014-07-01 16:53:41 -040022import com.google.common.collect.Ordering;
limpbizkit490833f2008-11-02 00:12:39 +000023import com.google.inject.ConfigurationException;
limpbizkit564053f2008-06-15 11:21:18 +000024import com.google.inject.CreationException;
sameb9867f9c2015-02-02 12:45:25 -080025import com.google.inject.Guice;
limpbizkit564053f2008-06-15 11:21:18 +000026import com.google.inject.Key;
limpbizkitee792462009-04-08 23:48:49 +000027import com.google.inject.MembersInjector;
limpbizkit564053f2008-06-15 11:21:18 +000028import com.google.inject.Provider;
sameb9867f9c2015-02-02 12:45:25 -080029import com.google.inject.Provides;
limpbizkit490833f2008-11-02 00:12:39 +000030import com.google.inject.ProvisionException;
limpbizkit564053f2008-06-15 11:21:18 +000031import com.google.inject.Scope;
32import com.google.inject.TypeLiteral;
sberlindfee9fd2010-10-30 14:15:06 +000033import com.google.inject.internal.util.Classes;
limpbizkit@gmail.com9a227be2010-07-03 15:51:31 +000034import com.google.inject.internal.util.SourceProvider;
35import com.google.inject.internal.util.StackTraceElements;
limpbizkita98bc7a2008-08-29 16:52:44 +000036import com.google.inject.spi.Dependency;
Christian Edward Gruber605bd082013-08-09 11:04:00 -070037import com.google.inject.spi.ElementSource;
limpbizkit516e2ab2009-03-26 22:01:18 +000038import com.google.inject.spi.InjectionListener;
limpbizkit564053f2008-06-15 11:21:18 +000039import com.google.inject.spi.InjectionPoint;
40import com.google.inject.spi.Message;
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -070041import com.google.inject.spi.ScopeBinding;
sberlinb2f17602010-11-19 02:33:32 +000042import com.google.inject.spi.TypeConverterBinding;
limpbizkitee792462009-04-08 23:48:49 +000043import com.google.inject.spi.TypeListenerBinding;
sberlinb7a02b02011-07-08 00:34:16 +000044
limpbizkit490833f2008-11-02 00:12:39 +000045import java.io.PrintWriter;
limpbizkit564053f2008-06-15 11:21:18 +000046import java.io.Serializable;
limpbizkit490833f2008-11-02 00:12:39 +000047import java.io.StringWriter;
limpbizkit564053f2008-06-15 11:21:18 +000048import java.lang.annotation.Annotation;
49import java.lang.reflect.Constructor;
50import java.lang.reflect.Field;
51import java.lang.reflect.Member;
limpbizkitb47d75a2009-09-08 00:17:45 +000052import java.lang.reflect.Method;
limpbizkitb0f3c9b2008-11-15 09:19:28 +000053import java.lang.reflect.Type;
limpbizkit564053f2008-06-15 11:21:18 +000054import java.util.Collection;
limpbizkit564053f2008-06-15 11:21:18 +000055import java.util.Formatter;
limpbizkitb3a8f0b2008-09-05 22:30:40 +000056import java.util.List;
sberlincc17f142011-02-27 00:02:03 +000057import java.util.Set;
sameb9867f9c2015-02-02 12:45:25 -080058import java.util.logging.Level;
59import java.util.logging.Logger;
limpbizkit564053f2008-06-15 11:21:18 +000060
61/**
limpbizkit163c48a2008-06-16 02:58:08 +000062 * A collection of error messages. If this type is passed as a method parameter, the method is
sberlinb2f17602010-11-19 02:33:32 +000063 * considered to have executed successfully only if new errors were not added to this collection.
limpbizkit564053f2008-06-15 11:21:18 +000064 *
limpbizkit06898062008-11-02 05:14:55 +000065 * <p>Errors can be chained to provide additional context. To add context, call {@link #withSource}
66 * to create a new Errors instance that contains additional context. All messages added to the
67 * returned instance will contain full context.
68 *
69 * <p>To avoid messages with redundant context, {@link #withSource} should be added sparingly. A
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -070070 * good rule of thumb is to assume a method's caller has already specified enough context to
limpbizkit06898062008-11-02 05:14:55 +000071 * identify that method. When calling a method that's defined in a different context, call that
72 * method with an errors object that includes its context.
73 *
limpbizkit163c48a2008-06-16 02:58:08 +000074 * @author jessewilson@google.com (Jesse Wilson)
limpbizkit564053f2008-06-15 11:21:18 +000075 */
76public final class Errors implements Serializable {
77
sameb9867f9c2015-02-02 12:45:25 -080078 private static final Logger logger = Logger.getLogger(Guice.class.getName());
79
sberlina23937e2011-06-29 22:02:50 +000080
limpbizkite89c49e2009-05-06 01:02:14 +000081 /**
82 * The root errors object. Used to access the list of error messages.
83 */
84 private final Errors root;
85
86 /**
87 * The parent errors object. Used to obtain the chain of source objects.
88 */
limpbizkit06898062008-11-02 05:14:55 +000089 private final Errors parent;
limpbizkite89c49e2009-05-06 01:02:14 +000090
91 /**
92 * The leaf source for errors added here.
93 */
limpbizkit06898062008-11-02 05:14:55 +000094 private final Object source;
limpbizkit2c2c6102008-06-20 13:34:36 +000095
limpbizkite89c49e2009-05-06 01:02:14 +000096 /**
97 * null unless (root == this) and error messages exist. Never an empty list.
98 */
99 private List<Message> errors; // lazy, use getErrorsForAdd()
100
limpbizkit2c2c6102008-06-20 13:34:36 +0000101 public Errors() {
limpbizkite89c49e2009-05-06 01:02:14 +0000102 this.root = this;
limpbizkit06898062008-11-02 05:14:55 +0000103 this.parent = null;
104 this.source = SourceProvider.UNKNOWN_SOURCE;
limpbizkit2c2c6102008-06-20 13:34:36 +0000105 }
106
107 public Errors(Object source) {
limpbizkite89c49e2009-05-06 01:02:14 +0000108 this.root = this;
limpbizkit06898062008-11-02 05:14:55 +0000109 this.parent = null;
110 this.source = source;
limpbizkit2c2c6102008-06-20 13:34:36 +0000111 }
112
limpbizkita6e0e782008-09-03 06:19:56 +0000113 private Errors(Errors parent, Object source) {
limpbizkite89c49e2009-05-06 01:02:14 +0000114 this.root = parent.root;
limpbizkit06898062008-11-02 05:14:55 +0000115 this.parent = parent;
116 this.source = source;
limpbizkita6e0e782008-09-03 06:19:56 +0000117 }
118
119 /**
120 * Returns an instance that uses {@code source} as a reference point for newly added errors.
121 */
122 public Errors withSource(Object source) {
Sam Berlinc5848c02013-12-06 17:05:44 -0500123 return source == this.source || source == SourceProvider.UNKNOWN_SOURCE
limpbizkita6e0e782008-09-03 06:19:56 +0000124 ? this
125 : new Errors(this, source);
126 }
127
limpbizkit564053f2008-06-15 11:21:18 +0000128 /**
129 * We use a fairly generic error message here. The motivation is to share the
130 * same message for both bind time errors:
131 * <pre><code>Guice.createInjector(new AbstractModule() {
132 * public void configure() {
133 * bind(Runnable.class);
134 * }
135 * }</code></pre>
136 * ...and at provide-time errors:
137 * <pre><code>Guice.createInjector().getInstance(Runnable.class);</code></pre>
138 * Otherwise we need to know who's calling when resolving a just-in-time
139 * binding, which makes things unnecessarily complex.
140 */
limpbizkit06898062008-11-02 05:14:55 +0000141 public Errors missingImplementation(Key key) {
142 return addMessage("No implementation for %s was bound.", key);
limpbizkit564053f2008-06-15 11:21:18 +0000143 }
sberlina23937e2011-06-29 22:02:50 +0000144
sberlin888a2642010-02-11 22:07:07 +0000145 public Errors jitDisabled(Key key) {
146 return addMessage("Explicit bindings are required and %s is not explicitly bound.", key);
147 }
limpbizkit564053f2008-06-15 11:21:18 +0000148
Tavian Barnes1dd0a912014-12-19 22:38:50 -0500149 public Errors jitDisabledInParent(Key<?> key) {
Tavian Barnes6c9726f2015-01-07 10:37:17 -0500150 return addMessage(
151 "Explicit bindings are required and %s would be bound in a parent injector.%n"
152 + "Please add an explicit binding for it, either in the child or the parent.",
153 key);
Tavian Barnes1dd0a912014-12-19 22:38:50 -0500154 }
155
Sam Berlinc7567772012-05-31 19:54:04 -0400156 public Errors atInjectRequired(Class clazz) {
157 return addMessage(
158 "Explicit @Inject annotations are required on constructors,"
159 + " but %s has no constructors annotated with @Inject.",
160 clazz);
161 }
162
limpbizkitc5c488e2008-06-16 01:42:25 +0000163 public Errors converterReturnedNull(String stringValue, Object source,
sberlinb2f17602010-11-19 02:33:32 +0000164 TypeLiteral<?> type, TypeConverterBinding typeConverterBinding) {
limpbizkitc5c488e2008-06-16 01:42:25 +0000165 return addMessage("Received null converting '%s' (bound at %s) to %s%n"
166 + " using %s.",
sberlinb2f17602010-11-19 02:33:32 +0000167 stringValue, convert(source), type, typeConverterBinding);
limpbizkit564053f2008-06-15 11:21:18 +0000168 }
169
limpbizkitc5c488e2008-06-16 01:42:25 +0000170 public Errors conversionTypeError(String stringValue, Object source, TypeLiteral<?> type,
sberlinb2f17602010-11-19 02:33:32 +0000171 TypeConverterBinding typeConverterBinding, Object converted) {
limpbizkitc5c488e2008-06-16 01:42:25 +0000172 return addMessage("Type mismatch converting '%s' (bound at %s) to %s%n"
173 + " using %s.%n"
174 + " Converter returned %s.",
sberlinb2f17602010-11-19 02:33:32 +0000175 stringValue, convert(source), type, typeConverterBinding, converted);
limpbizkit564053f2008-06-15 11:21:18 +0000176 }
177
178 public Errors conversionError(String stringValue, Object source,
sberlinb2f17602010-11-19 02:33:32 +0000179 TypeLiteral<?> type, TypeConverterBinding typeConverterBinding, RuntimeException cause) {
limpbizkit516e2ab2009-03-26 22:01:18 +0000180 return errorInUserCode(cause, "Error converting '%s' (bound at %s) to %s%n"
limpbizkitc5c488e2008-06-16 01:42:25 +0000181 + " using %s.%n"
182 + " Reason: %s",
sberlinb2f17602010-11-19 02:33:32 +0000183 stringValue, convert(source), type, typeConverterBinding, cause);
limpbizkit564053f2008-06-15 11:21:18 +0000184 }
185
limpbizkit163c48a2008-06-16 02:58:08 +0000186 public Errors ambiguousTypeConversion(String stringValue, Object source, TypeLiteral<?> type,
sberlinb2f17602010-11-19 02:33:32 +0000187 TypeConverterBinding a, TypeConverterBinding b) {
limpbizkit163c48a2008-06-16 02:58:08 +0000188 return addMessage("Multiple converters can convert '%s' (bound at %s) to %s:%n"
189 + " %s and%n"
190 + " %s.%n"
191 + " Please adjust your type converter configuration to avoid overlapping matches.",
limpbizkit06898062008-11-02 05:14:55 +0000192 stringValue, convert(source), type, a, b);
limpbizkit564053f2008-06-15 11:21:18 +0000193 }
194
195 public Errors bindingToProvider() {
196 return addMessage("Binding to Provider is not allowed.");
197 }
198
199 public Errors subtypeNotProvided(Class<? extends Provider<?>> providerType,
200 Class<?> type) {
201 return addMessage("%s doesn't provide instances of %s.", providerType, type);
202 }
203
204 public Errors notASubtype(Class<?> implementationType, Class<?> type) {
205 return addMessage("%s doesn't extend %s.", implementationType, type);
206 }
207
208 public Errors recursiveImplementationType() {
209 return addMessage("@ImplementedBy points to the same class it annotates.");
210 }
211
212 public Errors recursiveProviderType() {
213 return addMessage("@ProvidedBy points to the same class it annotates.");
214 }
215
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700216 public Errors missingRuntimeRetention(Class<? extends Annotation> annotation) {
217 return addMessage(format("Please annotate %s with @Retention(RUNTIME).", annotation));
limpbizkit564053f2008-06-15 11:21:18 +0000218 }
219
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700220 public Errors missingScopeAnnotation(Class<? extends Annotation> annotation) {
221 return addMessage(format("Please annotate %s with @ScopeAnnotation.", annotation));
limpbizkit564053f2008-06-15 11:21:18 +0000222 }
223
224 public Errors optionalConstructor(Constructor constructor) {
225 return addMessage("%s is annotated @Inject(optional=true), "
226 + "but constructors cannot be optional.", constructor);
227 }
228
229 public Errors cannotBindToGuiceType(String simpleName) {
230 return addMessage("Binding to core guice framework type is not allowed: %s.", simpleName);
231 }
232
limpbizkit564053f2008-06-15 11:21:18 +0000233 public Errors scopeNotFound(Class<? extends Annotation> scopeAnnotation) {
234 return addMessage("No scope is bound to %s.", scopeAnnotation);
235 }
236
limpbizkit185d2a22008-06-16 07:22:47 +0000237 public Errors scopeAnnotationOnAbstractType(
238 Class<? extends Annotation> scopeAnnotation, Class<?> type, Object source) {
239 return addMessage("%s is annotated with %s, but scope annotations are not supported "
limpbizkit06898062008-11-02 05:14:55 +0000240 + "for abstract types.%n Bound at %s.", type, scopeAnnotation, convert(source));
limpbizkit185d2a22008-06-16 07:22:47 +0000241 }
242
243 public Errors misplacedBindingAnnotation(Member member, Annotation bindingAnnotation) {
244 return addMessage("%s is annotated with %s, but binding annotations should be applied "
245 + "to its parameters instead.", member, bindingAnnotation);
246 }
247
limpbizkit564053f2008-06-15 11:21:18 +0000248 private static final String CONSTRUCTOR_RULES =
249 "Classes must have either one (and only one) constructor "
limpbizkitd37c58b2008-06-29 23:00:47 +0000250 + "annotated with @Inject or a zero-argument constructor that is not private.";
limpbizkit564053f2008-06-15 11:21:18 +0000251
252 public Errors missingConstructor(Class<?> implementation) {
253 return addMessage("Could not find a suitable constructor in %s. " + CONSTRUCTOR_RULES,
254 implementation);
255 }
256
257 public Errors tooManyConstructors(Class<?> implementation) {
258 return addMessage("%s has more than one constructor annotated with @Inject. "
259 + CONSTRUCTOR_RULES, implementation);
260 }
261
limpbizkit9b8bdc72009-06-07 19:37:28 +0000262 public Errors constructorNotDefinedByType(Constructor<?> constructor, TypeLiteral<?> type) {
263 return addMessage("%s does not define %s", type, constructor);
264 }
265
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700266 public Errors duplicateScopes(ScopeBinding existing,
limpbizkit564053f2008-06-15 11:21:18 +0000267 Class<? extends Annotation> annotationType, Scope scope) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700268 return addMessage("Scope %s is already bound to %s at %s.%n Cannot bind %s.",
269 existing.getScope(), annotationType, existing.getSource(), scope);
limpbizkit564053f2008-06-15 11:21:18 +0000270 }
271
limpbizkit759662b2009-04-26 21:00:24 +0000272 public Errors voidProviderMethod() {
273 return addMessage("Provider methods must return a value. Do not return void.");
274 }
275
limpbizkit564053f2008-06-15 11:21:18 +0000276 public Errors missingConstantValues() {
277 return addMessage("Missing constant value. Please call to(...).");
278 }
279
280 public Errors cannotInjectInnerClass(Class<?> type) {
281 return addMessage("Injecting into inner classes is not supported. "
282 + "Please use a 'static' class (top-level or nested) instead of %s.", type);
283 }
284
285 public Errors duplicateBindingAnnotations(Member member,
286 Class<? extends Annotation> a, Class<? extends Annotation> b) {
287 return addMessage("%s has more than one annotation annotated with @BindingAnnotation: "
288 + "%s and %s", member, a, b);
289 }
290
guice.mirrorbot@gmail.comee443bc2011-09-09 21:19:11 +0000291 public Errors staticInjectionOnInterface(Class<?> clazz) {
292 return addMessage("%s is an interface, but interfaces have no static injection points.", clazz);
293 }
294
limpbizkitb47d75a2009-09-08 00:17:45 +0000295 public Errors cannotInjectFinalField(Field field) {
296 return addMessage("Injected field %s cannot be final.", field);
297 }
298
299 public Errors cannotInjectAbstractMethod(Method method) {
300 return addMessage("Injected method %s cannot be abstract.", method);
301 }
302
303 public Errors cannotInjectNonVoidMethod(Method method) {
304 return addMessage("Injected method %s must return void.", method);
305 }
306
307 public Errors cannotInjectMethodWithTypeParameters(Method method) {
308 return addMessage("Injected method %s cannot declare type parameters of its own.", method);
309 }
310
limpbizkit564053f2008-06-15 11:21:18 +0000311 public Errors duplicateScopeAnnotations(
312 Class<? extends Annotation> a, Class<? extends Annotation> b) {
limpbizkitb1f42f52008-11-26 07:44:53 +0000313 return addMessage("More than one scope annotation was found: %s and %s.", a, b);
limpbizkit564053f2008-06-15 11:21:18 +0000314 }
315
316 public Errors recursiveBinding() {
317 return addMessage("Binding points to itself.");
318 }
319
320 public Errors bindingAlreadySet(Key<?> key, Object source) {
limpbizkit06898062008-11-02 05:14:55 +0000321 return addMessage("A binding to %s was already configured at %s.", key, convert(source));
limpbizkit564053f2008-06-15 11:21:18 +0000322 }
sberlina23937e2011-06-29 22:02:50 +0000323
sberlin0d8b52f2011-02-21 21:06:40 +0000324 public Errors jitBindingAlreadySet(Key<?> key) {
325 return addMessage("A just-in-time binding to %s was already configured on a parent injector.", key);
326 }
limpbizkit564053f2008-06-15 11:21:18 +0000327
sberlincc17f142011-02-27 00:02:03 +0000328 public Errors childBindingAlreadySet(Key<?> key, Set<Object> sources) {
329 Formatter allSources = new Formatter();
330 for (Object source : sources) {
331 if (source == null) {
332 allSources.format("%n (bound by a just-in-time binding)");
333 } else {
334 allSources.format("%n bound at %s", source);
335 }
336 }
337 Errors errors = addMessage(
338 "Unable to create binding for %s."
339 + " It was already configured on one or more child injectors or private modules"
340 + "%s%n"
341 + " If it was in a PrivateModule, did you forget to expose the binding?",
342 key, allSources.out());
343 return errors;
limpbizkit5fb9d922008-10-14 23:35:56 +0000344 }
345
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000346 public Errors errorCheckingDuplicateBinding(Key<?> key, Object source, Throwable t) {
347 return addMessage(
sberlina23937e2011-06-29 22:02:50 +0000348 "A binding to %s was already configured at %s and an error was thrown "
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000349 + "while checking duplicate bindings. Error: %s",
sberlin45ca7f62011-02-20 00:05:28 +0000350 key, convert(source), t);
sberlin@gmail.com7bcec882010-06-24 01:03:26 +0000351 }
352
limpbizkit564053f2008-06-15 11:21:18 +0000353 public Errors errorInjectingMethod(Throwable cause) {
limpbizkit516e2ab2009-03-26 22:01:18 +0000354 return errorInUserCode(cause, "Error injecting method, %s", cause);
355 }
356
limpbizkitee792462009-04-08 23:48:49 +0000357 public Errors errorNotifyingTypeListener(TypeListenerBinding listener,
limpbizkita843a952009-04-08 22:24:55 +0000358 TypeLiteral<?> type, Throwable cause) {
limpbizkit516e2ab2009-03-26 22:01:18 +0000359 return errorInUserCode(cause,
limpbizkita843a952009-04-08 22:24:55 +0000360 "Error notifying TypeListener %s (bound at %s) of %s.%n"
limpbizkit516e2ab2009-03-26 22:01:18 +0000361 + " Reason: %s",
limpbizkita843a952009-04-08 22:24:55 +0000362 listener.getListener(), convert(listener.getSource()), type, cause);
limpbizkit564053f2008-06-15 11:21:18 +0000363 }
364
365 public Errors errorInjectingConstructor(Throwable cause) {
limpbizkit516e2ab2009-03-26 22:01:18 +0000366 return errorInUserCode(cause, "Error injecting constructor, %s", cause);
limpbizkit564053f2008-06-15 11:21:18 +0000367 }
368
limpbizkit490833f2008-11-02 00:12:39 +0000369 public Errors errorInProvider(RuntimeException runtimeException) {
sberlin890b9ef2010-07-31 15:06:36 +0000370 Throwable unwrapped = unwrap(runtimeException);
371 return errorInUserCode(unwrapped, "Error in custom provider, %s", unwrapped);
limpbizkit516e2ab2009-03-26 22:01:18 +0000372 }
373
limpbizkitee792462009-04-08 23:48:49 +0000374 public Errors errorInUserInjector(
375 MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException cause) {
376 return errorInUserCode(cause, "Error injecting %s using %s.%n"
377 + " Reason: %s", type, listener, cause);
378 }
379
limpbizkit516e2ab2009-03-26 22:01:18 +0000380 public Errors errorNotifyingInjectionListener(
limpbizkitee792462009-04-08 23:48:49 +0000381 InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException cause) {
limpbizkit516e2ab2009-03-26 22:01:18 +0000382 return errorInUserCode(cause, "Error notifying InjectionListener %s of %s.%n"
limpbizkitee792462009-04-08 23:48:49 +0000383 + " Reason: %s", listener, type, cause);
limpbizkit490833f2008-11-02 00:12:39 +0000384 }
385
sberlin3748e4a2010-05-23 13:40:06 +0000386 public Errors exposedButNotBound(Key<?> key) {
387 return addMessage("Could not expose() %s, it must be explicitly bound.", key);
388 }
sberlina23937e2011-06-29 22:02:50 +0000389
sberlin3748e4a2010-05-23 13:40:06 +0000390 public Errors keyNotFullySpecified(TypeLiteral<?> typeLiteral) {
391 return addMessage("%s cannot be used as a key; It is not fully specified.", typeLiteral);
limpbizkitfcbdf992008-11-26 02:37:35 +0000392 }
sberlina23937e2011-06-29 22:02:50 +0000393
sberlinb02627d2010-10-25 04:56:00 +0000394 public Errors errorEnhancingClass(Class<?> clazz, Throwable cause) {
395 return errorInUserCode(cause, "Unable to method intercept: %s", clazz);
396 }
limpbizkitfcbdf992008-11-26 02:37:35 +0000397
limpbizkit72d11dd2008-11-02 07:59:13 +0000398 public static Collection<Message> getMessagesFromThrowable(Throwable throwable) {
399 if (throwable instanceof ProvisionException) {
400 return ((ProvisionException) throwable).getErrorMessages();
401 } else if (throwable instanceof ConfigurationException) {
402 return ((ConfigurationException) throwable).getErrorMessages();
403 } else if (throwable instanceof CreationException) {
404 return ((CreationException) throwable).getErrorMessages();
405 } else {
406 return ImmutableSet.of();
407 }
408 }
409
limpbizkit516e2ab2009-03-26 22:01:18 +0000410 public Errors errorInUserCode(Throwable cause, String messageFormat, Object... arguments) {
limpbizkit72d11dd2008-11-02 07:59:13 +0000411 Collection<Message> messages = getMessagesFromThrowable(cause);
limpbizkit490833f2008-11-02 00:12:39 +0000412
limpbizkit72d11dd2008-11-02 07:59:13 +0000413 if (!messages.isEmpty()) {
414 return merge(messages);
limpbizkit564053f2008-06-15 11:21:18 +0000415 } else {
limpbizkit516e2ab2009-03-26 22:01:18 +0000416 return addMessage(cause, messageFormat, arguments);
limpbizkit564053f2008-06-15 11:21:18 +0000417 }
418 }
sberlina23937e2011-06-29 22:02:50 +0000419
sberlin890b9ef2010-07-31 15:06:36 +0000420 private Throwable unwrap(RuntimeException runtimeException) {
421 if(runtimeException instanceof Exceptions.UnhandledCheckedUserException) {
422 return runtimeException.getCause();
423 } else {
424 return runtimeException;
425 }
426 }
limpbizkit564053f2008-06-15 11:21:18 +0000427
limpbizkit564053f2008-06-15 11:21:18 +0000428 public Errors cannotInjectRawProvider() {
429 return addMessage("Cannot inject a Provider that has no type parameter");
430 }
431
limpbizkit0ca7f912009-03-28 19:11:40 +0000432 public Errors cannotInjectRawMembersInjector() {
433 return addMessage("Cannot inject a MembersInjector that has no type parameter");
434 }
435
limpbizkitb0f3c9b2008-11-15 09:19:28 +0000436 public Errors cannotInjectTypeLiteralOf(Type unsupportedType) {
437 return addMessage("Cannot inject a TypeLiteral of %s", unsupportedType);
438 }
439
440 public Errors cannotInjectRawTypeLiteral() {
441 return addMessage("Cannot inject a TypeLiteral that has no type parameter");
442 }
443
limpbizkit564053f2008-06-15 11:21:18 +0000444 public Errors cannotSatisfyCircularDependency(Class<?> expectedType) {
445 return addMessage(
446 "Tried proxying %s to support a circular dependency, but it is not an interface.",
447 expectedType);
448 }
sberlina23937e2011-06-29 22:02:50 +0000449
sberlinb9978212010-04-24 21:42:40 +0000450 public Errors circularProxiesDisabled(Class<?> expectedType) {
451 return addMessage(
452 "Tried proxying %s to support a circular dependency, but circular proxies are disabled.",
453 expectedType);
454 }
limpbizkit564053f2008-06-15 11:21:18 +0000455
limpbizkit06898062008-11-02 05:14:55 +0000456 public void throwCreationExceptionIfErrorsExist() {
457 if (!hasErrors()) {
458 return;
459 }
460
461 throw new CreationException(getMessages());
limpbizkit564053f2008-06-15 11:21:18 +0000462 }
463
limpbizkit06898062008-11-02 05:14:55 +0000464 public void throwConfigurationExceptionIfErrorsExist() {
limpbizkit490833f2008-11-02 00:12:39 +0000465 if (!hasErrors()) {
466 return;
467 }
468
469 throw new ConfigurationException(getMessages());
470 }
471
472 public void throwProvisionExceptionIfErrorsExist() {
473 if (!hasErrors()) {
474 return;
475 }
476
477 throw new ProvisionException(getMessages());
478 }
479
limpbizkit18cb1912008-09-02 18:20:45 +0000480 private Message merge(Message message) {
limpbizkita6e0e782008-09-03 06:19:56 +0000481 List<Object> sources = Lists.newArrayList();
limpbizkit06898062008-11-02 05:14:55 +0000482 sources.addAll(getSources());
limpbizkita6e0e782008-09-03 06:19:56 +0000483 sources.addAll(message.getSources());
limpbizkit06898062008-11-02 05:14:55 +0000484 return new Message(sources, message.getMessage(), message.getCause());
limpbizkit18cb1912008-09-02 18:20:45 +0000485 }
limpbizkit564053f2008-06-15 11:21:18 +0000486
limpbizkit18cb1912008-09-02 18:20:45 +0000487 public Errors merge(Collection<Message> messages) {
limpbizkit06898062008-11-02 05:14:55 +0000488 for (Message message : messages) {
limpbizkite89c49e2009-05-06 01:02:14 +0000489 addMessage(merge(message));
limpbizkit564053f2008-06-15 11:21:18 +0000490 }
limpbizkit18cb1912008-09-02 18:20:45 +0000491 return this;
492 }
limpbizkit564053f2008-06-15 11:21:18 +0000493
limpbizkit18cb1912008-09-02 18:20:45 +0000494 public Errors merge(Errors moreErrors) {
limpbizkite89c49e2009-05-06 01:02:14 +0000495 if (moreErrors.root == root || moreErrors.root.errors == null) {
limpbizkit06898062008-11-02 05:14:55 +0000496 return this;
497 }
498
limpbizkite89c49e2009-05-06 01:02:14 +0000499 merge(moreErrors.root.errors);
limpbizkit564053f2008-06-15 11:21:18 +0000500 return this;
501 }
502
limpbizkit06898062008-11-02 05:14:55 +0000503 public List<Object> getSources() {
504 List<Object> sources = Lists.newArrayList();
505 for (Errors e = this; e != null; e = e.parent) {
limpbizkit72d11dd2008-11-02 07:59:13 +0000506 if (e.source != SourceProvider.UNKNOWN_SOURCE) {
507 sources.add(0, e.source);
508 }
limpbizkit06898062008-11-02 05:14:55 +0000509 }
510 return sources;
511 }
512
limpbizkit72d11dd2008-11-02 07:59:13 +0000513 public void throwIfNewErrors(int expectedSize) throws ErrorsException {
514 if (size() == expectedSize) {
limpbizkit564053f2008-06-15 11:21:18 +0000515 return;
516 }
517
518 throw toException();
519 }
520
limpbizkit163c48a2008-06-16 02:58:08 +0000521 public ErrorsException toException() {
522 return new ErrorsException(this);
limpbizkit564053f2008-06-15 11:21:18 +0000523 }
524
525 public boolean hasErrors() {
limpbizkite89c49e2009-05-06 01:02:14 +0000526 return root.errors != null;
limpbizkit564053f2008-06-15 11:21:18 +0000527 }
528
limpbizkit03c8d262008-12-02 06:15:57 +0000529 public Errors addMessage(String messageFormat, Object... arguments) {
limpbizkit564053f2008-06-15 11:21:18 +0000530 return addMessage(null, messageFormat, arguments);
531 }
532
533 private Errors addMessage(Throwable cause, String messageFormat, Object... arguments) {
limpbizkit2c2c6102008-06-20 13:34:36 +0000534 String message = format(messageFormat, arguments);
limpbizkit06898062008-11-02 05:14:55 +0000535 addMessage(new Message(getSources(), message, cause));
limpbizkit2c2c6102008-06-20 13:34:36 +0000536 return this;
537 }
538
539 public Errors addMessage(Message message) {
limpbizkite89c49e2009-05-06 01:02:14 +0000540 if (root.errors == null) {
541 root.errors = Lists.newArrayList();
542 }
543 root.errors.add(message);
limpbizkit564053f2008-06-15 11:21:18 +0000544 return this;
545 }
546
limpbizkitb1f42f52008-11-26 07:44:53 +0000547 public static String format(String messageFormat, Object... arguments) {
limpbizkit564053f2008-06-15 11:21:18 +0000548 for (int i = 0; i < arguments.length; i++) {
549 arguments[i] = Errors.convert(arguments[i]);
550 }
551 return String.format(messageFormat, arguments);
552 }
553
limpbizkit564053f2008-06-15 11:21:18 +0000554 public List<Message> getMessages() {
limpbizkite89c49e2009-05-06 01:02:14 +0000555 if (root.errors == null) {
556 return ImmutableList.of();
557 }
limpbizkit564053f2008-06-15 11:21:18 +0000558
Sam Berlinc00df282014-07-01 16:53:41 -0400559 return new Ordering<Message>() {
560 @Override
limpbizkit564053f2008-06-15 11:21:18 +0000561 public int compare(Message a, Message b) {
562 return a.getSource().compareTo(b.getSource());
563 }
Sam Berlinc00df282014-07-01 16:53:41 -0400564 }.sortedCopy(root.errors);
limpbizkit564053f2008-06-15 11:21:18 +0000565 }
566
limpbizkit490833f2008-11-02 00:12:39 +0000567 /** Returns the formatted message for an exception with the specified messages. */
568 public static String format(String heading, Collection<Message> errorMessages) {
limpbizkit564053f2008-06-15 11:21:18 +0000569 Formatter fmt = new Formatter().format(heading).format(":%n%n");
570 int index = 1;
limpbizkit490833f2008-11-02 00:12:39 +0000571 boolean displayCauses = getOnlyCause(errorMessages) == null;
572
limpbizkit564053f2008-06-15 11:21:18 +0000573 for (Message errorMessage : errorMessages) {
limpbizkita6e0e782008-09-03 06:19:56 +0000574 fmt.format("%s) %s%n", index++, errorMessage.getMessage());
limpbizkit564053f2008-06-15 11:21:18 +0000575
limpbizkita6e0e782008-09-03 06:19:56 +0000576 List<Object> dependencies = errorMessage.getSources();
limpbizkita98bc7a2008-08-29 16:52:44 +0000577 for (int i = dependencies.size() - 1; i >= 0; i--) {
limpbizkita6e0e782008-09-03 06:19:56 +0000578 Object source = dependencies.get(i);
limpbizkit06898062008-11-02 05:14:55 +0000579 formatSource(fmt, source);
limpbizkit564053f2008-06-15 11:21:18 +0000580 }
581
limpbizkit490833f2008-11-02 00:12:39 +0000582 Throwable cause = errorMessage.getCause();
583 if (displayCauses && cause != null) {
584 StringWriter writer = new StringWriter();
585 cause.printStackTrace(new PrintWriter(writer));
586 fmt.format("Caused by: %s", writer.getBuffer());
587 }
588
limpbizkit564053f2008-06-15 11:21:18 +0000589 fmt.format("%n");
590 }
591
limpbizkit490833f2008-11-02 00:12:39 +0000592 if (errorMessages.size() == 1) {
593 fmt.format("1 error");
594 } else {
595 fmt.format("%s errors", errorMessages.size());
596 }
597
598 return fmt.toString();
limpbizkit564053f2008-06-15 11:21:18 +0000599 }
600
limpbizkit918dff82008-08-03 01:29:46 +0000601 /**
602 * Returns {@code value} if it is non-null allowed to be null. Otherwise a message is added and
603 * an {@code ErrorsException} is thrown.
604 */
limpbizkita98bc7a2008-08-29 16:52:44 +0000605 public <T> T checkForNull(T value, Object source, Dependency<?> dependency)
limpbizkit918dff82008-08-03 01:29:46 +0000606 throws ErrorsException {
sberlina23937e2011-06-29 22:02:50 +0000607 if (value != null || dependency.isNullable() ) {
limpbizkit918dff82008-08-03 01:29:46 +0000608 return value;
609 }
610
sameb9867f9c2015-02-02 12:45:25 -0800611 // Hack to allow null parameters to @Provides methods, for backwards compatibility.
612 if (dependency.getInjectionPoint().getMember() instanceof Method) {
613 Method annotated = (Method) dependency.getInjectionPoint().getMember();
614 if (annotated.isAnnotationPresent(Provides.class)) {
615 switch (InternalFlags.getNullableProvidesOption()) {
616 case ERROR:
617 break; // break out & let the below exception happen
618 case IGNORE:
619 return value; // user doesn't care about injecting nulls to non-@Nullables.
620 case WARN:
621 logger.log(Level.WARNING,
622 "Guice injected null into parameter {0} of {1} (a {2}), please mark it @Nullable."
623 + " Use -Dguice_check_nullable_provides_params=ERROR to turn this into an"
624 + " error.",
625 new Object[] {
626 dependency.getParameterIndex(),
627 convert(dependency.getInjectionPoint().getMember()),
628 convert(dependency.getKey())});
629 return null; // log & exit.
630 }
631 }
632 }
633
limpbizkita98bc7a2008-08-29 16:52:44 +0000634 int parameterIndex = dependency.getParameterIndex();
limpbizkit918dff82008-08-03 01:29:46 +0000635 String parameterName = (parameterIndex != -1)
636 ? "parameter " + parameterIndex + " of "
637 : "";
638 addMessage("null returned by binding at %s%n but %s%s is not @Nullable",
limpbizkita98bc7a2008-08-29 16:52:44 +0000639 source, parameterName, dependency.getInjectionPoint().getMember());
limpbizkit918dff82008-08-03 01:29:46 +0000640
641 throw toException();
642 }
643
limpbizkit490833f2008-11-02 00:12:39 +0000644 /**
645 * Returns the cause throwable if there is exactly one cause in {@code messages}. If there are
646 * zero or multiple messages with causes, null is returned.
647 */
648 public static Throwable getOnlyCause(Collection<Message> messages) {
649 Throwable onlyCause = null;
650 for (Message message : messages) {
651 Throwable messageCause = message.getCause();
652 if (messageCause == null) {
653 continue;
654 }
655
656 if (onlyCause != null) {
657 return null;
658 }
659
660 onlyCause = messageCause;
661 }
662
663 return onlyCause;
664 }
665
limpbizkit72d11dd2008-11-02 07:59:13 +0000666 public int size() {
limpbizkite89c49e2009-05-06 01:02:14 +0000667 return root.errors == null ? 0 : root.errors.size();
limpbizkit72d11dd2008-11-02 07:59:13 +0000668 }
669
limpbizkit2c2c6102008-06-20 13:34:36 +0000670 private static abstract class Converter<T> {
limpbizkit564053f2008-06-15 11:21:18 +0000671
672 final Class<T> type;
673
674 Converter(Class<T> type) {
675 this.type = type;
676 }
677
678 boolean appliesTo(Object o) {
sberlinb2f17602010-11-19 02:33:32 +0000679 return o != null && type.isAssignableFrom(o.getClass());
limpbizkit564053f2008-06-15 11:21:18 +0000680 }
681
682 String convert(Object o) {
683 return toString(type.cast(o));
684 }
685
686 abstract String toString(T t);
687 }
688
limpbizkit2c2c6102008-06-20 13:34:36 +0000689 private static final Collection<Converter<?>> converters = ImmutableList.of(
limpbizkit564053f2008-06-15 11:21:18 +0000690 new Converter<Class>(Class.class) {
Sam Berlinc7567772012-05-31 19:54:04 -0400691 @Override public String toString(Class c) {
limpbizkit564053f2008-06-15 11:21:18 +0000692 return c.getName();
693 }
694 },
limpbizkit185d2a22008-06-16 07:22:47 +0000695 new Converter<Member>(Member.class) {
Sam Berlinc7567772012-05-31 19:54:04 -0400696 @Override public String toString(Member member) {
sberlindfee9fd2010-10-30 14:15:06 +0000697 return Classes.toString(member);
limpbizkit185d2a22008-06-16 07:22:47 +0000698 }
699 },
limpbizkit564053f2008-06-15 11:21:18 +0000700 new Converter<Key>(Key.class) {
Sam Berlinc7567772012-05-31 19:54:04 -0400701 @Override public String toString(Key key) {
limpbizkit06898062008-11-02 05:14:55 +0000702 if (key.getAnnotationType() != null) {
703 return key.getTypeLiteral() + " annotated with "
704 + (key.getAnnotation() != null ? key.getAnnotation() : key.getAnnotationType());
705 } else {
706 return key.getTypeLiteral().toString();
limpbizkit564053f2008-06-15 11:21:18 +0000707 }
limpbizkit564053f2008-06-15 11:21:18 +0000708 }
709 });
710
711 public static Object convert(Object o) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700712 ElementSource source = null;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700713 if (o instanceof ElementSource) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700714 source = (ElementSource)o;
715 o = source.getDeclaringSource();
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700716 }
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700717 return convert(o, source);
718 }
719
720 public static Object convert(Object o, ElementSource source) {
limpbizkit564053f2008-06-15 11:21:18 +0000721 for (Converter<?> converter : converters) {
722 if (converter.appliesTo(o)) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700723 return appendModules(converter.convert(o), source);
limpbizkit564053f2008-06-15 11:21:18 +0000724 }
725 }
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700726 return appendModules(o, source);
727 }
728
729 private static Object appendModules(Object source, ElementSource elementSource) {
730 String modules = moduleSourceString(elementSource);
731 if (modules.length() == 0) {
732 return source;
733 } else {
734 return source + modules;
735 }
736 }
737
738 private static String moduleSourceString(ElementSource elementSource) {
739 // if we only have one module (or don't know what they are), then don't bother
740 // reporting it, because the source already is going to report exactly that module.
741 if (elementSource == null) {
742 return "";
743 }
744 List<String> modules = Lists.newArrayList(elementSource.getModuleClassNames());
745 // Insert any original element sources w/ module info into the path.
746 while(elementSource.getOriginalElementSource() != null) {
747 elementSource = elementSource.getOriginalElementSource();
748 modules.addAll(0, elementSource.getModuleClassNames());
749 }
750 if (modules.size() <= 1) {
751 return "";
752 }
753
754 // Ideally we'd do:
755 // return Joiner.on(" -> ")
756 // .appendTo(new StringBuilder(" (via modules: "), Lists.reverse(modules))
757 // .append(")").toString();
758 // ... but for some reason we can't find Lists.reverse, so do it the boring way.
759 StringBuilder builder = new StringBuilder(" (via modules: ");
760 for (int i = modules.size() - 1; i >= 0; i--) {
761 builder.append(modules.get(i));
762 if (i != 0) {
763 builder.append(" -> ");
764 }
765 }
766 builder.append(")");
767 return builder.toString();
limpbizkit564053f2008-06-15 11:21:18 +0000768 }
limpbizkit4ce9cfa2008-08-14 03:35:16 +0000769
limpbizkit06898062008-11-02 05:14:55 +0000770 public static void formatSource(Formatter formatter, Object source) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700771 ElementSource elementSource = null;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700772 if (source instanceof ElementSource) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700773 elementSource = (ElementSource)source;
774 source = elementSource.getDeclaringSource();
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700775 }
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700776 formatSource(formatter, source, elementSource);
777 }
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700778
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700779 public static void formatSource(Formatter formatter, Object source, ElementSource elementSource) {
780 String modules = moduleSourceString(elementSource);
limpbizkit06898062008-11-02 05:14:55 +0000781 if (source instanceof Dependency) {
782 Dependency<?> dependency = (Dependency<?>) source;
783 InjectionPoint injectionPoint = dependency.getInjectionPoint();
784 if (injectionPoint != null) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700785 formatInjectionPoint(formatter, dependency, injectionPoint, elementSource);
limpbizkit06898062008-11-02 05:14:55 +0000786 } else {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700787 formatSource(formatter, dependency.getKey(), elementSource);
limpbizkit06898062008-11-02 05:14:55 +0000788 }
limpbizkit4ce9cfa2008-08-14 03:35:16 +0000789
limpbizkit06898062008-11-02 05:14:55 +0000790 } else if (source instanceof InjectionPoint) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700791 formatInjectionPoint(formatter, null, (InjectionPoint) source, elementSource);
limpbizkit06898062008-11-02 05:14:55 +0000792
limpbizkit4ce9cfa2008-08-14 03:35:16 +0000793 } else if (source instanceof Class) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700794 formatter.format(" at %s%s%n", StackTraceElements.forType((Class<?>) source), modules);
limpbizkit06898062008-11-02 05:14:55 +0000795
796 } else if (source instanceof Member) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700797 formatter.format(" at %s%s%n", StackTraceElements.forMember((Member) source), modules);
limpbizkit06898062008-11-02 05:14:55 +0000798
limpbizkit97eac0f2009-03-28 18:25:35 +0000799 } else if (source instanceof TypeLiteral) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700800 formatter.format(" while locating %s%s%n", source, modules);
limpbizkit97eac0f2009-03-28 18:25:35 +0000801
limpbizkit06898062008-11-02 05:14:55 +0000802 } else if (source instanceof Key) {
803 Key<?> key = (Key<?>) source;
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700804 formatter.format(" while locating %s%n", convert(key, elementSource));
limpbizkit06898062008-11-02 05:14:55 +0000805
limpbizkit4ce9cfa2008-08-14 03:35:16 +0000806 } else {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700807 formatter.format(" at %s%s%n", source, modules);
limpbizkit4ce9cfa2008-08-14 03:35:16 +0000808 }
809 }
limpbizkita6e0e782008-09-03 06:19:56 +0000810
limpbizkit06898062008-11-02 05:14:55 +0000811 public static void formatInjectionPoint(Formatter formatter, Dependency<?> dependency,
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700812 InjectionPoint injectionPoint, ElementSource elementSource) {
limpbizkit06898062008-11-02 05:14:55 +0000813 Member member = injectionPoint.getMember();
sberlindfee9fd2010-10-30 14:15:06 +0000814 Class<? extends Member> memberType = Classes.memberType(member);
limpbizkit06898062008-11-02 05:14:55 +0000815
816 if (memberType == Field.class) {
limpbizkit72d11dd2008-11-02 07:59:13 +0000817 dependency = injectionPoint.getDependencies().get(0);
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700818 formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource));
limpbizkit72d11dd2008-11-02 07:59:13 +0000819 formatter.format(" for field at %s%n", StackTraceElements.forMember(member));
limpbizkit06898062008-11-02 05:14:55 +0000820
821 } else if (dependency != null) {
Christian Edward Gruber2e39ef72013-10-05 14:04:53 -0700822 formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource));
limpbizkit72d11dd2008-11-02 07:59:13 +0000823 formatter.format(" for parameter %s at %s%n",
limpbizkit06898062008-11-02 05:14:55 +0000824 dependency.getParameterIndex(), StackTraceElements.forMember(member));
825
826 } else {
827 formatSource(formatter, injectionPoint.getMember());
limpbizkita6e0e782008-09-03 06:19:56 +0000828 }
limpbizkita6e0e782008-09-03 06:19:56 +0000829 }
limpbizkit564053f2008-06-15 11:21:18 +0000830}