or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

api-versioning.mdasync.mdconfiguration.mdcontent-negotiation.mdcontroller-annotations.mdcore-framework.mdcors.mddata-binding.mdexception-handling.mdflash-attributes.mdfunctional-endpoints.mdi18n.mdindex.mdinterceptors.mdmultipart.mdrequest-binding.mdresource-handling.mdresponse-handling.mduri-building.mdview-resolution.md
tile.json

exception-handling.mddocs/

Exception Handling

Annotations and classes for handling exceptions in Spring MVC applications, mapping exceptions to HTTP responses, and providing global error handling advice across controllers.

Capabilities

@ExceptionHandler

Marks a method to handle specific exceptions thrown by controller methods. Can be used within a controller for local exception handling or within @ControllerAdvice for global exception handling.

/**
 * Annotation for handling exceptions in specific handler classes and/or handler methods.
 *
 * Handler methods which are annotated with this annotation are allowed to have very flexible
 * signatures. They may have parameters of the following types, in arbitrary order:
 * - An exception argument: declared as a general Exception or as a more specific exception.
 * - Request and/or response objects (typically from the Servlet API).
 * - Session object: typically HttpSession.
 * - WebRequest or NativeWebRequest.
 * - Locale for the current request locale.
 * - InputStream/Reader for access to the request's content.
 * - OutputStream/Writer for generating the response's content.
 * - Model as an alternative to returning a model map from the handler method.
 *
 * Handler methods can return:
 * - A ModelAndView object (from Servlet MVC).
 * - A Model object, with the view name implicitly determined through a RequestToViewNameTranslator.
 * - A Map object for exposing a model, with the view name implicitly determined through a RequestToViewNameTranslator.
 * - A View object.
 * - A String value which is interpreted as view name.
 * - @ResponseBody annotated methods (Servlet-only) to set the response content.
 * - A ResponseEntity object to set response headers and content.
 * - void if the method handles the response itself.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {
    /**
     * Exceptions handled by the annotated method. If empty, will default to any
     * exceptions listed in the method argument list.
     */
    Class<? extends Throwable>[] value() default {};
}

Usage Example:

@RestController
@RequestMapping("/api/products")
public class ProductController {

    @GetMapping("/{id}")
    public Product getProduct(@PathVariable Long id) {
        return productService.findById(id);
    }

