Newsletter

Exception Handling in RESTful Web Services (JAX-RS) with Jersey

Web Services » on May 21, 2017 { 13 Comments } By Sivateja

Exception handling in RESTful (JAX-RS) web services is a very important concept, in this article I am going to explain it step by step with an example. FYI. check this article for Creating Simple Maven RESTful Web Service Project in Eclipse. I am directly going to start with directory structure of the current example.

Directory structure

As we are dealing with exception handling, I am going to create a service which will throw an exception 🙂

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" 
	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>RESTExceptionHandlingExample</groupId>
<artifactId>RESTExceptionHandlingExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
 
<repositories>
       <repository>
         <id>maven2-repository.java.net</id>
          <name>Java.net Repository for Maven</name>
          <url>http://download.java.net/maven/2/</url>
          <layout>default</layout>
       </repository>
</repositories>
 
<dependencies>
       <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.8.2</version>
          <scope>test</scope>
       </dependency>
 
       <dependency>
          <groupId>com.sun.jersey</groupId>
          <artifactId>jersey-server</artifactId>
          <version>1.8</version>
       </dependency>
</dependencies>
 
<build>
   <finalName>RESTExceptionHandlingExample</finalName>
   <plugins>
      <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
             <configuration>
                <compilerVersion>1.8</compilerVersion>
                <source>1.8</source>
                <target>1.8</target>
             </configuration>
       </plugin>
   </plugins>
</build>
 
</project>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns="http://java.sun.com/xml/ns/j2ee" 
         xmlns:web="http://xmlns.jcp.org/xml/ns/javaee" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.4">
  <display-name>RESTExceptionHandlingExample</display-name>
  <servlet>
    <servlet-name>jersey-serlvet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>com.java4s</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>jersey-serlvet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping> 
</web-app>

RESTResource.java

package com.java4s;
 
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
 
@Path("/customers")
public class RESTResource {
	
	@GET
	@Path("/checkProfile/{id}")
	public Response getAdminDetails(@PathParam("id") String id) {
		
		String msg = RESTService.checkCustomerStatus(id);
 
		return Response.status(200).entity(msg).build(); 
	} 	
}

RESTService.java

package com.java4s;

public class RESTService {
	
	CallDB cdb = new CallDB();
	
	public String checkCustomerStatus(String custId){
		
		MyData da = cdb.getStatus(custId);
		
		return da.getStatus().trim();			
	}
}

CallDB.java

package com.java4s;

public class CallDB {
	
	public MyData getStatus(String custId) {
				
	     // Lets say, database logic will go here and setting the output in MyData bean
		
	        MyData da = new MyData();
			
             // da.setStatus("Valid");
			
	        return da;
			
        }
}

MyData.java

package com.java4s;

public class MyData {
	
	String status;

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}	
}

Explanation

So we are good to run the application now,  if you observe I have just created 4 java classes till now..

  • RESTResource.java
  • RESTService.java
  • CallDB.java
  • MyData.java

The application will start by hitting the following URL [ I am using 2017 as my server port, this might be different for your server]

http://localhost:2017/RESTExceptionHandlingExample/customers/checkProfile/100

  • If you hit the above URL, the flow will come to RESTResource.java, in that at line number 17, I am calling checkCustomerStatus( – ) function of RESTService class, by passing the id
  • Consider, CallDB is a class which handle all database related stuff, so in RESTService.java > line number 11, I am calling getStatus( – ) of CallDB
  • In CallDB.java > consider we had a database call at line number 7,  after that creating MyData class object and setting all the data that I retrieved from the database and returning it at line number 13, if you observe line number 11, I have commented the setter method, means I am not setting status, so by default it contains NULL value ( if we call its getter method, it will return NULL)
  • Now the flow will come to RESTService.java > at line number 11, I am calling getStatus(), as this gives null value [as we have not set anything in CallDB > line 11], on that null I am calling .trim() again, which will give NullPointerException 🙂

Hmm.. so successfully we are able to create a service, which will throw a NullPointerException 🙂 If you hit the URL, you will see..


Its the Tomcat default error page, showing the exception as NullPointerException but I don’t think its the right way of displaying the errors to the consumers! lets try to display the error with some custom error message, in order to do that I am going to create a custom (user defined) run time exception, lets say my custom exception class name is CustomerDataNotFoundException.

CustomerDataNotFoundException.java

package com.java4s.ExceptionHandlingRelated;

public class CustomerDataNotFoundException extends RuntimeException{

	private static final long serialVersionUID = 1L;

	public CustomerDataNotFoundException(String exceptionMsg)
	{
		super(exceptionMsg);
	}
	
}

Here I have just created an exception class with constructor which takes String as an argument, now let me change RESTService.java as..

RESTService.java

package com.java4s;

import com.java4s.ExceptionHandlingRelated.CustomerDataNotFoundException;

public class RESTService {
	
	CallDB cdb = new CallDB();
	
	public String checkCustomerStatus(String custId){
		
		MyData da = cdb.getStatus(custId);		
		
		if(da.getStatus() == null)
		{
			throw new CustomerDataNotFoundException("Customer status not found with id "+custId);
		}
		
		return da.getStatus().trim();
			
	}
}

I am checking the status with if condition. If status is NULL, throwing out the custom exception by passing some meaningful message. Lets run the application and see..


Its throwing our exception with the message we have sent, not bad 😉 but still this is not the right way of showing the errors.

What happens behind the scenes

