me.alidg.errors.adapter.attributes.ServletErrorAttributes Maven / Gradle / Ivy
package me.alidg.errors.adapter.attributes;
import me.alidg.errors.HttpError;
import me.alidg.errors.WebErrorHandlers;
import me.alidg.errors.adapter.HttpErrorAttributesAdapter;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.web.context.request.WebRequest;
import java.util.Map;
import static java.util.Objects.requireNonNull;
import static org.springframework.web.context.request.RequestAttributes.SCOPE_REQUEST;
/**
* Custom implementation of {@link org.springframework.boot.web.servlet.error.ErrorAttributes}
* which adapts the handled {@link HttpError} to a Spring Boot's compatible error attributes
* representation.
*
* @author Ali Dehghani
* @see HttpError
* @see HttpErrorAttributesAdapter
* @see org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController
*/
public class ServletErrorAttributes extends DefaultErrorAttributes {
/**
* To convey the status code from the handled exception to the
* {@link org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController}.
*/
private static final String STATUS_CODE_ATTR = "javax.servlet.error.status_code";
/**
* To handle exceptions.
*/
private final WebErrorHandlers webErrorHandlers;
/**
* To adapt our representation of an error to Spring Boot's representation.
*/
private final HttpErrorAttributesAdapter httpErrorAttributesAdapter;
/**
* Initializes the error attributes with required dependencies.
*
* @param webErrorHandlers To handle exceptions.
* @param httpErrorAttributesAdapter To adapt our representation of an error to Spring Boot's representation.
* @throws NullPointerException When one of the required parameters is null.
*/
public ServletErrorAttributes(WebErrorHandlers webErrorHandlers,
HttpErrorAttributesAdapter httpErrorAttributesAdapter) {
requireNonNull(webErrorHandlers, "Web error handlers is required");
requireNonNull(httpErrorAttributesAdapter, "Adapter is required");
this.webErrorHandlers = webErrorHandlers;
this.httpErrorAttributesAdapter = httpErrorAttributesAdapter;
}
/**
* Extracts the thrown exception from the request attributes. If it was null, then checks the stored
* status code and tries its best to find an exception related to that status code. Finally, handles
* the exception using the {@link #webErrorHandlers} and adapts the returned {@link HttpError} to a
* Spring Boot compatible representation.
*
* @param webRequest The current HTTP request.
* @param includeStackTrace Whether or not to include the stack trace in the error attributes.
* @return Error details.
*/
@Override
public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map attributes = super.getErrorAttributes(webRequest, includeStackTrace);
Throwable exception = getError(webRequest);
if (exception == null) exception = Exceptions.refineUnknownException(attributes);
HttpError httpError = webErrorHandlers.handle(exception, webRequest, webRequest.getLocale());
saveStatusCodeInRequest(webRequest, httpError);
return httpErrorAttributesAdapter.adapt(httpError);
}
/**
* Storing the handled status code in the request as an attribute. The
* {@link org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController}
* would use this status code when it's writing the HTTP response.
*
* @param webRequest The request.
* @param httpError Represents the handled exception.
*/
private void saveStatusCodeInRequest(WebRequest webRequest, HttpError httpError) {
int statusCode = httpError.getHttpStatus().value();
webRequest.setAttribute(STATUS_CODE_ATTR, statusCode, SCOPE_REQUEST);
}
}