• Java
    • JAXB Tutorial
      • What is JAXB
      • JAXB Marshalling Example
      • JAXB UnMarshalling Example
  • Spring Tutorial
    • Spring Core Tutorial
    • Spring MVC Tutorial
      • Quick Start
        • Flow Diagram
        • Hello World Example
        • Form Handling Example
      • Handler Mapping
        • BeanNameUrlHandlerMapping
        • ControllerClassNameHandlerMapping
        • SimpleUrlHandlerMapping
      • Validation & Exception Handling
        • Validation+Annotations
        • Validation+ResourceBundle
        • @ExceptionHandler
        • @ControllerAdvice
        • Custom Exception Handling
      • Form Tag Library
        • Textbox Example
        • TextArea Example
        • Password Example
        • Dropdown Box Example
        • Checkboxes Example
        • Radiobuttons Example
        • HiddenValue Example
      • Misc
        • Change Config file name
    • Spring Boot Tutorial
  • Hibernate Tutorial
  • REST Tutorial
    • JAX-RS REST @PathParam Example
    • JAX-RS REST @QueryParam Example
    • JAX-RS REST @DefaultValue Example
    • JAX-RS REST @Context Example
    • JAX-RS REST @MatrixParam Example
    • JAX-RS REST @FormParam Example
    • JAX-RS REST @Produces Example
    • JAX-RS REST @Consumes Example
    • JAX-RS REST @Produces both XML and JSON Example
    • JAX-RS REST @Consumes both XML and JSON Example
  • Miscellaneous
    • JSON Parser
      • Read a JSON file
      • Write JSON object to File
      • Read / Write JSON using GSON
      • Java Object to JSON using JAXB
    • CSV Parser
      • Read / Write CSV file
      • Read/Parse/Write CSV File – OpenCSV
      • Export data into a CSV File
      • CsvToBean and BeanToCsv – OpenCSV

JavaInterviewPoint

Java Development Tutorials

Spring Boot Exception Handling – @RestControllerAdvice + @ExceptionHandler

February 13, 2019 by javainterviewpoint 2 Comments

A good REST API should handle the exception properly and send the proper response to the user. The user should not be rendered with any unhandled exception. In this Spring Boot Exception Handling article, we will learn how to handle in exception in Spring Boot RESTful Web Services using @RestControllerAdvice and @ExceptionHandler

What is @RestControllerAdvice ?

@RestControllerAdvice is the combination of both @ControllerAdvice and @ResponseBody. We can use the @ControllerAdvice annotation for handling exceptions in the RESTful Services but we need to add @ResponseBody separately.

Folder Structure:

Spring Boot Exception Handling 2

  1. Create a Maven project (maven-archetype-quickstart) “SpringBootApplication” and create a package for our source files “com.javainterviewpoint” under  src/main/java 
  2. Now add the following dependency in the POM.xml
    <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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    
    	<groupId>com.javainterviewpoint</groupId>
    	<artifactId>SpringBootApplication</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    
    	<name>SpringBootApplication</name>
    	<url>http://maven.apache.org</url>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    	</properties>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.0.2.RELEASE</version>
    	</parent>
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    	</dependencies>
    </project>
  3. Create the Java classes Employee.java, EmployeeService.java, ErrorResponse.java, EmployeeController.java, RestExceptionHandler.java and Application.java under com.javainterviewpoint folder.

The spring-boot-starter-parent is a special starter, it provides useful Maven defaults. Since we are developing a web application, we also need to add spring-boot-starter-web dependency.This will add dependencies such Tomcat, Jackson, Spring boot etc which are required for our application.

Other interesting articles which you may like …

  • Spring Boot Security Basic Authentication
  • Spring Boot @ConfigurationProperties Example
  • Spring Boot auto-configuration @SpringBootApplication
  • Spring Boot Thymeleaf Example
  • Spring Boot JPA Tutorial
  • Spring Boot Tomcat JDBC Connection Pool
  • Spring Boot Logging – Logback
  • Spring Boot Log4j2 Example
  • Spring Boot HikariCP Connection Pool
  • Spring Boot JDBC Connection Pool
  • Spring Boot RESTful Web Services Example
  • Spring Boot Kotlin RESTful Web Services
  • Spring Boot with Kotlin Hello World Example
  • Spring Boot Hello World Example with Maven
  • Spring Boot Hello World Example in Eclipse
  • How to Create Deployable WAR | Spring Boot | SpringBootServletInitializer
  • Spring Boot Change Embedded Tomcat default port
  • Spring Boot CRUDRepository Example- Spring Data JPA
  • Fix missing src/main/java folder in Eclipse Maven Project
  • Spring MVC CRUD Example with MySql + JdbcTemplate
  • RESTful Java Client With Jersey Client
  • RESTEasy Hello World Example with Apache Tomcat
  • RESTful Java client with RESTEasy client
  • Spring RESTful Web Services Hello World XML Example
  • Springfox Swagger 2 for Spring RESTful Web Services

