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.
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.
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.
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.
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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With