    // Local exception handler for this controller
    @ExceptionHandler(ProductNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleProductNotFound(ProductNotFoundException ex) {
        ErrorResponse error = new ErrorResponse(
            "PRODUCT_NOT_FOUND",
            ex.getMessage(),
            HttpStatus.NOT_FOUND.value()
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException ex) {
        ErrorResponse error = new ErrorResponse(
            "INVALID_ARGUMENT",
            ex.getMessage(),
            HttpStatus.BAD_REQUEST.value()
        );
        return ResponseEntity.badRequest().body(error);
    }

    // Handle multiple exception types
    @ExceptionHandler({ProductOutOfStockException.class, ProductDiscontinuedException.class})
    public ResponseEntity<ErrorResponse> handleProductUnavailable(RuntimeException ex) {
        ErrorResponse error = new ErrorResponse(
            "PRODUCT_UNAVAILABLE",
            ex.getMessage(),
            HttpStatus.CONFLICT.value()
        );
        return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
    }

    // Access request information in exception handler
    @ExceptionHandler(ValidationException.class)
    public ResponseEntity<ErrorResponse> handleValidation(
            ValidationException ex,
            WebRequest request) {
        String path = request.getDescription(false);
        ErrorResponse error = new ErrorResponse(
            "VALIDATION_FAILED",
            ex.getMessage(),
            HttpStatus.BAD_REQUEST.value(),
            path
        );
        return ResponseEntity.badRequest().body(error);
    }
}

@ControllerAdvice

Marks a class with global @ExceptionHandler, @InitBinder, or @ModelAttribute methods that apply to multiple controllers. Supports selective application to specific controllers, packages, or annotations.

/**
 * Specialization of @Component for classes that declare @ExceptionHandler, @InitBinder,
 * or @ModelAttribute methods to be shared across multiple @Controller classes.
 *
 * Classes annotated with @ControllerAdvice are auto-detected through classpath scanning
 * if configured as Spring beans.
 *
 * @ControllerAdvice is typically used in combination with @ExceptionHandler methods
 * for global error handling in the web tier.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
    /**
     * Alias for {@link #basePackages}.
     * Allows for more concise annotation declarations.
     */
    @AliasFor("basePackages")
    String[] value() default {};

    /**
     * Array of base packages.
     * Controllers that belong to those base packages or sub-packages thereof
     * will be included, e.g.: "org.example.web".
     */
    @AliasFor("value")
    String[] basePackages() default {};

    /**
     * Type-safe alternative to {@link #basePackages} for specifying the packages
     * to select controllers to be advised by the @ControllerAdvice annotated class.
     * The package of each class specified will be used.
     */
    Class<?>[] basePackageClasses() default {};

    /**
     * Array of classes.
     * Controllers that are assignable to at least one of the given types
     * will be advised by the @ControllerAdvice annotated class.
     */
    Class<?>[] assignableTypes() default {};

    /**
     * Array of annotations.
     * Controllers that are annotated with at least one of the supplied annotations
     * will be advised by the @ControllerAdvice annotated class.
     * Consider creating a custom composed annotation or use multiple
     * @ControllerAdvice declarations to target specific groups of controllers.
     */
    Class<? extends Annotation>[] annotations() default {};
}

Usage Example:

// Global exception handler for all controllers
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse(
            "RESOURCE_NOT_FOUND",
            ex.getMessage(),
            HttpStatus.NOT_FOUND.value()
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
        ErrorResponse error = new ErrorResponse(
            "INTERNAL_ERROR",
            "An unexpected error occurred",
            HttpStatus.INTERNAL_SERVER_ERROR.value()
        );
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ValidationErrorResponse> handleValidationErrors(
            MethodArgumentNotValidException ex) {
        List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
        ValidationErrorResponse error = new ValidationErrorResponse(
            "VALIDATION_FAILED",
            fieldErrors
        );
        return ResponseEntity.badRequest().body(error);
    }
}

// Controller advice for specific package
@ControllerAdvice(basePackages = "com.example.api.admin")
public class AdminControllerAdvice {

    @ExceptionHandler(UnauthorizedException.class)
    public ResponseEntity<ErrorResponse> handleUnauthorized(UnauthorizedException ex) {
        ErrorResponse error = new ErrorResponse(
            "UNAUTHORIZED",
            "Admin access required",
            HttpStatus.UNAUTHORIZED.value()
        );
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(error);
    }
}

// Controller advice for specific controller types
@ControllerAdvice(assignableTypes = {UserController.class, AccountController.class})
public class UserAccountAdvice {

    @ModelAttribute("currentUser")
    public User getCurrentUser() {
        return securityService.getCurrentUser();
    }

    @ExceptionHandler(AccountLockedException.class)
    public ResponseEntity<ErrorResponse> handleAccountLocked(AccountLockedException ex) {
        ErrorResponse error = new ErrorResponse(
            "ACCOUNT_LOCKED",
            ex.getMessage(),
            HttpStatus.FORBIDDEN.value()
        );
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
    }
}

// Controller advice for REST controllers only
@ControllerAdvice(annotations = RestController.class)
public class RestControllerAdvice {

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseEntity<ErrorResponse> handleInvalidJson(HttpMessageNotReadableException ex) {
        ErrorResponse error = new ErrorResponse(
            "INVALID_JSON",
            "Invalid JSON in request body",
            HttpStatus.BAD_REQUEST.value()
        );
        return ResponseEntity.badRequest().body(error);
    }
}

@RestControllerAdvice

Convenience annotation that combines @ControllerAdvice and @ResponseBody. All exception handler methods automatically serialize their return values to the response body.

/**
 * A convenience annotation that is itself annotated with @ControllerAdvice and @ResponseBody.
 *
 * Types that carry this annotation are treated as controller advice where @ExceptionHandler
 * methods assume @ResponseBody semantics by default.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {
    /**
     * Alias for {@link ControllerAdvice#basePackages}.
     */
    @AliasFor(annotation = ControllerAdvice.class)
    String[] value() default {};