Spring Boot Exception Handling – @RestControllerAdvice + @ExceptionHandler

Dependency Tree

[INFO] ------------------------------------------------------------------------
[INFO] Building SpringBootApplication 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:3.0.2:tree (default-cli) @ SpringBootApplication ---
[INFO] com.javainterviewpoint:SpringBootApplication:jar:0.0.1-SNAPSHOT
[INFO] \- org.springframework.boot:spring-boot-starter-web:jar:2.0.2.RELEASE:compile
[INFO]    +- org.springframework.boot:spring-boot-starter:jar:2.0.2.RELEASE:compile
[INFO]    |  +- org.springframework.boot:spring-boot:jar:2.0.2.RELEASE:compile
[INFO]    |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.0.2.RELEASE:compile
[INFO]    |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.0.2.RELEASE:compile
[INFO]    |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO]    |  |  |  +- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO]    |  |  |  \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO]    |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.10.0:compile
[INFO]    |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.10.0:compile
[INFO]    |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO]    |  +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO]    |  +- org.springframework:spring-core:jar:5.0.6.RELEASE:compile
[INFO]    |  |  \- org.springframework:spring-jcl:jar:5.0.6.RELEASE:compile
[INFO]    |  \- org.yaml:snakeyaml:jar:1.19:runtime
[INFO]    +- org.springframework.boot:spring-boot-starter-json:jar:2.0.2.RELEASE:compile
[INFO]    |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.5:compile
[INFO]    |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO]    |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.9.5:compile
[INFO]    |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.5:compile
[INFO]    |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.5:compile
[INFO]    |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.5:compile
[INFO]    +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.0.2.RELEASE:compile
[INFO]    |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.31:compile
[INFO]    |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.31:compile
[INFO]    |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.31:compile
[INFO]    +- org.hibernate.validator:hibernate-validator:jar:6.0.9.Final:compile
[INFO]    |  +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO]    |  +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
[INFO]    |  \- com.fasterxml:classmate:jar:1.3.4:compile
[INFO]    +- org.springframework:spring-web:jar:5.0.6.RELEASE:compile
[INFO]    |  \- org.springframework:spring-beans:jar:5.0.6.RELEASE:compile
[INFO]    \- org.springframework:spring-webmvc:jar:5.0.6.RELEASE:compile
[INFO]       +- org.springframework:spring-aop:jar:5.0.6.RELEASE:compile
[INFO]       +- org.springframework:spring-context:jar:5.0.6.RELEASE:compile
[INFO]       \- org.springframework:spring-expression:jar:5.0.6.RELEASE:compile
[INFO] ------------------------------------------------------------------------

Global Exception Handler

package com.javainterviewpoint;

import java.io.IOException;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class RestExceptionHandler
{
    @ExceptionHandler(value = { IOException.class })
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse badRequest(Exception ex)
    {
        return new ErrorResponse(400, "Bad Request");
    }
    
    @ExceptionHandler(value = { Exception.class })
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ErrorResponse unKnownException(Exception ex)
    {
        return new ErrorResponse(404, "Employee Not Found");
    }
}

Here you can see that the RestExceptionHandler class is annotated with @RestControllerAdvice, which tells the Spring to treat this class as the global exception handler. The @ExceptionHandler handles each of the exception separately and returns the corresponding error message.

Custom Error Message

Global exception handler RestExceptionHandler will return the custom ErrorResponse with the error message and status code.

package com.javainterviewpoint;

public class ErrorResponse
{
    private int status;
    private String message;
    
    public ErrorResponse()
    {
        super();
    }
    public ErrorResponse(int status, String message)
    {
        super();
        this.status = status;
        this.message = message;
    }
    
    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;
    }
    @Override
    public String toString()
    {
        return "ErrorResponse [status=" + status + ", message=" + message + "]";
    }
}

EmployeeController.java

package com.javainterviewpoint;

import java.io.IOException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EmployeeController
{
    @Autowired
    EmployeeService employeeService;
    
    @Autowired
    Employee employee;
    
    @RequestMapping("/employee/{employeeName}")
    public Employee hello(@PathVariable("employeeName") String employeeName) throws Exception
    {
        if (employeeName.length() < 4)
            throw new IOException();
        
        employee = employeeService.getEmployee(employeeName);
        if(employee == null)
            throw new Exception();
        
        return employee;
    }
}

Our EmployeeController class will throw two exceptions

  1. When the employeeName is lesser than 4 characters it will throw IOException
  2. When the employee object is null then it will throw Exception

Both the exceptions will be handled globally by our RestExceptionHandler class.

EmployeeService.java

package com.javainterviewpoint;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.springframework.stereotype.Service;

@Service
public class EmployeeService
{
    Map<String, Employee> employeeMap = new HashMap<String, Employee>(); 
    
    @PostConstruct
    void initialize() {
        Employee emp1 = new Employee("John", 11);
        Employee emp2 = new Employee("James", 22);
        employeeMap.put("John", emp1);
        employeeMap.put("James", emp2);
    }
    
