JAVA spring boot

Spring REST Exception Handling Example

This article explains how to handle exceptions while creating RESTful web services using spring framework.

Spring is one of the popular frameworks used to build RESTful web services. It is very easy to create Restful services using the spring framework. While creating the spring applications or web services, exception handling is also essential.

Spring framework provides different built-in features to handle the exception that may occur during program execution.

In this article, we will learn about exception handling properly and efficiently while building our RESTful spring applications.

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

Table of Contents

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 exceptions 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 a 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 is limited only to the current controller class. This may also cause more problems if there are multiple controller classes in an application.

Global Exception Handler

We can handle exceptions that occurred within the spring application globally using @ControllerAdvice annotation. Spring version 3.2+ added this feature. We can apply this annotation 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. We can annotate these methods with @ExceptionHandler annotation and also we can set the value property of the annotation to handle different types of exceptions.

Below is an example global exception handler class.

@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 also define any custom exception and tag an HTTP response status to it as shown below.

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

Handling Exception in RESTful spring services

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

Advertisements

We will create an ApiError.java class, which we will use as an API response for any exceptions that occurred in RESTful service. This class will also 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 a 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 the user-defined exceptions as well as other exceptions.

Below GlobalErrorHandler.java class shows how to define a global exception handler with the 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 the 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");
	}
}

Testing the application

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

The postman response displays the exception with the expected JSON format as shown below.

spring exception handling

Conclusion

In this article, we learned about how to handle exceptions and return proper error responses back to the service consumers.

We also learned how to use a global error handler to handle all the errors in a single place and created example applications.