    /**
     * Alias for {@link ControllerAdvice#basePackages}.
     */
    @AliasFor(annotation = ControllerAdvice.class)
    String[] basePackages() default {};

    /**
     * Type-safe alternative to {@link #basePackages} for specifying the packages
     * to select controllers to be advised.
     */
    @AliasFor(annotation = ControllerAdvice.class)
    Class<?>[] basePackageClasses() default {};

    /**
     * Array of classes. Controllers that are assignable to at least one of the
     * given types will be advised.
     */
    @AliasFor(annotation = ControllerAdvice.class)
    Class<?>[] assignableTypes() default {};

    /**
     * Array of annotations. Controllers that are annotated with at least one of
     * the supplied annotations will be advised.
     */
    @AliasFor(annotation = ControllerAdvice.class)
    Class<? extends Annotation>[] annotations() default {};
}

Usage Example:

@RestControllerAdvice
public class RestExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(RestExceptionHandler.class);

    @ExceptionHandler(ResourceNotFoundException.class)
    public ErrorResponse handleResourceNotFound(ResourceNotFoundException ex) {
        logger.warn("Resource not found: {}", ex.getMessage());
        return new ErrorResponse(
            "RESOURCE_NOT_FOUND",
            ex.getMessage(),
            HttpStatus.NOT_FOUND.value(),
            Instant.now()
        );
    }

    @ExceptionHandler(DataIntegrityViolationException.class)
    public ErrorResponse handleDataIntegrityViolation(DataIntegrityViolationException ex) {
        logger.error("Data integrity violation", ex);
        return new ErrorResponse(
            "DATA_INTEGRITY_VIOLATION",
            "Data constraint violation occurred",
            HttpStatus.CONFLICT.value(),
            Instant.now()
        );
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ValidationErrorResponse handleValidationErrors(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error ->
            errors.put(error.getField(), error.getDefaultMessage())
        );
        return new ValidationErrorResponse(
            "VALIDATION_FAILED",
            errors,
            HttpStatus.BAD_REQUEST.value()
        );
    }
}

// REST controller advice for specific base package
@RestControllerAdvice(basePackages = "com.example.api")
public class ApiExceptionHandler {

    @ExceptionHandler(ApiException.class)
    public ResponseEntity<ApiErrorResponse> handleApiException(ApiException ex) {
        ApiErrorResponse error = new ApiErrorResponse(
            ex.getErrorCode(),
            ex.getMessage(),
            ex.getDetails()
        );
        return ResponseEntity.status(ex.getStatus()).body(error);
    }
}

ResponseEntityExceptionHandler

Base class for @ControllerAdvice classes that provides centralized exception handling for standard Spring MVC exceptions. Provides protected methods to customize the response for each exception type.

/**
 * A convenient base class for @ControllerAdvice classes that wish to provide
 * centralized exception handling across all @RequestMapping methods through
 * @ExceptionHandler methods.
 *
 * This base class provides an @ExceptionHandler method for handling internal
 * Spring MVC exceptions. This method returns a ResponseEntity for writing to
 * the response with a MessageConverter, in contrast to
 * DefaultHandlerExceptionResolver which returns a ModelAndView.
 *
 * If there is no need to write error content to the response body, or when
 * using view resolution (e.g. via ContentNegotiatingViewResolver), then
 * DefaultHandlerExceptionResolver is good enough.
 */
public abstract class ResponseEntityExceptionHandler {
    /**
     * A logger available to subclasses.
     */
    protected final Log logger = LogFactory.getLog(getClass());

    /**
     * Provides handling for standard Spring MVC exceptions.
     *
     * @param ex the target exception
     * @param request the current request
     * @return a ResponseEntity instance
     */
    @ExceptionHandler({
        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
    })
    public final ResponseEntity<Object> handleException(Exception ex, WebRequest request) {}

