You know, Spring framework provides several ways which developers can use to handle exceptions in their applications. One of them is controller-based exception handing or exception handler per controller.

And in this guide, you will learn how to code controller-based exception handlers for your Spring applications.

 

1. Why Controller-based exception handling?

In this kind of exception handling, you write exception handling code in a separate handler method in a controller class. Then only matching exceptions thrown in that controller is handled by the exception handler method. The same exceptions thrown in other controllers are not handled.

The following code illustrates this approach:

The following code illustrates this approach:
public class ControllerA {

	// normal handler methods...
	
	@ExceptionHandler(Exception1.class)
	public String handleException1() {
	
		// handle Exception1 in ControllerA
	}
}


public class ControllerB {

	// normal handler methods...
	
	@ExceptionHandler(Exception1.class)
	public String handleException1() {
	
		// handle Exception1 in ControllerB
	}
}
You see, both ControllerA and ControllerB handles Exception1 in their separate handler method annotated with @ExceptionHandler annotation. So consider using controller-based exception handler if:

- the logics of handling an exception is very specific to a controller. It cannot be applied for the same exceptions thrown by other controllers.

- there’s only one controller in your application.


2. Exception Handler Examples in Spring Web Controller

Consider the following Spring web controller class that works with view template (JSP or Thymeleaf):

package net.codejava;

@Controller
public class AppController {
	
	@RequestMapping("/edit/{id}")
	public ModelAndView editProduct(Long id) {

		// code that may throw ProductNotFoundException

	}	
	
	@RequestMapping("/delete/{id}")
	public String deleteProduct(Long id) {
		
		// code that may throw ProductNotFoundException
		
	}
}


You see, in this controller, two handler methods have code that may throw ProductNotFoundException so we want to handle that exception right in this class, such as directing clients to a separate error view. For example, put an exception handler method as follows:

package net.codejava;

@Controller
public class AppController {
	
	// normal handler methods...
	
	@ExceptionHandler(ProductNotFoundException.class)
	public ModelAndView handleProductNotFoundError(Exception ex) {
	
		ModelAndView mav = new ModelAndView("productNotFound");
		mav.addObject("message", ex.getLocalizedMessage());
		
		return mav;
	}	
}
Here, you need to use @ExceptionHandler annotation for the exception handler method, and specify the type of exception this method will handle. It returns a view similar to a regular web controller, which is the productNotFound view name in this example. And you can access the exception object by declaring a parameter in the method signature.

You can also return a String of view name instead of a ModelAndView object, like this:

@ExceptionHandler(ProductNotFoundException.class)
public String handleProductNotFoundError(Exception ex) {

	// code that handles exception
	
	return "ProductNotFound";
}
If you want to access the request and response object, you can declare additional parameters in the method signature. Below is another example:

@ExceptionHandler(ProductNotFoundException.class)
public String handleProductNotFoundError(
		HttpServletRequest request, HttpServletResponse response, Exception ex) {

	// code that handles exception
	// code that uses request
	// code that uses response
	
	return "ProductNotFound";
}
In case you want to handle more than one exception, you can specify an array of exception classes like this:

@ExceptionHandler({Exception1.class, Exception2.class, Exception3.class})
  

3. Exception Handler Examples in Spring REST Controller

Handle exception in a Spring REST controller is slightly different. In addition to @ExceptionHandler annotation, you may need to use @ResponseStatus and @ResponseBody annotations, to specify HTTP status code and what to be sent in the response, respectively.

Consider the following Spring REST controller class:

@RestController
public class EmployeeController {


	@GetMapping("/employees/{id}")
	EntityModel<Employee> one(@PathVariable Long id) {
		
		// code that may throw EmployeeNotFoundException
		
	}

	@PutMapping("/employees/{id}")
	ResponseEntity<?> replaceEmployee(@RequestBody Employee newEmployee, Long id) {
		
		// code that may throw EmployeeNotFoundException
		
	}

	@DeleteMapping("/employees/{id}")
	ResponseEntity<?> deleteEmployee(@PathVariable Long id) {
		
		// code that may throw EmployeeNotFoundException
		
	}
}
You see, all three handler methods may throw EmployeeNotFoundException, so we want to handle this exception right inside this class. For example, put the following method into the controller class:

@ResponseBody
@ExceptionHandler(EmployeeNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String employeeNotFoundHandler(
		HttpServletRequest request, HttpServletResponse response, Exception ex) {
	
	// code that handles exception	
	
	return ex.getMessage();
}
Let me explain this code. If, somehow, an EmployeeNotFoundException is thrown by this controller, the employeeNotFoundHandler() method will get invoked. You can access the request, response and exception objects as arguments of the method. This exception handler returns HTTP status 404 (Not Found) with the exception message is the content of the response.

You can return a JSON document in the exception handler, as shown below:

@ExceptionHandler(OrderNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
ErrorInfo orderNotFoundHandler(HttpServletRequest request, Exception ex) {
	
	// code that handles exception...
	
	return new ErrorInfo(request.getRequestURL().toString(), ex);
}
Here, Spring will serialize the ErrorInfo object to a corresponding JSON string as the response. Code of the ErrorInfo class is as follows:

public class ErrorInfo {
	private final String url;
	private final String ex;
	
	public ErrorInfo(String url, Exception ex) {
		this.url = url;
		this.ex = ex.getLocalizedMessage();
	}

	// getters and setters are not shown, for brevity
	
}
The client will get the JSON response like this:

{
  "url": "http://localhost:8080/orders/823",
  "ex": "Could not find order ID 823"
}
So far I have shared some code examples about handling exception in Spring applications with controller-based exception handler, for both Spring Web and Spring REST controllers. To see the coding in action, I recommend you watch the following video:

 

Related Tutorials:

 

Other Spring Boot Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Add comment