Spring Boot – Exception Handling

Handling exceptions and errors in APIs and sending the proper response to the client is good for enterprise applications. In this chapter, we will learn how to handle exceptions in Spring Boot.

Before proceeding with exception handling, let us gain an understanding on the following annotations.

1. Controller Advice

The @ControllerAdvice is an annotation, to handle the exceptions globally.

2. Exception Handler

The @ExceptionHandler is an annotation used to handle the specific exceptions and sending the custom responses to the client.

You can use the following code to create @ControllerAdvice class to handle the exceptions globally −

package com.maixuanviet.demo.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;

@ControllerAdvice
   public class ProductExceptionController {
}

Define a class that extends the RuntimeException class.

package com.maixuanviet.demo.exception;

public class ProductNotfoundException extends RuntimeException {
   private static final long serialVersionUID = 1L;
}

You can define the @ExceptionHandler method to handle the exceptions as shown. This method should be used for writing the Controller Advice class file.

@ExceptionHandler(value = ProductNotfoundException.class)

public ResponseEntity<Object> exception(ProductNotfoundException exception) {
}

Now, use the code given below to throw the exception from the API.

@RequestMapping(value = "/products/{id}", method = RequestMethod.PUT)
public ResponseEntity<Object> updateProduct() { 
   throw new ProductNotfoundException();
}

The complete code to handle the exception is given below. In this example, we used the PUT API to update the product. Here, while updating the product, if the product is not found, then return the response error message as “Product not found”. Note that the ProductNotFoundException exception class should extend the RuntimeException.

package com.maixuanviet.demo.exception;
public class ProductNotfoundException extends RuntimeException {
   private static final long serialVersionUID = 1L;
}

The Controller Advice class to handle the exception globally is given below. We can define any Exception Handler methods in this class file.

package com.maixuanviet.demo.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class ProductExceptionController {
   @ExceptionHandler(value = ProductNotfoundException.class)
   public ResponseEntity<Object> exception(ProductNotfoundException exception) {
      return new ResponseEntity<>("Product not found", HttpStatus.NOT_FOUND);
   }
}

The Product Service API controller file is given below to update the Product. If the Product is not found, then it throws the ProductNotFoundException class.

package com.maixuanviet.demo.controller;

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

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.maixuanviet.demo.exception.ProductNotfoundException;
import com.maixuanviet.demo.model.Product;

@RestController
public class ProductServiceController {
   private static Map<String, Product> productRepo = new HashMap<>();
   static {
      Product honey = new Product();
      honey.setId("1");
      honey.setName("Honey");
      productRepo.put(honey.getId(), honey);
      
      Product almond = new Product();
      almond.setId("2");
      almond.setName("Almond");
      productRepo.put(almond.getId(), almond);
   }
   
   @RequestMapping(value = "/products/{id}", method = RequestMethod.PUT)
   public ResponseEntity<Object> updateProduct(@PathVariable("id") String id, @RequestBody Product product) { 
      if(!productRepo.containsKey(id))throw new ProductNotfoundException();
      productRepo.remove(id);
      product.setId(id);
      productRepo.put(id, product);
      return new ResponseEntity<>("Product is updated successfully", HttpStatus.OK);
   }
}

The code for main Spring Boot application class file is given below −

package com.maixuanviet.demo;

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

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

The code for POJO class for Product is given below −

package com.maixuanviet.demo.model;
public class Product {
   private String id;
   private String name;

   public String getId() {
      return id;
   }
   public void setId(String id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}

The code for Maven build – pom.xml is shown below −

<?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 
   http://maven.apache.org/xsd/maven-4.0.0.xsd">
   
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.maixuanviet</groupId>
   <artifactId>demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>demo</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.8.RELEASE</version>
      <relativePath/> 
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <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-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>

The code for Gradle Build – build.gradle is given below −

<?xml version = "1.0" encoding = "UTF-8"?>
buildscript {
   ext {
      springBootVersion = '1.5.8.RELEASE'
   }
   repositories {
      mavenCentral()
   }
   dependencies {
      classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
   }
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

group = 'com.maixuanviet'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
   mavenCentral()
}
dependencies {
   compile('org.springframework.boot:spring-boot-starter-web')
   testCompile('org.springframework.boot:spring-boot-starter-test')
}

You can create an executable JAR file, and run the Spring Boot application by using the Maven or Gradle commands −

For Maven, you can use the following command −

mvn clean install

After “BUILD SUCCESS”, you can find the JAR file under the target directory.

For Gradle, you can use the following command −

gradle clean build

After “BUILD SUCCESSFUL”, you can find the JAR file under the build/libs directory.

You can run the JAR file by using the following command −

java –jar <JARFILE>

This will start the application on the Tomcat port 8080 as shown below −

Exception Handling Tomcat Application Startded

Now hit the below URL in POSTMAN application and you can see the output as shown below −

Update URL:

http://localhost:8080/products/3
Postman Application Update URL

Related posts:

Java Program to Describe the Representation of Graph using Incidence Matrix
Java – Combine Multiple Collections
Java Program to Perform Naive String Matching
Java Program to Implement AA Tree
Java Program to Delete a Particular Node in a Tree Without Using Recursion
LIKE Queries in Spring JPA Repositories
Java Program to Implement Segment Tree
Model, ModelMap, and ModelAndView in Spring MVC
Checking for Empty or Blank Strings in Java
Mệnh đề if-else trong java
Hướng dẫn Java Design Pattern – Mediator
Convert a Map to an Array, List or Set in Java
Chương trình Java đầu tiên
Java Program to Find Path Between Two Nodes in a Graph
Getting the Size of an Iterable in Java
Hướng dẫn Java Design Pattern – MVC
Hướng dẫn Java Design Pattern – Builder
Sử dụng JDBC API thực thi câu lệnh truy vấn dữ liệu
Java Program to Perform Sorting Using B-Tree
Java – Create a File
Spring Security and OpenID Connect
Java Program to Perform Cryptography Using Transposition Technique
Java Program to Find Nearest Neighbor Using Linear Search
Java List UnsupportedOperationException
Redirect to Different Pages after Login with Spring Security
Java Program to Find Median of Elements where Elements are Stored in 2 Different Arrays
Java Program to Perform the Unique Factorization of a Given Number
Generic Constructors in Java
Java Program to Implement Queue
Java Program to Check if it is a Sparse Matrix
Java Program to Implement LinkedBlockingDeque API
Java Program to Implement Sorted Vector