Handle uncaught exceptions in a Spring-Boot REST API – Part VI

Many times, we have seen exception thrown on your web page and all the stack trace of the exception. A non-technical user will not be able to understand most of the time. Also stack trace is not the best option when we can show the same exception error in nice JSON format with the root cause. In this post, we will show how to handle uncaught exceptions from our previous Spring REST API we built here.

This particular feature will show how to handle most HTTP 500 errors which happen because of server side issues. Any errors with request or client side, those are HTTP 400 errors and they have been handled in previous post Error Handling in Spring Boot Rest API.

Problem of uncaught exceptions

Firstly, what happens when there is a database connection issue? OR Columns in your REST API are different from specified in database tables? Your API will throw a 500 error and if you don’t have any mechanism, this will display error in an html format which will not give much information to user or developer to resolve the issue. Showing such stack trace on web page to end user is a bad example from programming perspective.

Solution

JAX-RS provides a way to handle uncaught exceptions. This can be done by my implementing an interface for ExtendedExceptionMapper. Basically this is a contract for a provider that takes java exceptions and maps them to a response object which can be transformed into a JSON. This can be implemented as below:

package com.betterjavacode.benefits.utilities;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.jersey.spi.ExtendedExceptionMapper;

@Provider
public class UncaughtExceptionMapper implements ExtendedExceptionMapper<Throwable> 
{

   private static final Logger LOGGER = LogManager.getLogger(UncaughtExceptionMapper.class);

   @Override
   public Response toResponse(Throwable exception) 
   {
     LOGGER.info("Enter >> toResponse ");
     LOGGER.debug("Exception Caught: " + exception.getMessage());
     LOGGER.info("Exit << toResponse");
     return Response.status(Status.BAD_REQUEST)
       .entity(exception.getMessage())
       .build();
   }

   @Override
   public boolean isMappable(Throwable arg0) 
   {
     return !(arg0 instanceof WebApplicationException);
   }

}

Basically this implementation shows a class `UncaughtExceptionMapper` implementing an interface `ExtendedExceptionMapper` which provides a way to map all exceptions which are not of type WebApplicationException (Most HTTP 400 errors are WebApplicationExceptions). toResponse method will help to log all the exceptions and convert exceptions into a Response object.

Conclusion

In conclusion, we showed how to map all unhandled exceptions into JSON format for a nice response. The code for this post is available at github repository.