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