PageRenderTime 56ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/core/src/com/google/inject/internal/Errors.java

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