Spring MVC @ExceptionHandler Annotation with Example





Hey guys in this post, we will discuss @ExceptionHandler annotation with an example

Overview


@ExceptionHandler works at the Controller level and it is only active for that particular Controller, not globally for the entire application, which means, only exceptions from this controller is routed to his @ExceptionHandler.

@RestController
public class EmployeeController {
	
        ...
	
	@ExceptionHandler
	public ResponseEntity<ErrorObject> handleException(EmployeeNotFoundException ex) {
		ErrorObject eObject = new ErrorObject();
		eObject.setStatus(HttpStatus.NOT_FOUND.value());
		eObject.setMessage(ex.getMessage());
		eObject.setTimestamp(System.currentTimeMillis());
		return new ResponseEntity<ErrorObject>(eObject, HttpStatus.NOT_FOUND);
	}
}

or

@RestController
public class EmployeeController {
	
        ...
	
	@ExceptionHandler(EmployeeNotFoundException.class)
	public ResponseEntity<ErrorObject> handleException() {
		ErrorObject eObject = new ErrorObject();
		eObject.setStatus(HttpStatus.NOT_FOUND.value());
		eObject.setMessage("Employee not found");
		eObject.setTimestamp(System.currentTimeMillis());
		return new ResponseEntity<ErrorObject>(eObject, HttpStatus.NOT_FOUND);
	}
}

Watch the video


Example on @ExceptionHandler


In order to understand, @ExceptionHandler annotation completely let’s create a Spring boot project

Create spring boot project


There are many different ways to create a spring boot project, you can follow the below articles to create one –

>> Create spring boot application using Spring initializer
>> Create spring boot application in Spring tool suite [STS]
>> Create spring boot application in IntelliJ IDEA

Add maven dependencies


Open pom.xml and add the following dependencies –

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>in.bushansirgur</groupId>
	<artifactId>exceptionhandler</artifactId>
	<version>v1</version>
	<name>exceptionhandler</name>
	<description>Spring boot exception handler annotaton</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

spring-boot-starter-web dependency for building web applications using Spring MVC. It uses the tomcat as the default embedded container.




spring-boot-devtools dependency for automatic reloads or live reload of applications.

Create an entity class


Create Employee.java inside the in.bushansirgur.springboot.entity package and add the following content

package in.bushansirgur.springboot.entity;

public class Employee {
	
	private Integer id;
	
	private String name;
	
	private Integer age;
	
	private String location;
	
	public Employee() {
	}
	
	public Employee(Integer id, String name, Integer age, String location) {
		this.id = id;
		this.name = name;
		this.age = age;
		this.location = location;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getLocation() {
		return location;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", location=" + location + "]";
	}
}

This is just a plain old java class that has setters, getters, constructors, and toString().

Create custom error response


Create ErrorObject.java inside in.bushansirgur.springboot.exceptions package and add the following content

package in.bushansirgur.springboot.exceptions;

public class ErrorObject {
	
	private int status;
	
	private String message;
	
	private long timestamp;

	public int getStatus() {
		return status;
	}

	public void setStatus(int status) {
		this.status = status;
	}

	public String getMessage() {
		return message;
	}

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

	public long getTimestamp() {
		return timestamp;
	}

	public void setTimestamp(long timestamp) {
		this.timestamp = timestamp;
	}
	
	public ErrorObject() {
	}

	public ErrorObject(int status, String message, long timestamp) {
		this.status = status;
		this.message = message;
		this.timestamp = timestamp;
	}
	
	
}

This is just a plain old java class that contains fields that we want to show in the error response.

Create a custom exception


So far we are dealing with an Employee, let’s create a custom exception EmployeeNotFoundException.

Create EmployeeNotFoundException.java inside the in.bushansirgur.springboot.exceptions package and add the following content

package in.bushansirgur.springboot.exceptions;

public class EmployeeNotFoundException extends RuntimeException {

	public EmployeeNotFoundException(String message) {
		super(message);
	}
	
}

Create a service class


Create EmployeeService.java inside in.bushansirgur.springboot.service package and add the following content

package in.bushansirgur.springboot.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Service;

import in.bushansirgur.springboot.entity.Employee;
import in.bushansirgur.springboot.exceptions.EmployeeNotFoundException;

@Service
public class EmployeeService {
	
	private static List<Employee> list = new ArrayList<>();
	
	static {
		Employee e = new Employee(1, "Employee 1", 28, "India");
		list.add(e);
		
		e = new Employee(2, "Employee 2", 25, "India");
		list.add(e);
		
		e = new Employee(3, "Employee 3", 30, "India");
		list.add(e);
		
		e = new Employee(4, "Employee 4", 48, "India");
		list.add(e);
		
		e = new Employee(5, "Employee 5", 27, "India");
		list.add(e);
	}
	
	public Employee getEmployee (Integer id) {
		Optional<Employee> theEmployee = list.stream().filter(e -> e.getId() == id).findFirst();
		if (theEmployee.isPresent()) {
			return theEmployee.get();
		}
		throw new EmployeeNotFoundException("Employee not found for the id ->"+id);
	}
}

For the sake of this tutorial, we are loading some static data inside the static block. And, we have created a method to get the Employee based on the Id.




If the Employee Id is not found then we are throwing the custom exception EmployeeNotFoundException.

Create a controller


Create EmployeeController.java inside in.bushansirgur.springboot.controller and add the following content

package in.bushansirgur.springboot.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import in.bushansirgur.springboot.entity.Employee;
import in.bushansirgur.springboot.exceptions.EmployeeNotFoundException;
import in.bushansirgur.springboot.exceptions.ErrorObject;
import in.bushansirgur.springboot.service.EmployeeService;

@RestController
public class EmployeeController {
	
	@Autowired
	EmployeeService eService;
	
	@GetMapping("/employees/{id}")
	public Employee getEmployee (@PathVariable Integer id) {
		return eService.getEmployee(id);
	}
	
	@ExceptionHandler
	public ResponseEntity<ErrorObject> handleException(EmployeeNotFoundException ex) {
		ErrorObject eObject = new ErrorObject();
		eObject.setStatus(HttpStatus.NOT_FOUND.value());
		eObject.setMessage(ex.getMessage());
		eObject.setTimestamp(System.currentTimeMillis());
		return new ResponseEntity<ErrorObject>(eObject, HttpStatus.NOT_FOUND);
	}
}

So inside the controller, we are creating a handler method to handle the custom exception. We will add @ExceptionHandler annotation to the handler method and inside the method, we will frame error response using ErrorObject and add it to the ResponseEntity.

run the app


Now, its time to test our application

mvn spring-boot:run

Open the browser and enter the following URL

  • http://localhost:8080/employees/2
{
    "id": 2,
    "name": "Employee 2",
    "age": 25,
    "location": "India"
}
  • http://localhost:8080/employees/88
{
    "status": 404,
    "message": "Employee not found for the id ->88",
    "timestamp": 1614794021192
}




About the author

Bushan Sirgur

Hey guys, I am Bushan Sirgur from Banglore, India. Currently, I am working as an Associate project in an IT company.

View all posts

Leave a Reply

Your email address will not be published. Required fields are marked *