Exceptions
@Controller
and @ControllerAdvice classes can have
@ExceptionHandler
methods to handle exceptions from controller methods. The following
example includes such a handler method:
-
Java
-
Kotlin
import java.io.IOException;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
@Controller
public class SimpleController {
@ExceptionHandler(IOException.class)
public ResponseEntity<String> handle() {
return ResponseEntity.internalServerError().body("Could not read file storage");
}
}
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.ExceptionHandler
import java.io.IOException
@Controller
class SimpleController {
@ExceptionHandler(IOException::class)
fun handle() : ResponseEntity<String> {
return ResponseEntity.internalServerError().body("Could not read file storage")
}
}
The exception can match against a top-level exception being propagated (that is, a direct
IOException
being thrown) or against the immediate cause within a top-level wrapper
exception (for example, an IOException
wrapped inside an IllegalStateException
).
For matching exception types, preferably declare the target exception as a method argument,
as shown in the preceding example. Alternatively, the annotation declaration can narrow the
exception types to match. We generally recommend being as specific as possible in the
argument signature and to declare your primary root exception mappings on a
@ControllerAdvice
prioritized with a corresponding order.
See the MVC section for details.
An @ExceptionHandler method in WebFlux supports the same method arguments and
return values as a @RequestMapping method, with the exception of request body-
and @ModelAttribute -related method arguments.
|
Support for @ExceptionHandler
methods in Spring WebFlux is provided by the
HandlerAdapter
for @RequestMapping
methods. See DispatcherHandler
for more detail.
Media Type Mapping
In addition to exception types, @ExceptionHandler
methods can also declare producible media types.
This allows to refine error responses depending on the media types requested by HTTP clients, typically in the "Accept" HTTP request header.
Applications can declare producible media types directly on annotations, for the same exception type:
-
Java
-
Kotlin
@ExceptionHandler(produces = "application/json")
public ResponseEntity<ErrorMessage> handleJson(IllegalArgumentException exc) {
return ResponseEntity.badRequest().body(new ErrorMessage(exc.getMessage(), 42));
}
@ExceptionHandler(produces = "text/html")
public String handle(IllegalArgumentException exc, Model model) {
model.addAttribute("error", new ErrorMessage(exc.getMessage(), 42));
return "errorView";
}
@ExceptionHandler(produces = ["application/json"])
fun handleJson(exc: IllegalArgumentException): ResponseEntity<ErrorMessage> {
return ResponseEntity.badRequest().body(ErrorMessage(exc.message, 42))
}
@ExceptionHandler(produces = ["text/html"])
fun handle(exc: IllegalArgumentException, model: Model): String {
model.addAttribute("error", ErrorMessage(exc.message, 42))
return "errorView"
}
Here, methods handle the same exception type but will not be rejected as duplicates.
Instead, API clients requesting "application/json" will receive a JSON error, and browsers will get an HTML error view.
Each @ExceptionHandler
annotation can declare several producible media types,
the content negotiation during the error handling phase will decide which content type will be used.
Method Arguments
@ExceptionHandler
methods support the same method arguments
as @RequestMapping
methods, except the request body might have been consumed already.
Return Values
@ExceptionHandler
methods support the same return values
as @RequestMapping
methods.