Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot default exceptions mapped to standard HTTP status codes

I know it is possible to define custom exception handlers in Spring Boot and have e.g. the IllegalArgumentException exception mapped to the HTTP 400 Bad Request. I am wondering are there any existing exceptions defined in Spring Web/Boot mapped to the standard HTTP status codes? So that I just can throw them and they will be automatically mapped to the standard HTTP status codes.

like image 703
Adam Siemion Avatar asked May 09 '18 11:05

Adam Siemion


People also ask

Which exception class is related to all the exceptions that are thrown in Spring applications?

all the exceptions thrown by the spring jdbc framework are subclasses of dataaccessexception which is a type of runtimeexception, so you need not handle it explicitly.

How does spring boot handle status code?

Spring provides a few primary ways to return custom status codes from its Controller classes: using a ResponseEntity. using the @ResponseStatus annotation on exception classes, and. using the @ControllerAdvice and @ExceptionHandler annotations.

How do you handle exceptions in spring boot?

Exception Handler The @ExceptionHandler is an annotation used to handle the specific exceptions and sending the custom responses to the client. Define a class that extends the RuntimeException class. You can define the @ExceptionHandler method to handle the exceptions as shown.

How does spring boot handle exceptions in REST API?

Altogether, the most common way is to use @ExceptionHandler on methods of @ControllerAdvice classes so that the exception handling will be applied globally or to a subset of controllers. ControllerAdvice is an annotation introduced in Spring 3.2, and as the name suggests, is “Advice” for multiple controllers.


2 Answers

Effectively, ResponseEntityExceptionHandler will, by default, transform Spring internally throwned exceptions to an HTTP status code. However, converting the exception to an HTTP status code does not provide any significant logs about the exception. Good security practices dictate that externally dispatched error message shall be the least informative possible about the internals of a system. Conversely logs shall be as informative as could be.

Moreover, the ResponseEntityExceptionHandler only handle Spring generated exceptions. All business related exceptions must be handled separately. For instance, a "Record not found" exception throwned from a findSomething(xxx) method is not handled by this class.

Following are examples on how to address these shortcomings:

Spring throwned internal errors You must override the handler of the exception(s) of interest and provide both an internal log message and an external error message to be returned to the caller.

The @ControllerAdvice is an annotation that wraps @Component classes with classes declaring @ExceptionHandler annotated methods. Simply put, these handlers will wrap all @Component methods.

@Slf4j
@ControllerAdvice
public class InternalExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    public ResponseEntity<Object> handleMissingServletRequestParameter(
            MissingServletRequestParameterException e,
            HttpHeaders headers,
            HttpStatus status,
            WebRequest request) {

        LogError error = new LogError("MissingServletRequestParameterException", 
                HttpStatus.BAD_REQUEST,
                String.format("Missing '%s' parameter", e.getParameterName()));
        log.debug(error.toJson());

        HttpErrorResponse response = new HttpErrorResponse(error.getStatus(), e.getMessage());
        return new ResponseEntity<>(response.toJson(),
                HeaderFactory.getErrorHeaders(),
                response.getStatus());
    }

    ....
}

Business layer throwned errors

You must first create a specific RuntimeException class for each of these exceptions and annotated it woth @ResponseStatus.

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Record not found") //
public class RecordNotFoundException extends RuntimeException {

    private static final long serialVersionUID = 8857378116992711720L;

    public RecordNotFoundException() {
        super();
    }

    public RecordNotFoundException(String message) {
        super(message);
    }
}

Then, you create an @ControllerAdvice annotated class that will hold all these exceptions handler method. There are no class to derive from as the internal redirection to these @ExceptionHandler annotated methods are managed by Spring.

@Slf4j
@ControllerAdvice
public class ClientExceptionHandler {

    @ExceptionHandler(value = RecordNotFoundException.class)
    public ResponseEntity<String> handleRecordNotFoundException(
            RecordNotFoundException e,
            WebRequest request) {

        LogError logging = new LogError("RecordNotFoundException",
                HttpStatus.NOT_FOUND, 
                request.getDescription(true));
        log.info(logging.toJson());

        HttpErrorResponse response = new HttpErrorResponse(logging.getStatus(), e.getMessage());
        return new ResponseEntity<>(response.toJson(),
                HeaderFactory.getErrorHeaders(),
                response.getStatus());
    }
   ....
}

Finally, the helper classes LogError and HttpErrorResponse are simple formatters for their respective destination.

Hope this helps.

Jake

like image 76
softjake Avatar answered Nov 15 '22 02:11

softjake


There is a handful e.g. HttpRequestMethodNotSupportedException which maps to 405.

Take a look at ResponseEntityExceptionHandler.handleException() method which defines basic rules for handling common exceptions in Spring MVC. You will find

NoSuchRequestHandlingMethodException.class,
HttpRequestMethodNotSupportedException.class,
HttpMediaTypeNotSupportedException.class,
HttpMediaTypeNotAcceptableException.class,
MissingPathVariableException.class,
MissingServletRequestParameterException.class,
ServletRequestBindingException.class,
ConversionNotSupportedException.class,
TypeMismatchException.class,
HttpMessageNotReadableException.class,
HttpMessageNotWritableException.class,
MethodArgumentNotValidException.class,
MissingServletRequestPartException.class,
BindException.class,
NoHandlerFoundException.class,
AsyncRequestTimeoutException.class
like image 42
Karol Dowbecki Avatar answered Nov 15 '22 04:11

Karol Dowbecki