Spring is one of the popular framework used to build RESTful web services. It is very easy to create Restful services using spring framework. While creating any applications or web services, It is very important that we have to handle the exceptional cases that may occur during the execution of the program.

Spring framework provides different built in features to handle the exceptions that may occur during program execution. In this article, we will learn how to use these features and handle exceptions in a proper and efficient way while building our RESTful applications.

Spring provides different options to handle exceptions. We will learn how to use them in the following sections.

Using @ExceptionHandler annotation :

We can use controller level exception handler methods in each one of our controller classes. This method only handles the exception within that particular controller.

An implementation example of @ExceptionHandler to handle exception in spring RESTful services is given below. Here, any exception thrown by the RestControllerExample class is handled by the method handleException() and returns exception messages as response along with HTTP status.

@RestController
public class RestControllerExample{
		
	@GetMapping(value="/", produces="application/json")
	public String test() throws Exception {
			
		throw new Exception("New Exception is thrown.!");
	}
		
	@ExceptionHandler(value= {Exception.class})
	public ResponseEntity<String> handleException(Exception e){
			
		return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
	}
}

Using @ExceptionHandler annotation to handle exceptions may not be the better approach. The scope of these handler methods are limited only to the current controller class. This may cause more problem if there are multiple controller classes in a application.

Global Exception Handler

We can handle exceptions occurred within spring application globally using @ControllerAdvice annotation. This feature is introduced in spring version 3.2+. This annotation is applied to a class, which handles multiple exceptions thrown by the application at runtime.

We can create a global exception class and annotate it with @ControllerAdvice annotation. This class will contain methods to handle different exceptions. These methods are annotated with @ExceptionHandler annotation and value property of the annotation is set to handle different types of exceptions.

An example global exception handler class is shown below.

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MyException.class) 
    public ResponseEntity<> handleMyException(MyException e){
      //code here
    }
}

Using Response Status

Spring provides @ResponseStatus annotation to indicate the HTTP status for any custom exception class. We can define any custom exception and tag a HTTP response status to it as shown below.

@ResponseStatus(HttpStatus.NOT_FOUND)
public class RecordNotFoundException extends RuntimeException {
}

Handling Exceptions in RESTful services

While developing RESTful web services, it is very important to handle the exceptional cases. It is also very good practice to send back a proper error response back to client with proper error details and a HTTP status.

We will create a ApiError.java class, which can be used as API response for any exceptions occurred in RESTful service. This class will have an error code field and a message field to send the error reason back to the called client.

import java.time.LocalDateTime;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class ApiError {
	
    private String code;
    private String message;
    private LocalDateTime timestamp;
  
    public ApiError(String message, String code, LocalDateTime datetime) {
        super();
        this.message = message;
        this.code = code;
        this.timestamp = datetime;
    }
}

Create a custom exception class CustomException.java and add the following content.

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

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class CustomException extends RuntimeException {
	
	private String code;
	private String message;
	
	public CustomException() {
		super();
	}
	
	public CustomException(String message, String code) {
		super(message);
		this.code = code;
	}
	
	public String getCode() {
		return code;
	}
}

Create a class and annotate with @ControllerAdvice annotation. This class will act as global exception handler. We have to create required error handling methods inside the global exception handler class.

We can create error handling methods for both user defined exceptions as well as other exceptions.

Below GlobalErrorHandler.java class shows how to define a global exception handler with custom exception, error message and date-time value.

import java.time.LocalDateTime;

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

@ControllerAdvice
public class GlobalErrorHandler {

	@ExceptionHandler(value = { CustomException.class })
	public ResponseEntity<ApiError> handleCustomException(CustomException e, WebRequest request) {
		ApiError error = new ApiError(e.getMessage(), e.getCode(), LocalDateTime.now());
		return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
	}
}

Create a TestController.java class to test our global error handler class. Add the following content to the controller class.

We have a simple GET mapping to map all the requests to callMethod() method. Inside this method we are throwing our custom exception.

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

	@GetMapping("/")
	public ResponseEntity<Object> callMethod(){
		throw new CustomException("My custom Exception!!", "555");
	}
}
Test the application

Start the spring boot application, open the postman and access the created URL : localhost:8080/

Exception with expected JSON format is displayed on postman response as shown below.

In this article we learned about how to handle exceptions and return proper error response back to service consumer. Well done! 🙂

You may also interested in