Rest using Jersey – Complete Tutorial with JAXB, Exception Handling and Client Program
Recently I started working on a Restful web service project using Jersey API. There are some tutorials available online but I faced some issues with exception handling and I didn’t found anywhere complete project using JaxB and providing exception handling approach. So once I was able to create a Restful web service using Jersey API with exception handling and client program, I decided to write this tutorial to help everyone getting started with Jersey.
Who Should Use This Tutorial
This tutorial is intended for Java programmers who are interested in developing and deploying Restful Web Services using Jersey API and JaxB.
Prerequisites
The scope of this tutorial is to use Jersey API for creating Restful web services and invoking the web service using Java client program and testing web service using tool. Basic understanding of Java, Web Services, XML, Maven and any application server (JBoss/Tomcat) is required to understand the tutorial with ease.
Softwares and Tools used
- JDK version 1.6.0_37
- Apache Maven 3.0.3
- Mac OS X 10.8.2
- JBoss 4.2.2 (You can use any application server like Tomcat, Glassfish etc.)
- Eclipse Indigo (Any Java IDE with Maven support)
Creating Maven Project in Eclipse and Jersey
Create a maven project in Eclipse and it will provide you with basic project structure. I have given GroupId as “JD” and artifactID as “my-jersey-project” but you can give anything you like. Once we complete the development of our project, it will look like below in the image.
Jersey Web service project explanation
pom.xml: Project configuration details, note the jersey dependencies provided, other details are common for any maven project.
<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>JD</groupId> <artifactId>my-jersey-project</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>1.14</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-servlet</artifactId> <version>1.14</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.14</version> </dependency> </dependencies> <build> <finalName>${artifactId}-${version}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.1-alpha-2</version> <configuration> <packagingExcludes> WEB-INF/lib/servlet-api-*.jar </packagingExcludes> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.0</version> <executions> <execution> <id>unpack</id> <phase>install</phase> <goals> <goal>unpack</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>${groupId}</groupId> <artifactId>${artifactId}</artifactId> <version>${version}</version> <type>${packaging}</type> <overWrite>true</overWrite> <outputDirectory>${project.build.directory}/${artifactId}-${version}-exploded.${packaging}</outputDirectory> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
EmpRequest.java: Java Bean for the request object. The important thing to note here is @XmlRootElement annotation to map the class to an XML element.
package com.jd.model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = 'empRequest') public class EmpRequest { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
EmpResponse.java: Java bean for the response object.
package com.jd.model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = 'empResponse') public class EmpResponse { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
ErrorResponse.java: Java Bean that will be send as response incase of exception.
package com.jd.model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = 'errorResponse') public class ErrorResponse { private String errorCode; private int errorId; public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } public int getErrorId() { return errorId; } public void setErrorId(int errorId) { this.errorId = errorId; } }
EmpNotFoundException.java: A normal exception class thrown in the web service.
package com.jd.exception; public class EmpNotFoundException extends Exception { private static final long serialVersionUID = 4351720088030656859L; private int errorId; public int getErrorId() { return errorId; } public EmpNotFoundException(String msg, int errorId) { super(msg); this.errorId = errorId; } public EmpNotFoundException(String msg, Throwable cause) { super(msg, cause); } }
jboss-web.xml: To define JBoss servlet context for the web service.
<jboss-web> <context-root>jd</context-root> </jboss-web>
web.xml: Deployment descriptor for the web service. So any request with URI “http://<HOST>:<POST>/jd/rest/*” will be processed by Jersey ServletContainer servlet. Important thing to note is the init-param value passed for “com.sun.jersey.config.property.packages”. This defines in which package jersey will look for the web service classes. This property must point to your resources classes. It also looks for the resource classes into the sub-packages.
<?xml version='1.0' encoding='UTF-8'?> <web-app id='WebApp_ID' version='2.5' xmlns='http://java.sun.com/xml/ns/javaee' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd'> <display-name>My Jersey Project</display-name> <!-- Jersey Servlet configurations --> <servlet> <servlet-name>Jersey REST Service</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.jd</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Jersey REST Service</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> <!-- Jersey Servlet configurations --> </web-app>
EmpRouter.java: Resource class handling different kinds of request.
- @Path(“/emp”) – All the requests with URI http://<HOST>:<PORT>/jd/rest/emp/ will be processed by this resource class.
- @Path(“/getEmp”) – All the requests with URI http://<HOST>:<PORT>/jd/rest/emp/getEmp will be processed by this method.
- @POST – This annotation defines that the HTTP method used should be POST. Some other possible values are @GET, @PUT, @DELETE
- @Consumes(MediaType.APPLICATION_XML) – The method accepts XML element
- @Produces(MediaType.APPLICATION_XML) – The method returns XML element
package com.jd.router; import com.jd.exception.EmpNotFoundException; import com.jd.model.*; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.xml.bind.JAXBElement; @Path('/emp') public class EmpRouter { @POST @Path('/getEmp') @Consumes(MediaType.APPLICATION_XML) @Produces(MediaType.APPLICATION_XML) public Response getEmp(JAXBElement<EmpRequest> empRequest) throws EmpNotFoundException { EmpResponse empResponse = new EmpResponse(); if (empRequest.getValue().getId() == 1) { empResponse.setId(empRequest.getValue().getId()); empResponse.setName(empRequest.getValue().getName()); } else { throw new EmpNotFoundException('Wrong ID', empRequest.getValue() .getId()); } return Response.ok(empResponse).build(); } }
EmpNotFoundExceptionMapper.java: Exception Mapper class that maps EmpNotFoundException to Response object. The class should have annotation @Provider. This class should be in the package provided for resource classes in web.xml. Implementation of toResponse() method generates the ErrorResponse object and set it as Entity in Response object with status as INTERNAL_SERVER_ERROR.
package com.jd.exceptionmapper; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; import com.jd.exception.EmpNotFoundException; import com.jd.model.ErrorResponse; @Provider public class EmpNotFoundExceptionMapper implements ExceptionMapper<EmpNotFoundException> { public EmpNotFoundExceptionMapper() { } public Response toResponse( EmpNotFoundException empNotFoundException) { ErrorResponse errorResponse = new ErrorResponse(); errorResponse.setErrorId(empNotFoundException.getErrorId()); errorResponse.setErrorCode(empNotFoundException.getMessage()); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( errorResponse).type( MediaType.APPLICATION_XML).build(); } }
Our web service is ready, just build it to create the WAR file and deploy it in the application server.
EmpClient.java: This is a sample java program through which are invoking our web service. We are using jersey client API to invoke the service and based on response status we are parsing response entity to EmpResponse or ErrorResponse class.
package com.jd.client; import javax.ws.rs.core.MediaType; import com.jd.model.EmpRequest; import com.jd.model.EmpResponse; import com.jd.model.ErrorResponse; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; public class EmpClient { /** * @param args */ public static void main(String[] args) { String uri = 'http://localhost:8080/jd/rest/emp/getEmp'; EmpRequest request = new EmpRequest(); //set id as 1 for OK response request.setId(2); request.setName('PK'); try{ Client client = Client.create(); WebResource r=client.resource(uri); ClientResponse response = r.type(MediaType.APPLICATION_XML).post(ClientResponse.class,request ); System.out.println(response.getStatus()); if(response.getStatus() == 200){ EmpResponse empResponse = response.getEntity(EmpResponse.class); System.out.println(empResponse.getId() + '::'+empResponse.getName()); }else{ ErrorResponse exc = response.getEntity(ErrorResponse.class); System.out.println(exc.getErrorCode()); System.out.println(exc.getErrorId()); } }catch(Exception e){ System.out.println(e.getMessage()); } } }
I hope the tutorial is easy enough to follow and write your first Restful web service using Jersey.
Please let me know if you face any issues or need further explanations.
Reference: Rest using Jersey – Complete Tutorial with JAXB, Exception Handling and Client Program from our JCG partner Pankaj Kumar at the Developer Recipes blog.
HI,
Thank you for this tutorial, can you please post or send me the source code ?
If I want to use Tomcat instead of Jboss, should I just ignore jboss-web.xml ?
thanks, your help is appreciated.