Spring @ExceptionHandler – Multiple exceptions and global handler

Exception handling is very essential feature of any Java application. Every good open source framework allows to write the exception handlers in such a way that we can separate then from our application code. Well, Spring framework also allows us to do so using annotation Spring @ExceptionHandler

@ExceptionHandler annotation is used for handling exceptions in specific handler classes and/or handler methods.

Table of Contents

1. Spring @ExceptionHandler annotation
2. Spring @ExceptionHandler example
3. Spring @ExceptionHandler - Handle multiple exceptions
4. Spring @ExceptionHandler Global exception handling with @ControllerAdvice

1. Spring @ExceptionHandler annotation

To handle exceptions in String MVC, we can define a method in controller class and use the annotation @ExceptionHandler on it. Spring configuration will detect this annotation and register the method as exception handler for argument exception class and its subclasses.

1.1. Exception handler method arguments

Handler methods which are annotated with this annotation are allowed to have very flexible signatures. They can accept arguments of different types. For example, an exception argument, request and/or response objects, session object, locale object and model object etc.

1.2. Exception handler method return types

Similar to arguments, return types can be of different types. For example, ModelAndView object, Model object, View Object, view name as String etc. We can mark the method to void also if the method handles the response itself by writing the response content directly to HttpServletResponse.

We may combine the ExceptionHandler annotation with @ResponseStatus for a specific HTTP error status.

1.3. Exception handler method example

@ExceptionHandler(NullPointerException.class)
public ModelAndView handleException(NullPointerException ex)
{
	//Do something additional if required
	ModelAndView modelAndView = new ModelAndView();
	modelAndView.setViewName("error");
	modelAndView.addObject("message", ex.getMessage());
	return modelAndView;
}

Now every time, controller encounter NullPointerException in request processing for any web request in this controller, control will automatically come to this handler method.

2. Spring @ExceptionHandler example

For example, below handler method is intentionally returning NullPointerException.

@RequestMapping(value="/demo/not-exist", method = RequestMethod.GET,  headers="Accept=*/*")
public @ResponseBody ModelAndView oneFaultyMethod()
{
	if(true)
	{
		throw new NullPointerException("This error message if for demo only.");
	}
	return null;
}

If we deploy above application and hit the URL [/SpringApplication/users/demo/not-exist] in browser, it will show the “error” page as configured in first section.

< %@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
< %@ taglib prefix="x" uri="http://java.sun.com/jstl/xml" %>
< %@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>
< %@ taglib prefix="sql" uri="http://java.sun.com/jstl/sql" %>
<html>

	<head>
		<title>This is sample error page</title>
	</head>
	<body>
		<h1>This is sample error page : <c:out value="${message}"></c:out></h1>
	</body>
<html>

Below will be the output in browser.

message-on-browser-3924864

3. Spring @ExceptionHandler – Handle multiple exceptions

As mentioned earlier, above exception handler will handle all exceptions which are either instance of given class or sub-classes of argument exception. But, if we want to configure @ExceptionHandler for multiple exceptions of different types, then we can specify all such exceptions in form of array.

@ExceptionHandler({NullPointerException.class, ArrayIndexOutOfBoundsException.class, IOException.class})
public ModelAndView handleException(NullPointerException ex)
{
	//Do something additional if required
	ModelAndView modelAndView = new ModelAndView();
	modelAndView.setViewName("error");
	modelAndView.addObject("message", ex.getMessage());
	return modelAndView;
}

4. Spring @ExceptionHandler Global exception handling with @ControllerAdvice

If we want to centralize the exception handling logic to one class which is capable to handle exceptions thrown from any handler class/ controller class – then we can use @ControllerAdvice annotation.

By default the methods in an @ControllerAdvice apply globally to all Controllers. We can create a class and add @ControllerAdvice annotation on top. Then add @ExceptionHandler methods for each type of specific exception classes in it.

