Handle Exceptions in Spring Boot RESTful Service

With this Spring Boot tutorial, I am going to share with how to handle exceptions in your RESTful Web Service application build with Spring Boot.

What If Exception Takes Place

The good news is that if Exception takes place and your code does not handle it, Spring Boot will handle the Exception for you and will return back to a calling client application a well-formatted JSON or XML message. Like for example the one below:

{
    "timestamp": "2018-04-18T23:38:30.376+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "could not execute statement; SQL [n/a]; constraint [UK_6dotkott2kjsp8vw4d0m25fb7]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
    "path": "/users"
}

To produce this JSON document I did not have to programmatically create the JSON document or a Java class and then convert it to JSON. I did not have to set myself the values of error, path or status code. All of these is handled for us by the framework.

What If You Throw Your Own Exception

Another good news is that if you throw your own custom Exception the calling client application will get exactly same JSON or XML payload structure. The error message and the timestamp values, of course, will be different but the structure of the document returned will be the same.  So you do not need to create it and set its values programmatically.

Let’s create our own Runtime Exception and throw it.

package com.appsdeveloperblog.app.ws.exceptions;

public class UserServiceException extends RuntimeException{
    
    private static final long serialVersionUID = 5776681206288518465L;
    
    public UserServiceException(String message)
    {
    	  super(message);
    }
}

Now let’s throw this Exception

@Override
public UserDetails loadUserByUsername(String username) throws UserServiceException {

    UserEntity userEntity = userRepository.findUserByEmail(username);

    if (userEntity == null) {
        throw new UserServiceException("User " + username + " not found");
    }

    return new User(userEntity.getEmail(), userEntity.getEncryptedPassword(), new ArrayList<>());
}

the resulting JSON payload returned back with a Response will be:

{
    "timestamp": "2018-04-18T23:51:54.405+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "User sergey not found",
    "path": "/users/sergey"
}

How to Handle Any Exception

You can handle any exception that took place anywhere in your RESTful Web Services app built with Spring Boot. To do that we need to define a new Java class with a single method that will be responsible for catching all those Exceptions.

  1. Create a new class annotated with @ControllerAdvice
  2. Add a method that is annotated with @ExceptionHandler specifying which Exception class this method needs to handle.
package com.appsdeveloperblog.app.ws.exceptions;

import org.springframework.http.HttpHeaders;
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;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class EntityExceptionHandler {

@ExceptionHandler(value = { Exception.class })
public ResponseEntity<Object> handleAnyException(Exception ex, WebRequest request) {
        return new ResponseEntity<>(
          ex.getMessage(), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

This is it!

Return Custom Error Message Object

To make the returned error message be of a specific JSON or XML structure, you can create a Java bean class and use it as Response Entity.

import java.util.Date;
 
public class ErrorMessage {
  private Date timestamp;
  private String message;
  private String details;

  public ErrorMessage(){}

  public ErrorMessage(Date timestamp, String message, String details) {
    this.timestamp = timestamp;
    this.message = message;
    this.details = details;
  }
 
    public Date getTimestamp() {
        return timestamp;
    }

 
    public void setTimestamp(Date timestamp) {
        this.timestamp = timestamp;
    }
 
    public String getMessage() {
        return message;
    }

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

 
    public String getDetails() {
        return details;
    }

 
    public void setDetails(String details) {
        this.details = details;
    }

}

Now use this custom ErrorMessage class as Response Entity in your Exception Handler class

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;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import java.util.Date;


@ControllerAdvice
public class MyExceptionHandler {
  @ExceptionHandler(Exception.class)
  public final ResponseEntity<ErrorMessage> handleAllExceptions(Exception ex, WebRequest request) {
    
    ErrorMessage errorObj = new ErrorMessage(new Date(), ex.getMessage(),
        request.getDescription(false));
    return new ResponseEntity<>(errorObj, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
  }
}

Handle Your Own Custom Runtime Exception

Earlier in this tutorial, we have created our own custom UserServiceException which extends RuntimeException.

package com.appsdeveloperblog.app.ws.exceptions;

public class UserServiceException extends RuntimeException{
    
    private static final long serialVersionUID = 5776681206288518465L;
    
    public UserServiceException(String message)
    {
    	  super(message);
    }
}

If this exception is thrown, then we can handle it using the below exception handler class. And to make it handle our own specific custom exception, we will simply specify the name of our exception in @ExceptionHandler annotation.

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;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import java.util.Date;


@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {
  @ExceptionHandler(UserServiceException.class)
  public final ResponseEntity<ErrorMessage> handleSpecificExceptions(Exception ex, WebRequest request) {

    ErrorMessage errorMessage = new ErrorMessage(new Date(), ex.getMessage(),
        request.getDescription(false));
    return new ResponseEntity<>(errorMessage, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
  }
}

Handle More Than One Exception 

If you need a method to handle more than one Exception then you can specify those exceptions separating them with a comma inside of @ExceptionHandler annotation. For example:

@ExceptionHandler(UserNotFoundException.class, RecordExistsException.class)

Here is how you use it within a class:

@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {
  @ExceptionHandler(UserNotFoundException.class, RecordExistsException.class)
  public final ResponseEntity<ErrorMessage> handleUserExceptions(Exception ex, WebRequest request) {

    ErrorMessage errorMessage = new ErrorMessage(new Date(), ex.getMessage(),
        request.getDescription(false));
    return new ResponseEntity<>(errorMessage, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
  }

}

Handle Exception Inside of @RestController class

You can also handle an exception within the same class it was thrown if you like. For example, you can have one the methods in your @RestController class handle an exception message. This will work well, although I prefer not to have methods that handle an exception in my @RestController classes.

Here is an example of a very simple Root Resource class annotated with @RestController annotation which intentionally throws an exception right away to demonstrate how it can be handled within the same class.

Notice the @ExceptionHandler within same class?
Also, the source code of an ErrorMessage class which is being used as a Response Entity can be taken from this same tutorial. It is a few paragraphs above.

@RestController
@RequestMapping("users")
public class UserController {

    @Autowired
    UserService userService;
 

    @PostMapping
    public UserRest createUser(@RequestBody UserDetailsRequestModel requestUserDetails) {
        UserRest returnValue = new UserRest();

// THROW EXCEPTION NOW JUST FOR DEMONSTRATION PURPOSES
                
        if(true) throw new MissingRequiredFieldException("One of the required fields is missing");
/////
        UserDto userDto = new UserDto();
        BeanUtils.copyProperties(requestUserDetails, userDto);

        UserDto createdUser = userService.createUser(userDto);
        BeanUtils.copyProperties(createdUser, returnValue);

        returnValue.setHref("/users/" + createdUser.getUserId());

        return returnValue;
    }


    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingRequiredFieldException.class)
    public ErrorMessage handleBadRequest(HttpServletRequest req, Exception ex) {
       return new ErrorMessage(new Date(), ex.getMessage(), req.getRequestURI());
    }


}

Create @ControllerAdvice Video Tutorial

 

 

I hope this short tutorial on how to handle Exceptions in RESTful Web Services app built with Spring Boot was helpful to you. To learn more about Spring Boot by following step-by-step video lessons, check out the below video courses and hopefully one of them will help you take your skills to a new level.