    public Employee getEmployee (String name) throws Exception
    {
        return employeeMap.get(name);
    }
}

Employee.java

Employee class is a simple POJO consisting the getters and setters for name and age.

package com.javainterviewpoint;

import org.springframework.stereotype.Component;

@Component
public class Employee
{
    private String name;
    private int age;

    
    public Employee()
    {
        super();
    }

    public Employee(String name, int age)
    {
        this.setName(name);
        this.setAge(age);
    }

    public String getName()
    {
        return name;
    }

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

    public int getAge()
    {
        return age;
    }

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

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

Application.java

package com.javainterviewpoint;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application
{
    public static void main(String[] args)
    {
        SpringApplication.run(Application.class, args);
    }
}

The Application class main() method is the triggering point of our application. Inside the main method we will be calling the SpringApplication class run() method which bootstraps our Application and starts the tomcat server. We will be passing our class name [Applicaion.class] as an argument to the run() method.

Output

Pass the employee name less than 4 characters

In POSTMAN,  select GET method and give the url as “http://localhost:8080/employee/asd”. You will be getting 400 – Bad Request

Spring Boot Exception Handling

Pass the employee name which is not in the map

In POSTMAN,  select GET method and give the url as “http://localhost:8080/employee/javainterviewpoint”. You will be getting 500 – Internal Server Error

Spring Boot Exception Handling 1
Pass the correct Employee name and you should the Employee details

In POSTMAN,  select GET method and give the url as “http://localhost:8080/employee/John”. 

Spring Boot Exception Handling 3

Filed Under: Java, Spring, Spring Boot Tagged With: @ExceptionHandler, @RestControllerAdvice, Exception Handling, Spring Boot, Spring Boot Exception Handling

Comments

  1. sukh says

    May 22, 2019 at 6:47 am

    Nice article. Could you please let me know if we have MVC architecture where we should throw exceptions exactly (DAO or services or just like controller you mentioned)? Thanks

    Reply
    • javainterviewpoint says

      May 22, 2019 at 9:53 pm

      It is always a good practice throwing an exception from the DAO layer. Just for simplicity of the code, I have not followed that architecture.

      Reply

Leave a Reply Cancel reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Java Basics

  • JVM Architecture
  • Object in Java
  • Class in Java
  • How to Set Classpath for Java in Windows
  • Components of JDK
  • Decompiling a class file
  • Use of Class.forName in java
  • Use Class.forName in SQL JDBC

Oops Concepts

  • Inheritance in Java
  • Types of Inheritance in Java
  • Single Inheritance in Java
  • Multiple Inheritance in Java
  • Multilevel Inheritance in Java
  • Hierarchical Inheritance in Java
  • Hybrid Inheritance in Java
  • Polymorphism in Java – Method Overloading and Overriding
  • Types of Polymorphism in java
  • Method Overriding in Java
  • Can we Overload static methods in Java
  • Can we Override static methods in Java
  • Java Constructor Overloading
  • Java Method Overloading Example
  • Encapsulation in Java with Example
  • Constructor in Java
  • Constructor in an Interface?
  • Parameterized Constructor in Java
  • Constructor Chaining with example
  • What is the use of a Private Constructors in Java
  • Interface in Java
  • What is Marker Interface
  • Abstract Class in Java

Java Keywords

  • Java this keyword
  • Java super keyword
  • Final Keyword in Java
  • static Keyword in Java
  • Static Import
  • Transient Keyword

Miscellaneous

  • newInstance() method
  • How does Hashmap works internally in Java
  • Java Ternary operator
  • How System.out.println() really work?
  • Autoboxing and Unboxing Examples
  • Serialization and Deserialization in Java with Example
  • Generate SerialVersionUID in Java
  • How to make a class Immutable in Java
  • Differences betwen HashMap and Hashtable
  • Difference between Enumeration and Iterator ?
  • Difference between fail-fast and fail-safe Iterator
  • Difference Between Interface and Abstract Class in Java
  • Difference between equals() and ==
  • Sort Objects in a ArrayList using Java Comparable Interface
  • Sort Objects in a ArrayList using Java Comparator

Follow

  • Coding Utils

Useful Links

  • Spring 4.1.x Documentation
  • Spring 3.2.x Documentation
  • Spring 2.5.x Documentation
  • Java 6 API
  • Java 7 API
  • Java 8 API
  • Java EE 5 Tutorial
  • Java EE 6 Tutorial
  • Java EE 7 Tutorial
  • Maven Repository
  • Hibernate ORM

About JavaInterviewPoint

javainterviewpoint.com is a tech blog dedicated to all Java/J2EE developers and Web Developers. We publish useful tutorials on Java, J2EE and all latest frameworks.

All examples and tutorials posted here are very well tested in our development environment.

Connect with us on Facebook | Privacy Policy | Sitemap

Copyright ©2023 · Java Interview Point - All Rights Are Reserved ·