    /**
     * Customize the response for HttpRequestMethodNotSupportedException.
     * This method delegates to handleExceptionInternal.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(
            HttpRequestMethodNotSupportedException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for HttpMediaTypeNotSupportedException.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleHttpMediaTypeNotSupported(
            HttpMediaTypeNotSupportedException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for HttpMediaTypeNotAcceptableException.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(
            HttpMediaTypeNotAcceptableException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for MissingPathVariableException.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleMissingPathVariable(
            MissingPathVariableException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for MissingServletRequestParameterException.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleMissingServletRequestParameter(
            MissingServletRequestParameterException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for MethodArgumentNotValidException.
     * This method delegates to handleExceptionInternal.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for BindException.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleBindException(
            BindException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for TypeMismatchException.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleTypeMismatch(
            TypeMismatchException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for HttpMessageNotReadableException.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleHttpMessageNotReadable(
            HttpMessageNotReadableException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for HttpMessageNotWritableException.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleHttpMessageNotWritable(
            HttpMessageNotWritableException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for NoHandlerFoundException.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleNoHandlerFoundException(
            NoHandlerFoundException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * Customize the response for AsyncRequestTimeoutException.
     *
     * @param ex the exception
     * @param headers the headers to be written to the response
     * @param status the selected response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleAsyncRequestTimeoutException(
            AsyncRequestTimeoutException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {}

    /**
     * A single place to customize the response body of all exception types.
     * The default implementation sets the WebUtils.ERROR_EXCEPTION_ATTRIBUTE
     * request attribute and creates a ResponseEntity from the given body,
     * headers, and status.
     *
     * @param ex the exception
     * @param body the body for the response
     * @param headers the headers for the response
     * @param statusCode the response status
     * @param request the current request
     * @return a ResponseEntity instance
     */
    protected ResponseEntity<Object> handleExceptionInternal(
            Exception ex,
            Object body,
            HttpHeaders headers,
            HttpStatusCode statusCode,
            WebRequest request) {}

    /**
     * Create the ResponseEntity to use from the given body, headers, and statusCode.
     * Subclasses can override this method to provide a custom body.
     *
     * @param body the body to use for the response (may be null)
     * @param headers the headers for the response
     * @param statusCode the status code for the response
     * @param request the current request
     * @return the created ResponseEntity
     */
    protected ResponseEntity<Object> createResponseEntity(
            Object body,
            HttpHeaders headers,
            HttpStatusCode statusCode,
            WebRequest request) {}
}

Usage Example:

@RestControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {

    // Override to customize handling of validation errors
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error ->
            errors.put(error.getField(), error.getDefaultMessage())
        );

        ValidationErrorResponse body = new ValidationErrorResponse(
            "VALIDATION_FAILED",
            errors,
            status.value()
        );

        return handleExceptionInternal(ex, body, headers, status, request);
    }

    // Override to customize handling of missing parameters
    @Override
    protected ResponseEntity<Object> handleMissingServletRequestParameter(
            MissingServletRequestParameterException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {
        ErrorResponse body = new ErrorResponse(
            "MISSING_PARAMETER",
            String.format("Required parameter '%s' is missing", ex.getParameterName()),
            status.value()
        );

        return handleExceptionInternal(ex, body, headers, status, request);
    }

    // Override to customize handling of unsupported media type
    @Override
    protected ResponseEntity<Object> handleHttpMediaTypeNotSupported(
            HttpMediaTypeNotSupportedException ex,
            HttpHeaders headers,
            HttpStatusCode status,
            WebRequest request) {
        StringBuilder builder = new StringBuilder();
        builder.append(ex.getContentType());
        builder.append(" media type is not supported. Supported media types are ");
        ex.getSupportedMediaTypes().forEach(t -> builder.append(t).append(", "));

        ErrorResponse body = new ErrorResponse(
            "UNSUPPORTED_MEDIA_TYPE",
            builder.substring(0, builder.length() - 2),
            status.value()
        );

        return handleExceptionInternal(ex, body, headers, status, request);
    }

    // Handle custom application exceptions
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Object> handleBusinessException(
            BusinessException ex,
            WebRequest request) {
        ErrorResponse body = new ErrorResponse(
            ex.getErrorCode(),
            ex.getMessage(),
            HttpStatus.UNPROCESSABLE_ENTITY.value()
        );

        return handleExceptionInternal(
            ex,
            body,
            new HttpHeaders(),
            HttpStatus.UNPROCESSABLE_ENTITY,
            request
        );
    }

    // Override to customize all exception responses
    @Override
    protected ResponseEntity<Object> handleExceptionInternal(
            Exception ex,
            Object body,
            HttpHeaders headers,
            HttpStatusCode statusCode,
            WebRequest request) {
        // Log the exception
        logger.error("Exception occurred", ex);

        // If body is null, create a default error response
        if (body == null) {
            body = new ErrorResponse(
                "ERROR",
                ex.getMessage(),
                statusCode.value()
            );
        }

        return super.handleExceptionInternal(ex, body, headers, statusCode, request);
    }
}

