David Gray

About David Gray

David is a software engineer with a passion for everything Java and the web. He is a server side java developer based in Derby, England by day and a Android, jQuery, jack of all trades by night.

Jax-RS custom exception handling

One of the nice things about working with JEE is the components available really are pretty standard.  While using JAX-RS, sometimes you need to control how exceptions get processed and fed back to the user.  If an exception is thrown, by default, you’ll get some horrible HTTP 500 internal server exception, exposing the internal failings of your web service.

Consider the following gist, this endpoint would be used to view a user based on the Id.
 
 
 

@Path("/users")
public interface UserWebService {
	
	@POST
	@Consumes({ MediaType.APPLICATION_JSON })
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	@Path("/{userId}")
	Response getUser(@PathParam("userId") String userId);
}

Now, the implementation of this interface would look something like the following, to do the donkey work of actually retrieving the user.

public final class UserWebServiceImpl implements UserWebService {
	
	@EJB 
	private UserDao userDao;
	
	public Response getUser(final String userId) {
		final User user = userDao.getUser(userId);
		return Response.ok().entity(user).build();
	}
}

This looks fine, but consider if the userDao was doing some entity business logic, using Query.getSingleResult and the user with this ID didn’t exist?

According to the JEE6 API documentation, you’d receive a NoResultException, which would cause an HTTP 500 error exposing your internal server exception, which is definitely something end users shouldn’t see. We need to leverage the exception handling of Jax-RS!

First, we need a dumb exception object, appropriately named, which will be what we’ll actually throw, consider the code below..

public class UserWebServiceException extends Exception implements
	Serializable {

	private static final long serialVersionUID = 1169426381288170661L;

	public UserWebServiceException() {
		super();
	}

	public UserWebServiceException(String msg) {
		super(msg);
	}

	public UserWebServiceException(String msg, Exception e) {
		super(msg, e);
	}
}

Next, we need to modify our original code to take into account this exception, I’ve modified the original UserWebService and associated implementation appropriately below.

@Path("/users")
public interface UserWebService {
	
	@POST
	@Consumes({ MediaType.APPLICATION_JSON })
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	@Path("/{userId}")
	Response getUser(@PathParam("userId") String userId) throws UserWebServiceException;
}
public final class UserWebServiceImpl implements UserWebService {
	
	@EJB 
	private UserDao userDao;
	
	public Response getUser(final String userId) throws UserWebServiceException {
		try {
			final User user = userDao.getUser(userId);
		} catch(NoResultException e) {
			throw new UserWebServiceException("User does not exist with id " + userId);
		}
		return Response.ok().entity(user).build();
	}
}

This will now throw an appropriate exception when a user cannot be found. However, we still need to create a Handler object to convert this exception into an actual JSON response so we get a nice friendly error message. The class below handles this exception and will convert the error message in the exception into a JSON response. The important annotation you’ll see on this class is the @Provider annotation.

@Provider
public final class UserWebServiceExceptionHandler implements
	ExceptionMapper<UserWebServiceException> {

	@Override
	public Response toResponse(final UserWebServiceException exception) {
		return Response.status(Status.BAD_REQUEST)
			.entity(new ErrorMessage(exception.getMessage())
			).type(MediaType.APPLICATION_JSON).build();
	}	
}

You’ll notice we create an ErrorMessage object to respond to from the web service. This is just a simple dumb object to hold the details of the actual error that’ll be marshalled into JSON.

public class ErrorMessage {
	private String error;

	public ErrorMessage(String error) {
		this.error = error;
	}

	public String getError() {
		return error;
	}
}

The final step in mapping our exception handler provider to the web-app is to add the following into our web.xml for our webapp.

<context-param>
	<param-name>resteasy.providers</param-name>
  	<param-value>uk.co.soa.rest.providers.UserWebServiceExceptionHandler</param-value>        
</context-param>

Now when we call this REST endpoint with a user ID that doesn’t exist (let’s say “DAG”), we’ll happily receive the following JSON response rather than a stacktrace.

{
	"error": "User does not exist with id DAG"
}
Reference: Jax-RS custom exception handling from our JCG partner David Gray at the Code Mumble blog.
Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

Leave a Reply


eight − 7 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books