Actually we are throwing CustomerDataNotFoundException if the status is NULL, if you observe, we are not handling that exception in RESTService, instead simply throwing with our message. So the exception keeps bubbling up and will come to RESTResource (here also we are not handling ) and so from there to JAX-RS and finally will reach Tomcat server container, and server will show its default error page, that’s what we are seeing in the above image.

So in order to stop exception bubbling up to the tomcat server container, we need to create an exception mapper.

CustomerDataNotFoundExceptionMapper.java

package com.java4s.ExceptionHandlingRelated;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class CustomerDataNotFoundExceptionMapper implements ExceptionMapper<CustomerDataNotFoundException>{
	
	public Response toResponse(CustomerDataNotFoundException ex)
	{
		return Response.status(Status.NOT_FOUND)
				.entity(new ErrorProps("404", ex.getMessage()))
				.build();
	}
}

ErrorProps.java

package com.java4s.ExceptionHandlingRelated;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class ErrorProps {
	
	private String status;
	private String errorMessage;
	
	public ErrorProps(){}
	
	public ErrorProps(String statusFromOutside, String errorMessageFromOutside)
	{
		this.status = statusFromOutside;
		this.errorMessage = errorMessageFromOutside;
	}
	
	
	public String getErrorMessage() {
		return errorMessage;
	}
	public void setErrorMessage(String errorMessage) {
		this.errorMessage = errorMessage;
	}
	public String getStatus() {
		return status;
	}
	public void setStatus(String status) {
		this.status = status;
	}	

}

Explanation

  • Created an exception mapper CustomerDataNotFoundExceptionMapper for CustomerDataNotFoundException 
  • All exception mappers should implement ExceptionMapper interface of type generic, for now I am going to use this exception mapper only for our exception, so I have implemented ExceptionMapper of type CustomerDataNotFoundException [check at line number 9]
  • We need to override the toResponse method of ExceptionMapper interface, which takes exception as an argument, in this case CustomerDataNotFoundException
  • I want to display my exception details as an XML, so created a simple java model ErrorProps.java and annotated with @XmlRootElement
  • Now come back to mapper class toResponse method, there I am returning Response object

    Response.status( – ) :- setting the current status
    .entity( – ) :- passing ErrorProps class object by setting required values, here I am setting status as 404, and our custom exception message

  • Finally annotate our mapper class with @Provider annotation, so that JAX-RS will register this mapper to intercept the response when particular exception was thrown

Go ahead and run the application and see…

 

We did it 🙂

But this is only for NullPointerException, but how about the other exceptions ? for that we need to modify the mapper. Let me do it by creating new mapper class.

GenericExceptionMapper.java

package com.java4s.ExceptionHandlingRelated;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable>{
	
	public Response toResponse(Throwable ex)
	{
		if(ex instanceof CustomerDataNotFoundException)
		{
		
			return Response.status(Status.NOT_FOUND)
				       .entity(new ErrorProps("404", ex.getMessage()))
				       .build();
		}
		else
		{
			return Response.status(Status.INTERNAL_SERVER_ERROR)
					.entity(new ErrorProps("Some error code, 500 or somthing", ex.getMessage()))
					.build();
		}
	}

}

What are the changes ?

Implement ExceptionMapper of type Throwable, instead of our own exception. If you check the above class, at line number 13, I am checking whether the Throwable is the instance of CustomerDataNotFoundException, if its true, I will build my Response accordingly, like this you can handle any number of exceptions in a single class, you can download and play with it.

That’s it friends, hope you enjoy the article 😉

​​

You Might Also Like

  ::. About the Author .::

Java4s_Author
Sivateja Kandula - Java/J2EE Full Stack Developer
Founder of Java4s - Get It Yourself, A popular Java/J2EE Programming Blog, Love Java and UI frameworks.
You can sign-up for the Email Newsletter for your daily dose of Java tutorials.

Comments

13 Responses to “Exception Handling in RESTful Web Services (JAX-RS) with Jersey”
  1. mangesh says:

    Very easy to understand for all concepts. Please provide Design Pattern tutorial

  2. Vamshi Krishna says:

    I have seen lot blogs and Information on other sites But in this Blog Information is very useful

  3. Rambabu Mandalapu says:

    RestResource.java File need to be corrected. However downloaded example already having right code.

  4. ram says:

    Hi Kindly post Rest Client and How to publish Restful web services

  5. ajit says:

    Please include web service (rest and soap)security topic.thanks.we like all your explanations….

  6. deepak ahuja says:

    Very Nicely Explained.

  7. Akhil R says:

    Thank you Sir. Quit understandable, please do add code for JSON response as well. I bit confused with that concept and on other online resources its difficult to understand.

  8. Pavani says:

    Please include an article for OAuth authentication for REST

  9. sai prakash p says:

    Thanks, it was good Simple and well formed example..!!

  10. ssb says:

    In Single word … ultimate…

  11. Vikas says:

    Superb explanation in easy language. Cleared all my doubts. Self descriptive. Found so many blogs but this one is ultimate one for me

  12. Revana M J says:

    Hi,
    Some one can you please help me how to implement Oauth2 with Jesry Rest API.

Name*
Mail*
Website



By posting your answer, you agree to our comments policy.
Most Recent Posts from Top Categories
Spring Boot Hibernate Spring
Contact | About Us | Privacy Policy | Advertise With Us

© 2010 - 2024 Java4s - Get It Yourself.
The content is copyrighted to Sivateja Kandula and may not be reproduced on other websites.