Types

Common Spring MVC Exceptions

Standard exceptions handled by Spring MVC exception handling infrastructure.

/**
 * Exception thrown when a request handler does not support a specific request method.
 */
public class HttpRequestMethodNotSupportedException extends ServletException {
    public HttpRequestMethodNotSupportedException(String method) {}
    public HttpRequestMethodNotSupportedException(String method, String msg) {}
    public HttpRequestMethodNotSupportedException(String method, Collection<String> supportedMethods) {}
    public String getMethod() {}
    public String[] getSupportedMethods() {}
}

/**
 * Exception thrown when a client POSTs, PUTs, or PATCHes content of a type not supported by request handler.
 */
public class HttpMediaTypeNotSupportedException extends ServletException {
    public HttpMediaTypeNotSupportedException(String msg) {}
    public HttpMediaTypeNotSupportedException(MediaType contentType, List<MediaType> supportedMediaTypes) {}
    public MediaType getContentType() {}
    public List<MediaType> getSupportedMediaTypes() {}
}

/**
 * Exception thrown when the request handler cannot generate a response that is acceptable by the client.
 */
public class HttpMediaTypeNotAcceptableException extends ServletException {
    public HttpMediaTypeNotAcceptableException(String message) {}
    public HttpMediaTypeNotAcceptableException(List<MediaType> supportedMediaTypes) {}
    public List<MediaType> getSupportedMediaTypes() {}
}

/**
 * Exception thrown when a required path variable is missing.
 */
public class MissingPathVariableException extends ServletException {
    public MissingPathVariableException(String variableName, MethodParameter parameter) {}
    public String getVariableName() {}
    public MethodParameter getParameter() {}
}

/**
 * Exception thrown when a required request parameter is missing.
 */
public class MissingServletRequestParameterException extends ServletException {
    public MissingServletRequestParameterException(String parameterName, String parameterType) {}
    public String getParameterName() {}
    public String getParameterType() {}
}

/**
 * Exception thrown when validation on an argument annotated with @Valid fails.
 */
public class MethodArgumentNotValidException extends BindException {
    public MethodArgumentNotValidException(MethodParameter parameter, BindingResult bindingResult) {}
    public MethodParameter getParameter() {}
}

/**
 * Exception thrown when the request is missing a part in a multipart request.
 */
public class MissingServletRequestPartException extends ServletException {
    public MissingServletRequestPartException(String partName) {}
    public String getRequestPartName() {}
}

/**
 * Exception to be thrown when no handler is found for a request.
 */
public class NoHandlerFoundException extends ServletException {
    public NoHandlerFoundException(String httpMethod, String requestURL, HttpHeaders headers) {}
    public String getHttpMethod() {}
    public String getRequestURL() {}
    public HttpHeaders getHeaders() {}
}

/**
 * Exception thrown when an async request times out.
 */
public class AsyncRequestTimeoutException extends RuntimeException {
    public AsyncRequestTimeoutException() {}
}