Class XResponseEntityExceptionHandler

java.lang.Object
org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
uk.ac.ebi.utils.opt.springweb.exceptions.XResponseEntityExceptionHandler
All Implemented Interfaces:
org.springframework.beans.factory.Aware, org.springframework.context.MessageSourceAware

public class XResponseEntityExceptionHandler extends org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
A better web exception handler. This catches all exceptions happening while answering to a web requests (ie, in the controllers) and return a proper HTTP status with a proper response body. Namely, the latter is based on createProblemDetail(Exception, HttpStatusCode, String, String, Object[], WebRequest), which in turn, is based on RFC-9457. TODO: I've tested it in dependents only.
Author:
Marco Brandizi
Date:
30 Aug 2024
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    protected Map<Class<? extends Exception>,org.springframework.http.HttpStatusCode>
    Maps known exceptions to HTTP statuses.
    protected boolean
    If true, createProblemDetail(Exception, HttpStatusCode, String, String, Object[], WebRequest) adds a 'trace' field to the RFC-9457 output all the exceptions in this class produce.

    Fields inherited from class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler

    logger, PAGE_NOT_FOUND_LOG_CATEGORY, pageNotFoundLogger
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    protected org.springframework.http.ProblemDetail
    createProblemDetail(Exception ex, org.springframework.http.HttpStatusCode status, String defaultDetail, String detailMessageCode, Object[] detailMessageArguments, org.springframework.web.context.request.WebRequest request)
    Tweaks the original output to return more significant values: - sets detail to the most significant message from ex - sets title to the original detail (which isn't so detailed), discards the original title (since it has low information most of the times) - sets type to the FQN of ex - adds the 'trace' property with the exception's stack trace (TODO: make it optional) As in the superclass, this is used by handleExceptionInternal(Exception, Object, HttpHeaders, HttpStatusCode, WebRequest).
    protected org.springframework.http.HttpStatusCode
    protected org.springframework.http.ResponseEntity<Object>
    handleExceptionInternal(Exception ex, Object body, org.springframework.http.HttpHeaders headers, org.springframework.http.HttpStatusCode statusCode, org.springframework.web.context.request.WebRequest request)
    All exceptions are eventually routed here.
    org.springframework.http.ResponseEntity<Object>
    handleMappedException(Exception ex, org.springframework.web.context.request.WebRequest request)
    Our own catch-all wrapper This tries to see if the exception is associated to some HTTP status code, by using findExceptionMapping(Exception).

    Methods inherited from class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler

    createResponseEntity, getMessageSource, handleAsyncRequestTimeoutException, handleBindException, handleConversionNotSupported, handleErrorResponseException, handleException, handleHandlerMethodValidationException, handleHttpMediaTypeNotAcceptable, handleHttpMediaTypeNotSupported, handleHttpMessageNotReadable, handleHttpMessageNotWritable, handleHttpRequestMethodNotSupported, handleMaxUploadSizeExceededException, handleMethodArgumentNotValid, handleMethodValidationException, handleMissingPathVariable, handleMissingServletRequestParameter, handleMissingServletRequestPart, handleNoHandlerFoundException, handleNoResourceFoundException, handleServletRequestBindingException, handleTypeMismatch, setMessageSource

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • exception2StatusCode

      protected Map<Class<? extends Exception>,org.springframework.http.HttpStatusCode> exception2StatusCode
      Maps known exceptions to HTTP statuses. This is scanned in the order you define the classes and that MUST be from the most specific one to the more generic.
    • isStackTraceEnabled

      protected boolean isStackTraceEnabled
      If true, createProblemDetail(Exception, HttpStatusCode, String, String, Object[], WebRequest) adds a 'trace' field to the RFC-9457 output all the exceptions in this class produce.
  • Constructor Details

    • XResponseEntityExceptionHandler

      public XResponseEntityExceptionHandler()
  • Method Details

    • handleMappedException

      @ExceptionHandler public org.springframework.http.ResponseEntity<Object> handleMappedException(Exception ex, org.springframework.web.context.request.WebRequest request)
      Our own catch-all wrapper This tries to see if the exception is associated to some HTTP status code, by using findExceptionMapping(Exception). It then invokes handleExceptionInternal(Exception, Object, HttpHeaders, HttpStatusCode, WebRequest) with the found status code (or null code). This bypasses ResponseEntityExceptionHandler.handleException(Exception, WebRequest) and all the defaults in the parent handler. We have tried the alternative route to call this method with a ResponseStatusException wrapper, but we don't want the latter to be returned to the client as top-level exception. Instead, we intercept occurred exceptions here and then we call handleExceptionInternal(Exception, Object, HttpHeaders, HttpStatusCode, WebRequest).
    • handleExceptionInternal

      @Nullable protected org.springframework.http.ResponseEntity<Object> handleExceptionInternal(Exception ex, @Nullable Object body, org.springframework.http.HttpHeaders headers, org.springframework.http.HttpStatusCode statusCode, org.springframework.web.context.request.WebRequest request)
      All exceptions are eventually routed here.

      Does some tweaking of the default parent internal handler, before calling it as delegate:

      Overrides:
      handleExceptionInternal in class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
    • createProblemDetail

      protected org.springframework.http.ProblemDetail createProblemDetail(Exception ex, org.springframework.http.HttpStatusCode status, String defaultDetail, @Nullable String detailMessageCode, @Nullable Object[] detailMessageArguments, org.springframework.web.context.request.WebRequest request)
      Tweaks the original output to return more significant values: - sets detail to the most significant message from ex - sets title to the original detail (which isn't so detailed), discards the original title (since it has low information most of the times) - sets type to the FQN of ex - adds the 'trace' property with the exception's stack trace (TODO: make it optional) As in the superclass, this is used by handleExceptionInternal(Exception, Object, HttpHeaders, HttpStatusCode, WebRequest).
      Overrides:
      createProblemDetail in class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
    • findExceptionMapping

      protected org.springframework.http.HttpStatusCode findExceptionMapping(Exception ex)
      Used within handleMappedException(Exception, WebRequest). It tries to find one class in exception2StatusCode that is the same class of ex or a parent of it.
      Returns:
      the corresponding status if it finds something, null otherwise.