Notice we extended the exception handler class with ResponseEntityExceptionHandler. It is convenient base class for @ControllerAdvice classes that wish to provide centralized exception handling across all @RequestMapping methods through @ExceptionHandler methods.

@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler 
{
	@ExceptionHandler(Exception.class)
	public final ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex, WebRequest request) {
		List<String> details = new ArrayList<>();
		details.add(ex.getLocalizedMessage());
		ErrorResponse error = new ErrorResponse(ApplicationConstants.SERVER_ERROR, details);
		return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
	}

	@ExceptionHandler(RecordNotFoundException.class)
	public final ResponseEntity<ErrorResponse> handleUserNotFoundException(RecordNotFoundException ex,
												WebRequest request) {
		List<String> details = new ArrayList<>();
		details.add(ex.getLocalizedMessage());
		ErrorResponse error = new ErrorResponse(ApplicationConstants.RECORD_NOT_FOUND, details);
		return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
	}
}

Where supporting classes are. This is for example only. Please create your application specific exception and handle them.

@ResponseStatus(HttpStatus.NOT_FOUND)
public class RecordNotFoundException extends RuntimeException
{
	private static final long serialVersionUID = 1L;

	public RecordNotFoundException(String exception) {
        super(exception);
    }
}
@XmlRootElement(name = "error")
public class ErrorResponse
{
    public ErrorResponse(String message, List<String> details) {
        super();
        this.message = message;
        this.details = details;
    }
 
    private String message;
    private List<String> details;

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public List<String> getDetails() {
		return details;
	}

	public void setDetails(List<String> details) {
		this.details = details;
	}
}

Happy Learning !!

References:

ExceptionHandler Java Doc
ResponseEntityExceptionHandler Java Doc

Was this post helpful?

Join 7000+ Awesome Developers

Get the latest updates from industry, awesome resources, blog updates and much more.

* We do not spam !!

3 thoughts on “Spring @ExceptionHandler – Multiple exceptions and global handler”

  1. Hi Lokesh, I have a little confussion in this exception handling… i have a controller which have 5-8 @RequestMapping annotations(ModelAndView methods). if i use 1 @ExceptionHandler(Exception.class) for this controller, does it handles any exception which comes in this controller?

    Reply
  2. Hi Lokesh,

    I appreciate your work on Spring 3 . Good work keep it up.
    past 7 years I have been practicing java -j2ee working with reputed organization
    I have few questions on Spring Annotation , would like to discuss with you ,please provide me your valuable reply on those .

    1)@Configuration is introduced in Spring3 , which is the primary class reading that annotation and doing all necessary steps like instantiation , wiring and disposing bean .
    2)pls observe below code snippet which does creation of bean and disposing bean

    /*
    * To change this license header, choose License Headers in Project Properties.
    * To change this template file, choose Tools | Templates
    * and open the template in the editor.
    */

    package annotationparser;

    import java.lang.annotation.Annotation;
    import java.lang.reflect.Method;

    /**
    *
    * @author chinni
    */
    public class AnnotationParser {

    /**
    * @param args the command line arguments
    */
    public static void main(String[] args) throws ClassNotFoundException {
    // TODO code application logic here

    Class aimpl= (Class) Configuration.class.getClassLoader().loadClass(Configuration.class.getName());
    Annotation a[]= aimpl.getDeclaredAnnotations();
    for(Annotation m :a){
    System.out.println(m.getDeclaredAnnotations()[0]);
    }
    }
    }

    using bove code we can get list of all configuration classes and we can instantiate object and return back

    3)is it possible to invoke super class constructor using java.lang.reflect , if yes please send me the code
    snippet

    4) same question on this keyword
    5) can we write annotations to inject Author and date time stamp on the fly ?

    I am working on big project with Annotations , hence I have got all these questions . pls reply me back

    Thanks
    Sitaram Venkata
    Hyderabad

    Reply

Leave a Comment

HowToDoInJava

A blog about Java and related technologies, the best practices, algorithms, and interview questions.