• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.internal;
18 
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.ImmutableSet;
21 import com.google.common.collect.Lists;
22 import com.google.common.collect.Ordering;
23 import com.google.common.collect.Sets;
24 import com.google.inject.ConfigurationException;
25 import com.google.inject.CreationException;
26 import com.google.inject.Guice;
27 import com.google.inject.Key;
28 import com.google.inject.MembersInjector;
29 import com.google.inject.Provider;
30 import com.google.inject.Provides;
31 import com.google.inject.ProvisionException;
32 import com.google.inject.Scope;
33 import com.google.inject.TypeLiteral;
34 import com.google.inject.internal.util.Classes;
35 import com.google.inject.internal.util.SourceProvider;
36 import com.google.inject.internal.util.StackTraceElements;
37 import com.google.inject.spi.Dependency;
38 import com.google.inject.spi.ElementSource;
39 import com.google.inject.spi.InjectionListener;
40 import com.google.inject.spi.InjectionPoint;
41 import com.google.inject.spi.Message;
42 import com.google.inject.spi.ScopeBinding;
43 import com.google.inject.spi.TypeConverterBinding;
44 import com.google.inject.spi.TypeListenerBinding;
45 
46 import java.io.PrintWriter;
47 import java.io.Serializable;
48 import java.io.StringWriter;
49 import java.lang.annotation.Annotation;
50 import java.lang.reflect.Constructor;
51 import java.lang.reflect.Field;
52 import java.lang.reflect.Member;
53 import java.lang.reflect.Method;
54 import java.lang.reflect.Type;
55 import java.util.Collection;
56 import java.util.Formatter;
57 import java.util.List;
58 import java.util.Set;
59 import java.util.concurrent.ConcurrentHashMap;
60 import java.util.logging.Level;
61 import java.util.logging.Logger;
62 
63 /**
64  * A collection of error messages. If this type is passed as a method parameter, the method is
65  * considered to have executed successfully only if new errors were not added to this collection.
66  *
67  * <p>Errors can be chained to provide additional context. To add context, call {@link #withSource}
68  * to create a new Errors instance that contains additional context. All messages added to the
69  * returned instance will contain full context.
70  *
71  * <p>To avoid messages with redundant context, {@link #withSource} should be added sparingly. A
72  * good rule of thumb is to assume a method's caller has already specified enough context to
73  * identify that method. When calling a method that's defined in a different context, call that
74  * method with an errors object that includes its context.
75  *
76  * @author jessewilson@google.com (Jesse Wilson)
77  */
78 public final class Errors implements Serializable {
79 
80   private static final Logger logger = Logger.getLogger(Guice.class.getName());
81 
82   private static final Set<Dependency<?>> warnedDependencies =
83       Sets.newSetFromMap(new ConcurrentHashMap<Dependency<?>, Boolean>());
84 
85 
86   /**
87    * The root errors object. Used to access the list of error messages.
88    */
89   private final Errors root;
90 
91   /**
92    * The parent errors object. Used to obtain the chain of source objects.
93    */
94   private final Errors parent;
95 
96   /**
97    * The leaf source for errors added here.
98    */
99   private final Object source;
100 
101   /**
102    * null unless (root == this) and error messages exist. Never an empty list.
103    */
104   private List<Message> errors; // lazy, use getErrorsForAdd()
105 
Errors()106   public Errors() {
107     this.root = this;
108     this.parent = null;
109     this.source = SourceProvider.UNKNOWN_SOURCE;
110   }
111 
Errors(Object source)112   public Errors(Object source) {
113     this.root = this;
114     this.parent = null;
115     this.source = source;
116   }
117 
Errors(Errors parent, Object source)118   private Errors(Errors parent, Object source) {
119     this.root = parent.root;
120     this.parent = parent;
121     this.source = source;
122   }
123 
124   /**
125    * Returns an instance that uses {@code source} as a reference point for newly added errors.
126    */
withSource(Object source)127   public Errors withSource(Object source) {
128     return source == this.source || source == SourceProvider.UNKNOWN_SOURCE
129         ? this
130         : new Errors(this, source);
131   }
132 
133   /**
134    * We use a fairly generic error message here. The motivation is to share the
135    * same message for both bind time errors:
136    * <pre><code>Guice.createInjector(new AbstractModule() {
137    *   public void configure() {
138    *     bind(Runnable.class);
139    *   }
140    * }</code></pre>
141    * ...and at provide-time errors:
142    * <pre><code>Guice.createInjector().getInstance(Runnable.class);</code></pre>
143    * Otherwise we need to know who's calling when resolving a just-in-time
144    * binding, which makes things unnecessarily complex.
145    */
missingImplementation(Key key)146   public Errors missingImplementation(Key key) {
147     return addMessage("No implementation for %s was bound.", key);
148   }
149 
jitDisabled(Key key)150   public Errors jitDisabled(Key key) {
151     return addMessage("Explicit bindings are required and %s is not explicitly bound.", key);
152   }
153 
jitDisabledInParent(Key<?> key)154   public Errors jitDisabledInParent(Key<?> key) {
155     return addMessage(
156         "Explicit bindings are required and %s would be bound in a parent injector.%n"
157         + "Please add an explicit binding for it, either in the child or the parent.",
158         key);
159   }
160 
atInjectRequired(Class clazz)161   public Errors atInjectRequired(Class clazz) {
162     return addMessage(
163         "Explicit @Inject annotations are required on constructors,"
164         + " but %s has no constructors annotated with @Inject.",
165         clazz);
166   }
167 
converterReturnedNull(String stringValue, Object source, TypeLiteral<?> type, TypeConverterBinding typeConverterBinding)168   public Errors converterReturnedNull(String stringValue, Object source,
169       TypeLiteral<?> type, TypeConverterBinding typeConverterBinding) {
170     return addMessage("Received null converting '%s' (bound at %s) to %s%n"
171         + " using %s.",
172         stringValue, convert(source), type, typeConverterBinding);
173   }
174 
conversionTypeError(String stringValue, Object source, TypeLiteral<?> type, TypeConverterBinding typeConverterBinding, Object converted)175   public Errors conversionTypeError(String stringValue, Object source, TypeLiteral<?> type,
176       TypeConverterBinding typeConverterBinding, Object converted) {
177     return addMessage("Type mismatch converting '%s' (bound at %s) to %s%n"
178         + " using %s.%n"
179         + " Converter returned %s.",
180         stringValue, convert(source), type, typeConverterBinding, converted);
181   }
182 
conversionError(String stringValue, Object source, TypeLiteral<?> type, TypeConverterBinding typeConverterBinding, RuntimeException cause)183   public Errors conversionError(String stringValue, Object source,
184       TypeLiteral<?> type, TypeConverterBinding typeConverterBinding, RuntimeException cause) {
185     return errorInUserCode(cause, "Error converting '%s' (bound at %s) to %s%n"
186         + " using %s.%n"
187         + " Reason: %s",
188         stringValue, convert(source), type, typeConverterBinding, cause);
189   }
190 
ambiguousTypeConversion(String stringValue, Object source, TypeLiteral<?> type, TypeConverterBinding a, TypeConverterBinding b)191   public Errors ambiguousTypeConversion(String stringValue, Object source, TypeLiteral<?> type,
192       TypeConverterBinding a, TypeConverterBinding b) {
193     return addMessage("Multiple converters can convert '%s' (bound at %s) to %s:%n"
194         + " %s and%n"
195         + " %s.%n"
196         + " Please adjust your type converter configuration to avoid overlapping matches.",
197         stringValue, convert(source), type, a, b);
198   }
199 
bindingToProvider()200   public Errors bindingToProvider() {
201     return addMessage("Binding to Provider is not allowed.");
202   }
203 
subtypeNotProvided(Class<? extends Provider<?>> providerType, Class<?> type)204   public Errors subtypeNotProvided(Class<? extends Provider<?>> providerType,
205       Class<?> type) {
206     return addMessage("%s doesn't provide instances of %s.", providerType, type);
207   }
208 
notASubtype(Class<?> implementationType, Class<?> type)209   public Errors notASubtype(Class<?> implementationType, Class<?> type) {
210     return addMessage("%s doesn't extend %s.", implementationType, type);
211   }
212 
recursiveImplementationType()213   public Errors recursiveImplementationType() {
214     return addMessage("@ImplementedBy points to the same class it annotates.");
215   }
216 
recursiveProviderType()217   public Errors recursiveProviderType() {
218     return addMessage("@ProvidedBy points to the same class it annotates.");
219   }
220 
missingRuntimeRetention(Class<? extends Annotation> annotation)221   public Errors missingRuntimeRetention(Class<? extends Annotation> annotation) {
222     return addMessage(format("Please annotate %s with @Retention(RUNTIME).", annotation));
223   }
224 
missingScopeAnnotation(Class<? extends Annotation> annotation)225   public Errors missingScopeAnnotation(Class<? extends Annotation> annotation) {
226     return addMessage(format("Please annotate %s with @ScopeAnnotation.", annotation));
227   }
228 
optionalConstructor(Constructor constructor)229   public Errors optionalConstructor(Constructor constructor) {
230     return addMessage("%s is annotated @Inject(optional=true), "
231         + "but constructors cannot be optional.", constructor);
232   }
233 
cannotBindToGuiceType(String simpleName)234   public Errors cannotBindToGuiceType(String simpleName) {
235     return addMessage("Binding to core guice framework type is not allowed: %s.", simpleName);
236   }
237 
scopeNotFound(Class<? extends Annotation> scopeAnnotation)238   public Errors scopeNotFound(Class<? extends Annotation> scopeAnnotation) {
239     return addMessage("No scope is bound to %s.", scopeAnnotation);
240   }
241 
scopeAnnotationOnAbstractType( Class<? extends Annotation> scopeAnnotation, Class<?> type, Object source)242   public Errors scopeAnnotationOnAbstractType(
243       Class<? extends Annotation> scopeAnnotation, Class<?> type, Object source) {
244     return addMessage("%s is annotated with %s, but scope annotations are not supported "
245         + "for abstract types.%n Bound at %s.", type, scopeAnnotation, convert(source));
246   }
247 
misplacedBindingAnnotation(Member member, Annotation bindingAnnotation)248   public Errors misplacedBindingAnnotation(Member member, Annotation bindingAnnotation) {
249     return addMessage("%s is annotated with %s, but binding annotations should be applied "
250         + "to its parameters instead.", member, bindingAnnotation);
251   }
252 
253   private static final String CONSTRUCTOR_RULES =
254       "Classes must have either one (and only one) constructor "
255           + "annotated with @Inject or a zero-argument constructor that is not private.";
256 
missingConstructor(Class<?> implementation)257   public Errors missingConstructor(Class<?> implementation) {
258     return addMessage("Could not find a suitable constructor in %s. " + CONSTRUCTOR_RULES,
259         implementation);
260   }
261 
tooManyConstructors(Class<?> implementation)262   public Errors tooManyConstructors(Class<?> implementation) {
263     return addMessage("%s has more than one constructor annotated with @Inject. "
264         + CONSTRUCTOR_RULES, implementation);
265   }
266 
constructorNotDefinedByType(Constructor<?> constructor, TypeLiteral<?> type)267   public Errors constructorNotDefinedByType(Constructor<?> constructor, TypeLiteral<?> type) {
268     return addMessage("%s does not define %s", type, constructor);
269   }
270 
duplicateScopes(ScopeBinding existing, Class<? extends Annotation> annotationType, Scope scope)271   public Errors duplicateScopes(ScopeBinding existing,
272       Class<? extends Annotation> annotationType, Scope scope) {
273     return addMessage("Scope %s is already bound to %s at %s.%n Cannot bind %s.",
274         existing.getScope(), annotationType, existing.getSource(), scope);
275   }
276 
voidProviderMethod()277   public Errors voidProviderMethod() {
278     return addMessage("Provider methods must return a value. Do not return void.");
279   }
280 
missingConstantValues()281   public Errors missingConstantValues() {
282     return addMessage("Missing constant value. Please call to(...).");
283   }
284 
cannotInjectInnerClass(Class<?> type)285   public Errors cannotInjectInnerClass(Class<?> type) {
286     return addMessage("Injecting into inner classes is not supported.  "
287         + "Please use a 'static' class (top-level or nested) instead of %s.", type);
288   }
289 
duplicateBindingAnnotations(Member member, Class<? extends Annotation> a, Class<? extends Annotation> b)290   public Errors duplicateBindingAnnotations(Member member,
291       Class<? extends Annotation> a, Class<? extends Annotation> b) {
292     return addMessage("%s has more than one annotation annotated with @BindingAnnotation: "
293         + "%s and %s", member, a, b);
294   }
295 
staticInjectionOnInterface(Class<?> clazz)296   public Errors staticInjectionOnInterface(Class<?> clazz) {
297     return addMessage("%s is an interface, but interfaces have no static injection points.", clazz);
298   }
299 
cannotInjectFinalField(Field field)300   public Errors cannotInjectFinalField(Field field) {
301     return addMessage("Injected field %s cannot be final.", field);
302   }
303 
cannotInjectAbstractMethod(Method method)304   public Errors cannotInjectAbstractMethod(Method method) {
305     return addMessage("Injected method %s cannot be abstract.", method);
306   }
307 
cannotInjectNonVoidMethod(Method method)308   public Errors cannotInjectNonVoidMethod(Method method) {
309     return addMessage("Injected method %s must return void.", method);
310   }
311 
cannotInjectMethodWithTypeParameters(Method method)312   public Errors cannotInjectMethodWithTypeParameters(Method method) {
313     return addMessage("Injected method %s cannot declare type parameters of its own.", method);
314   }
315 
duplicateScopeAnnotations( Class<? extends Annotation> a, Class<? extends Annotation> b)316   public Errors duplicateScopeAnnotations(
317       Class<? extends Annotation> a, Class<? extends Annotation> b) {
318     return addMessage("More than one scope annotation was found: %s and %s.", a, b);
319   }
320 
recursiveBinding()321   public Errors recursiveBinding() {
322     return addMessage("Binding points to itself.");
323   }
324 
bindingAlreadySet(Key<?> key, Object source)325   public Errors bindingAlreadySet(Key<?> key, Object source) {
326     return addMessage("A binding to %s was already configured at %s.", key, convert(source));
327   }
328 
jitBindingAlreadySet(Key<?> key)329   public Errors jitBindingAlreadySet(Key<?> key) {
330     return addMessage("A just-in-time binding to %s was already configured on a parent injector.", key);
331   }
332 
childBindingAlreadySet(Key<?> key, Set<Object> sources)333   public Errors childBindingAlreadySet(Key<?> key, Set<Object> sources) {
334     Formatter allSources = new Formatter();
335     for (Object source : sources) {
336       if (source == null) {
337         allSources.format("%n    (bound by a just-in-time binding)");
338       } else {
339         allSources.format("%n    bound at %s", source);
340       }
341     }
342     Errors errors = addMessage(
343         "Unable to create binding for %s."
344       + " It was already configured on one or more child injectors or private modules"
345       + "%s%n"
346       + "  If it was in a PrivateModule, did you forget to expose the binding?",
347         key, allSources.out());
348     return errors;
349   }
350 
errorCheckingDuplicateBinding(Key<?> key, Object source, Throwable t)351   public Errors errorCheckingDuplicateBinding(Key<?> key, Object source, Throwable t) {
352     return addMessage(
353         "A binding to %s was already configured at %s and an error was thrown "
354       + "while checking duplicate bindings.  Error: %s",
355         key, convert(source), t);
356   }
357 
errorInjectingMethod(Throwable cause)358   public Errors errorInjectingMethod(Throwable cause) {
359     return errorInUserCode(cause, "Error injecting method, %s", cause);
360   }
361 
errorNotifyingTypeListener(TypeListenerBinding listener, TypeLiteral<?> type, Throwable cause)362   public Errors errorNotifyingTypeListener(TypeListenerBinding listener,
363       TypeLiteral<?> type, Throwable cause) {
364     return errorInUserCode(cause,
365         "Error notifying TypeListener %s (bound at %s) of %s.%n"
366         + " Reason: %s",
367         listener.getListener(), convert(listener.getSource()), type, cause);
368   }
369 
errorInjectingConstructor(Throwable cause)370   public Errors errorInjectingConstructor(Throwable cause) {
371     return errorInUserCode(cause, "Error injecting constructor, %s", cause);
372   }
373 
errorInProvider(RuntimeException runtimeException)374   public Errors errorInProvider(RuntimeException runtimeException) {
375     Throwable unwrapped = unwrap(runtimeException);
376     return errorInUserCode(unwrapped, "Error in custom provider, %s", unwrapped);
377   }
378 
errorInUserInjector( MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException cause)379   public Errors errorInUserInjector(
380       MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException cause) {
381     return errorInUserCode(cause, "Error injecting %s using %s.%n"
382         + " Reason: %s", type, listener, cause);
383   }
384 
errorNotifyingInjectionListener( InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException cause)385   public Errors errorNotifyingInjectionListener(
386       InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException cause) {
387     return errorInUserCode(cause, "Error notifying InjectionListener %s of %s.%n"
388         + " Reason: %s", listener, type, cause);
389   }
390 
exposedButNotBound(Key<?> key)391   public Errors exposedButNotBound(Key<?> key) {
392     return addMessage("Could not expose() %s, it must be explicitly bound.", key);
393   }
394 
keyNotFullySpecified(TypeLiteral<?> typeLiteral)395   public Errors keyNotFullySpecified(TypeLiteral<?> typeLiteral) {
396     return addMessage("%s cannot be used as a key; It is not fully specified.", typeLiteral);
397   }
398 
errorEnhancingClass(Class<?> clazz, Throwable cause)399   public Errors errorEnhancingClass(Class<?> clazz, Throwable cause) {
400     return errorInUserCode(cause, "Unable to method intercept: %s", clazz);
401   }
402 
getMessagesFromThrowable(Throwable throwable)403   public static Collection<Message> getMessagesFromThrowable(Throwable throwable) {
404     if (throwable instanceof ProvisionException) {
405       return ((ProvisionException) throwable).getErrorMessages();
406     } else if (throwable instanceof ConfigurationException) {
407       return ((ConfigurationException) throwable).getErrorMessages();
408     } else if (throwable instanceof CreationException) {
409       return ((CreationException) throwable).getErrorMessages();
410     } else {
411       return ImmutableSet.of();
412     }
413   }
414 
errorInUserCode(Throwable cause, String messageFormat, Object... arguments)415   public Errors errorInUserCode(Throwable cause, String messageFormat, Object... arguments) {
416     Collection<Message> messages = getMessagesFromThrowable(cause);
417 
418     if (!messages.isEmpty()) {
419       return merge(messages);
420     } else {
421       return addMessage(cause, messageFormat, arguments);
422     }
423   }
424 
unwrap(RuntimeException runtimeException)425   private Throwable unwrap(RuntimeException runtimeException) {
426    if(runtimeException instanceof Exceptions.UnhandledCheckedUserException) {
427      return runtimeException.getCause();
428    } else {
429      return runtimeException;
430    }
431   }
432 
cannotInjectRawProvider()433   public Errors cannotInjectRawProvider() {
434     return addMessage("Cannot inject a Provider that has no type parameter");
435   }
436 
cannotInjectRawMembersInjector()437   public Errors cannotInjectRawMembersInjector() {
438     return addMessage("Cannot inject a MembersInjector that has no type parameter");
439   }
440 
cannotInjectTypeLiteralOf(Type unsupportedType)441   public Errors cannotInjectTypeLiteralOf(Type unsupportedType) {
442     return addMessage("Cannot inject a TypeLiteral of %s", unsupportedType);
443   }
444 
cannotInjectRawTypeLiteral()445   public Errors cannotInjectRawTypeLiteral() {
446     return addMessage("Cannot inject a TypeLiteral that has no type parameter");
447   }
448 
cannotSatisfyCircularDependency(Class<?> expectedType)449   public Errors cannotSatisfyCircularDependency(Class<?> expectedType) {
450     return addMessage(
451         "Tried proxying %s to support a circular dependency, but it is not an interface.",
452         expectedType);
453   }
454 
circularProxiesDisabled(Class<?> expectedType)455   public Errors circularProxiesDisabled(Class<?> expectedType) {
456     return addMessage(
457         "Tried proxying %s to support a circular dependency, but circular proxies are disabled.",
458         expectedType);
459   }
460 
throwCreationExceptionIfErrorsExist()461   public void throwCreationExceptionIfErrorsExist() {
462     if (!hasErrors()) {
463       return;
464     }
465 
466     throw new CreationException(getMessages());
467   }
468 
throwConfigurationExceptionIfErrorsExist()469   public void throwConfigurationExceptionIfErrorsExist() {
470     if (!hasErrors()) {
471       return;
472     }
473 
474     throw new ConfigurationException(getMessages());
475   }
476 
throwProvisionExceptionIfErrorsExist()477   public void throwProvisionExceptionIfErrorsExist() {
478     if (!hasErrors()) {
479       return;
480     }
481 
482     throw new ProvisionException(getMessages());
483   }
484 
merge(Message message)485   private Message merge(Message message) {
486     List<Object> sources = Lists.newArrayList();
487     sources.addAll(getSources());
488     sources.addAll(message.getSources());
489     return new Message(sources, message.getMessage(), message.getCause());
490   }
491 
merge(Collection<Message> messages)492   public Errors merge(Collection<Message> messages) {
493     for (Message message : messages) {
494       addMessage(merge(message));
495     }
496     return this;
497   }
498 
merge(Errors moreErrors)499   public Errors merge(Errors moreErrors) {
500     if (moreErrors.root == root || moreErrors.root.errors == null) {
501       return this;
502     }
503 
504     merge(moreErrors.root.errors);
505     return this;
506   }
507 
getSources()508   public List<Object> getSources() {
509     List<Object> sources = Lists.newArrayList();
510     for (Errors e = this; e != null; e = e.parent) {
511       if (e.source != SourceProvider.UNKNOWN_SOURCE) {
512         sources.add(0, e.source);
513       }
514     }
515     return sources;
516   }
517 
throwIfNewErrors(int expectedSize)518   public void throwIfNewErrors(int expectedSize) throws ErrorsException {
519     if (size() == expectedSize) {
520       return;
521     }
522 
523     throw toException();
524   }
525 
toException()526   public ErrorsException toException() {
527     return new ErrorsException(this);
528   }
529 
hasErrors()530   public boolean hasErrors() {
531     return root.errors != null;
532   }
533 
addMessage(String messageFormat, Object... arguments)534   public Errors addMessage(String messageFormat, Object... arguments) {
535     return addMessage(null, messageFormat, arguments);
536   }
537 
addMessage(Throwable cause, String messageFormat, Object... arguments)538   private Errors addMessage(Throwable cause, String messageFormat, Object... arguments) {
539     String message = format(messageFormat, arguments);
540     addMessage(new Message(getSources(), message, cause));
541     return this;
542   }
543 
addMessage(Message message)544   public Errors addMessage(Message message) {
545     if (root.errors == null) {
546       root.errors = Lists.newArrayList();
547     }
548     root.errors.add(message);
549     return this;
550   }
551 
format(String messageFormat, Object... arguments)552   public static String format(String messageFormat, Object... arguments) {
553     for (int i = 0; i < arguments.length; i++) {
554       arguments[i] = Errors.convert(arguments[i]);
555     }
556     return String.format(messageFormat, arguments);
557   }
558 
getMessages()559   public List<Message> getMessages() {
560     if (root.errors == null) {
561       return ImmutableList.of();
562     }
563 
564     return new Ordering<Message>() {
565       @Override
566       public int compare(Message a, Message b) {
567         return a.getSource().compareTo(b.getSource());
568       }
569     }.sortedCopy(root.errors);
570   }
571 
572   /** Returns the formatted message for an exception with the specified messages. */
573   public static String format(String heading, Collection<Message> errorMessages) {
574     Formatter fmt = new Formatter().format(heading).format(":%n%n");
575     int index = 1;
576     boolean displayCauses = getOnlyCause(errorMessages) == null;
577 
578     for (Message errorMessage : errorMessages) {
579       fmt.format("%s) %s%n", index++, errorMessage.getMessage());
580 
581       List<Object> dependencies = errorMessage.getSources();
582       for (int i = dependencies.size() - 1; i >= 0; i--) {
583         Object source = dependencies.get(i);
584         formatSource(fmt, source);
585       }
586 
587       Throwable cause = errorMessage.getCause();
588       if (displayCauses && cause != null) {
589         StringWriter writer = new StringWriter();
590         cause.printStackTrace(new PrintWriter(writer));
591         fmt.format("Caused by: %s", writer.getBuffer());
592       }
593 
594       fmt.format("%n");
595     }
596 
597     if (errorMessages.size() == 1) {
598       fmt.format("1 error");
599     } else {
600       fmt.format("%s errors", errorMessages.size());
601     }
602 
603     return fmt.toString();
604   }
605 
606   /**
607    * Returns {@code value} if it is non-null allowed to be null. Otherwise a message is added and
608    * an {@code ErrorsException} is thrown.
609    */
610   public <T> T checkForNull(T value, Object source, Dependency<?> dependency)
611       throws ErrorsException {
612     if (value != null || dependency.isNullable() ) {
613       return value;
614     }
615 
616     // Hack to allow null parameters to @Provides methods, for backwards compatibility.
617     if (dependency.getInjectionPoint().getMember() instanceof Method) {
618       Method annotated = (Method) dependency.getInjectionPoint().getMember();
619       if (annotated.isAnnotationPresent(Provides.class)) {
620         switch (InternalFlags.getNullableProvidesOption()) {
621           case ERROR:
622             break; // break out & let the below exception happen
623           case IGNORE:
624             return value; // user doesn't care about injecting nulls to non-@Nullables.
625           case WARN:
626             // Warn only once, otherwise we spam logs too much.
627             if (!warnedDependencies.add(dependency)) {
628               return value;
629             }
630             logger.log(Level.WARNING,
631                 "Guice injected null into parameter {0} of {1} (a {2}), please mark it @Nullable."
632                     + " Use -Dguice_check_nullable_provides_params=ERROR to turn this into an"
633                     + " error.",
634                 new Object[] {
635                     dependency.getParameterIndex(),
636                     convert(dependency.getInjectionPoint().getMember()),
637                     convert(dependency.getKey())});
638             return null; // log & exit.
639         }
640       }
641     }
642 
643     int parameterIndex = dependency.getParameterIndex();
644     String parameterName = (parameterIndex != -1)
645         ? "parameter " + parameterIndex + " of "
646         : "";
647     addMessage("null returned by binding at %s%n but %s%s is not @Nullable",
648         source, parameterName, dependency.getInjectionPoint().getMember());
649 
650     throw toException();
651   }
652 
653   /**
654    * Returns the cause throwable if there is exactly one cause in {@code messages}. If there are
655    * zero or multiple messages with causes, null is returned.
656    */
657   public static Throwable getOnlyCause(Collection<Message> messages) {
658     Throwable onlyCause = null;
659     for (Message message : messages) {
660       Throwable messageCause = message.getCause();
661       if (messageCause == null) {
662         continue;
663       }
664 
665       if (onlyCause != null) {
666         return null;
667       }
668 
669       onlyCause = messageCause;
670     }
671 
672     return onlyCause;
673   }
674 
675   public int size() {
676     return root.errors == null ? 0 : root.errors.size();
677   }
678 
679   private static abstract class Converter<T> {
680 
681     final Class<T> type;
682 
683     Converter(Class<T> type) {
684       this.type = type;
685     }
686 
687     boolean appliesTo(Object o) {
688       return o != null && type.isAssignableFrom(o.getClass());
689     }
690 
691     String convert(Object o) {
692       return toString(type.cast(o));
693     }
694 
695     abstract String toString(T t);
696   }
697 
698   private static final Collection<Converter<?>> converters = ImmutableList.of(
699       new Converter<Class>(Class.class) {
700         @Override public String toString(Class c) {
701           return c.getName();
702         }
703       },
704       new Converter<Member>(Member.class) {
705         @Override public String toString(Member member) {
706           return Classes.toString(member);
707         }
708       },
709       new Converter<Key>(Key.class) {
710         @Override public String toString(Key key) {
711           if (key.getAnnotationType() != null) {
712             return key.getTypeLiteral() + " annotated with "
713                 + (key.getAnnotation() != null ? key.getAnnotation() : key.getAnnotationType());
714           } else {
715             return key.getTypeLiteral().toString();
716           }
717         }
718       });
719 
720   public static Object convert(Object o) {
721     ElementSource source = null;
722     if (o instanceof ElementSource) {
723       source = (ElementSource)o;
724       o = source.getDeclaringSource();
725     }
726     return convert(o, source);
727   }
728 
729   public static Object convert(Object o, ElementSource source) {
730     for (Converter<?> converter : converters) {
731       if (converter.appliesTo(o)) {
732         return appendModules(converter.convert(o), source);
733       }
734     }
735     return appendModules(o, source);
736   }
737 
738   private static Object appendModules(Object source, ElementSource elementSource) {
739     String modules = moduleSourceString(elementSource);
740     if (modules.length() == 0) {
741       return source;
742     } else {
743       return source + modules;
744     }
745   }
746 
747   private static String moduleSourceString(ElementSource elementSource) {
748     // if we only have one module (or don't know what they are), then don't bother
749     // reporting it, because the source already is going to report exactly that module.
750     if (elementSource == null) {
751       return "";
752     }
753     List<String> modules = Lists.newArrayList(elementSource.getModuleClassNames());
754     // Insert any original element sources w/ module info into the path.
755     while(elementSource.getOriginalElementSource() != null) {
756       elementSource = elementSource.getOriginalElementSource();
757       modules.addAll(0, elementSource.getModuleClassNames());
758     }
759     if (modules.size() <= 1) {
760       return "";
761     }
762 
763     // Ideally we'd do:
764     //    return Joiner.on(" -> ")
765     //        .appendTo(new StringBuilder(" (via modules: "), Lists.reverse(modules))
766     //        .append(")").toString();
767     // ... but for some reason we can't find Lists.reverse, so do it the boring way.
768     StringBuilder builder = new StringBuilder(" (via modules: ");
769     for (int i = modules.size() - 1; i >= 0; i--) {
770       builder.append(modules.get(i));
771       if (i != 0) {
772         builder.append(" -> ");
773       }
774     }
775     builder.append(")");
776     return builder.toString();
777   }
778 
779   public static void formatSource(Formatter formatter, Object source) {
780     ElementSource elementSource = null;
781     if (source instanceof ElementSource) {
782       elementSource = (ElementSource)source;
783       source = elementSource.getDeclaringSource();
784     }
785     formatSource(formatter, source, elementSource);
786   }
787 
788   public static void formatSource(Formatter formatter, Object source, ElementSource elementSource) {
789     String modules = moduleSourceString(elementSource);
790     if (source instanceof Dependency) {
791       Dependency<?> dependency = (Dependency<?>) source;
792       InjectionPoint injectionPoint = dependency.getInjectionPoint();
793       if (injectionPoint != null) {
794         formatInjectionPoint(formatter, dependency, injectionPoint, elementSource);
795       } else {
796         formatSource(formatter, dependency.getKey(), elementSource);
797       }
798 
799     } else if (source instanceof InjectionPoint) {
800       formatInjectionPoint(formatter, null, (InjectionPoint) source, elementSource);
801 
802     } else if (source instanceof Class) {
803       formatter.format("  at %s%s%n", StackTraceElements.forType((Class<?>) source), modules);
804 
805     } else if (source instanceof Member) {
806       formatter.format("  at %s%s%n", StackTraceElements.forMember((Member) source), modules);
807 
808     } else if (source instanceof TypeLiteral) {
809       formatter.format("  while locating %s%s%n", source, modules);
810 
811     } else if (source instanceof Key) {
812       Key<?> key = (Key<?>) source;
813       formatter.format("  while locating %s%n", convert(key, elementSource));
814 
815     } else if (source instanceof Thread) {
816       formatter.format("  in thread %s%n", source);
817 
818     } else {
819       formatter.format("  at %s%s%n", source, modules);
820     }
821   }
822 
823   public static void formatInjectionPoint(Formatter formatter, Dependency<?> dependency,
824       InjectionPoint injectionPoint, ElementSource elementSource) {
825     Member member = injectionPoint.getMember();
826     Class<? extends Member> memberType = Classes.memberType(member);
827 
828     if (memberType == Field.class) {
829       dependency = injectionPoint.getDependencies().get(0);
830       formatter.format("  while locating %s%n", convert(dependency.getKey(), elementSource));
831       formatter.format("    for field at %s%n", StackTraceElements.forMember(member));
832 
833     } else if (dependency != null) {
834       formatter.format("  while locating %s%n", convert(dependency.getKey(), elementSource));
835       formatter.format("    for parameter %s at %s%n",
836           dependency.getParameterIndex(), StackTraceElements.forMember(member));
837 
838     } else {
839       formatSource(formatter, injectionPoint.getMember());
840     }
841   }
842 }
843