skip to content

What method arguments and return types can a local @ExceptionHandler method declare?

level: middleimportance: should knowfreq 48%

answer

  1. exception or its supertype is the key arg
  2. HandlerMethod, WebRequest, HttpServletRequest/Response, HttpSession, Principal, Locale
  3. Model/Map arg is always empty
  4. no @RequestBody / command objects
  5. returns ResponseEntity / body+@ResponseStatus / view / void

basics

~20 s

It can take the exception itself, plus request-related things like WebRequest, HttpServletRequest/Response, HttpSession, Principal, Locale, and HandlerMethod. It returns the same values as a normal controller: ResponseEntity, an @ResponseBody object, a view name, ModelAndView, or void.

solid answer

~40 s

An @ExceptionHandler method can declare a focused set of arguments: the raised exception (or a supertype of it), the HandlerMethod that failed, WebRequest/NativeWebRequest, Servlet types (HttpServletRequest/Response, HttpSession), Principal, HttpMethod, Locale/TimeZone/ZoneId, OutputStream/Writer, and the Model/Map (which is always empty for error responses), plus RedirectAttributes and @SessionAttribute/@RequestAttribute. It cannot bind @RequestBody, command objects, @RequestParam-style handler-input beyond those. Return types mirror a normal controller method: ResponseEntity for full control, an object rendered via @ResponseBody (implicit in @RestController) usually paired with @ResponseStatus, a String view name, ModelAndView, or void if you write the response directly. Declaring the exception parameter is also how Spring infers which type to catch when the annotation value is empty.

code

java · 11 lines
java
@ExceptionHandler // empty value: type inferred from the parameter
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
ApiError handleValidation(ValidationException ex,
                          HandlerMethod failing,   // which endpoint threw
                          WebRequest request,       // request/session access
                          Locale locale) {          // for i18n messages
    return new ApiError("VALIDATION",
            messages.get(ex.getCode(), locale),
            request.getDescription(false));
}

go deeper

for a junior

Know that at minimum the handler receives the exception object and returns a response.

for a middle

List the common supported args (exception, HandlerMethod, WebRequest, Servlet types, Principal, Locale) and the return options.

for a senior

Call out that Model is always empty and that a plain body without @ResponseStatus yields 200.

for a principal

Relate the argument set to HandlerMethodArgumentResolver reuse and why body-binding resolvers are intentionally excluded here.

## Supported method arguments An `@ExceptionHandler` method is invoked by `ExceptionHandlerExceptionResolver` using argument resolvers similar to (but a narrower set than) normal `@RequestMapping` methods. The officially supported arguments include: - **The exception** — the raised exception, or any **supertype** of it (e.g. declare `Exception ex` to receive any subtype). This is the primary argument. - **`HandlerMethod`** — the controller method that threw, useful for logging which endpoint failed. - **`WebRequest` / `NativeWebRequest`** — Servlet-agnostic access to parameters and request/session attributes. - **Servlet types** — `ServletRequest`/`HttpServletRequest`, `ServletResponse`/`HttpServletResponse`, `HttpSession` (its presence is enforced if you declare it). - **`java.security.Principal`** — the authenticated user. - **`HttpMethod`**, **`java.util.Locale`**, **`TimeZone`/`ZoneId`**. - **`java.io.OutputStream` / `java.io.Writer`** — raw response body access. - **`Model` / `ModelMap` / `Map`** — the model for an error view. **Important gotcha: it is always empty** at this point. - **`RedirectAttributes`**, and **`@SessionAttribute` / `@RequestAttribute`** annotated parameters. What you **cannot** use: `@RequestBody`, command/model-attribute objects, and general request-body binding — the request body may already be consumed and the point of the handler is error rendering, not input binding. ## Supported return values These mirror ordinary controller return values: - **`ResponseEntity<T>`** — most common in REST; sets status, headers, and body explicitly. - **An `@ResponseBody` object** — the return value is serialized (e.g. to JSON). In a `@RestController`, `@ResponseBody` is implicit. Pair with **`@ResponseStatus`** on the handler method to control the HTTP status (otherwise 200 is used). - **`String`** — treated as a view name for an error page. - **`ModelAndView`** — explicit view + model. - **`void`** — you wrote to the response (`HttpServletResponse`/`Writer`) yourself, so nothing needs rendering. ## Example combining several ```java @ExceptionHandler(ValidationException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody ApiError handle(ValidationException ex, HandlerMethod method, Locale locale) { log.warn("Validation failed in {}", method.getMethod().getName()); return new ApiError("VALIDATION", messages.get(ex.getCode(), locale)); } ``` ## Gotchas - Declaring `Model` and expecting request data in it — it is **always empty** in an exception handler. - Forgetting `@ResponseStatus` (or not using `ResponseEntity`) when returning a plain body → you'll get **HTTP 200** on an error. - The exception parameter's type doubles as the **matching declaration** when `@ExceptionHandler`'s value is empty.

  • If you return a plain object from an @ExceptionHandler without @ResponseStatus, what status does the client get?
    HTTP 200 OK — because the object is just rendered as the body. To signal an error status you must add @ResponseStatus or return a ResponseEntity with the desired status.
  • Can you inject the Model to read the failed request's attributes?
    You can declare Model/ModelMap/Map, but for an exception handler it is always empty. Use WebRequest or the Servlet request to read attributes/parameters instead.

saying these in an interview costs you the question

  • Claiming you can bind @RequestBody or a command object in an @ExceptionHandler
  • Expecting the Model argument to contain data
  • Assuming a returned body automatically produces a 4xx/5xx status without @ResponseStatus
  • Thinking only the exact exception type (not a supertype) can be a parameter

context