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.