guice/src/main/java/com/google/inject/spi/ErrorDetail.java

127 lines
4.4 KiB
Java

package com.google.inject.spi;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.inject.internal.Messages;
import java.io.Serializable;
import java.util.Formatter;
import java.util.List;
import java.util.Optional;
/**
* Details about a single Guice error and supports formatting itself in the context of other Guice
* errors.
*
* <p>WARNING: The class and its APIs are still experimental and subject to change.
*
* @since 5.0
*/
public abstract class ErrorDetail<SelfT extends ErrorDetail<SelfT>> implements Serializable {
private final String message;
private final ImmutableList<Object> sources;
private final Throwable cause;
protected ErrorDetail(String message, List<Object> sources, Throwable cause) {
this.message = message;
this.sources = ImmutableList.copyOf(sources);
this.cause = cause;
}
/**
* Returns true if this error can be merged with the {@code otherError} and formatted together.
*
* <p>By default this return false and implementations that support merging with other errors
* should override this method.
*/
public boolean isMergeable(ErrorDetail<?> otherError) {
return false;
}
/**
* Formats this error along with other errors that are mergeable with this error.
*
* <p>{@code mergeableErrors} is a list that contains all other errors that are reported in the
* same exception that are considered to be mergable with this error base on result of calling
* {@link #isMergeable}. The list will be empty if non of the other errors are mergable with this
* error.
*
* <p>Formatted error has the following structure:
*
* <ul>
* <li>Summary of the error
* <li>Details about the error such as the source of the error
* <li>Hints for fixing the error if available
* <li>Link to the documentation on this error in greater detail
*
* @param index index for this error
* @param mergeableErrors list of errors that are mergeable with this error
* @param formatter for printing the error message
*/
public final void format(int index, List<ErrorDetail<?>> mergeableErrors, Formatter formatter) {
String id = getErrorIdentifier().map(s -> "[" + Messages.redBold(s) + "]: ").orElse("");
formatter.format("%s) %s%s%n", index, id, getMessage());
formatDetail(mergeableErrors, formatter);
// TODO(b/151482394): Output potiential fixes for the error
Optional<String> learnMoreLink = getLearnMoreLink();
if (learnMoreLink.isPresent()) {
formatter.format("%n%s%n", Messages.bold("Learn more:"));
formatter.format(" %s%n", Messages.underline(learnMoreLink.get()));
}
}
/**
* Formats the detail of this error message along with other errors that are mergeable with this
* error. This is called from {@link #format}.
*
* <p>{@code mergeableErrors} is a list that contains all other errors that are reported in the
* same exception that are considered to be mergable with this error base on result of calling
* {@link #isMergeable}. The list will be empty if non of the other errors are mergable with this
* error.
*
* @param mergeableErrors list of errors that are mergeable with this error
* @param formatter for printing the error message
*/
protected abstract void formatDetail(List<ErrorDetail<?>> mergeableErrors, Formatter formatter);
/**
* Returns an optional link to additional documentation about this error to be included in the
* formatted error message.
*/
protected Optional<String> getLearnMoreLink() {
return Optional.empty();
}
/** Returns an optional string identifier for this error. */
protected Optional<String> getErrorIdentifier() {
return Optional.empty();
}
public String getMessage() {
return message;
}
public List<Object> getSources() {
return sources;
}
public Throwable getCause() {
return cause;
}
@Override
public int hashCode() {
return Objects.hashCode(message, cause, sources);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ErrorDetail)) {
return false;
}
ErrorDetail<?> e = (ErrorDetail<?>) o;
return message.equals(e.message) && Objects.equal(cause, e.cause) && sources.equals(e.sources);
}
/** Returns a new instance of the same {@link ErrorDetail} with updated sources. */
public abstract SelfT withSources(List<Object> newSources);
}