Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java / JavaSE / J2EE

RESTFul Web Service Using Jersey 2.x (Part I)

4.56/5 (7 votes)
27 Nov 2015MPL8 min read 26.4K   246  
In this article, I like to show the reader step by step to create a RESTFul web service using Jersey 2.x.

Introduction

This tutorial is a very simple tutorial that teaches how to setup a Jersey project. This tutorial is very similar to some of the tutorials found online. The key difference between this one and the others is that this tutorial uses the latest Jersey library (version 2.x) rather than the older version (1.x). What you are not aware is that starting from Jersey 2.0 and up, all the classes has been re-organized into new packages. As you can see here, if you look at the existing tutorial, which uses older version of the Jersey libraries, you are going to have a problem when upgrade to the latest version.

If you never worked with Jersey libraries before, here is a chance for you to check out the libraries first hand. Again, just to point out the fact this tutorial uses the latest version of Jersey.

Background

What is Jersey anyways? Jersey is an implementation. An implementation of the JAX-RS specs. You can imagine JAX-RS as an abstraction for a set of functionality that describes how the RESTful service can be implemented and executed in J2EE container. The Jersey framework was done by the same group that was responsible for the Glassfish J2EE container. And it seems that there are quite a lot of companies which use it for production services development. So it is a good idea to know something about it.

Alternative to Jersey framework, there are RestEasy (created by the same group which is responsible for the JBoss/Wildfly J2EE containers) and the Spring MVC 4.x (which supports RESTFul service development). RestEasy is another JAX-RS implementation. Spring MVC 4.x is not. I personally would get some hands on with these two as well just to expand my own horizon. What is about this tutorial? This one just gives readers an idea how to setup a jersey project, compiled, run in a mock container and test.

Step 1 - Create a Maven based web app project

The first step is to create an empty project via Maven. I don't know about others, I mostly uses Maven to build my Java projects. One of my favorite Maven functionality is the capability to create an empty project so that I can add classes/resources later to the project. For this project we need to create an empty web app project. Assuming that you have already installed Apache Maven on your dev machine. This is the command to run to create a blank web application project:

mvn archetype:generate -DgroupId={project-packaging} -DartifactId={project-name} -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

What you need to do with above sample command is replacing the "{project-packaging}" and "{project-name}" with your project base package name and your project name. For example, I would do this:

mvn archetype:generate -DgroupId=org.hanbo.jersey.sample -DartifactId=hanbo-jersey-sample -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

As I run the above commend on my Command Line Prompt, I would see the following output:

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:2.4:generate (default-cli) @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:2.4:generate (default-cli) @ standalone-pom <<<
[INFO]
[INFO] --- maven-archetype-plugin:2.4:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype:
 maven-archetype-webapp:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: org.hanbo.jersey.sample
[INFO] Parameter: packageName, Value: org.hanbo.jersey.sample
[INFO] Parameter: package, Value: org.hanbo.jersey.sample
[INFO] Parameter: artifactId, Value: hanbo-jersey-sample
[INFO] Parameter: basedir, Value: C:\Users\hsun\workspace-ee\jerseysample
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: C:\Users\hsun\workspace-ee\jerseysample\hanbo-jersey-sample
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 18.597s
[INFO] Finished at: Fri Nov 20 14:52:14 CST 2015
[INFO] Final Memory: 10M/24M
[INFO] ------------------------------------------------------------------------

After the output completes, you will see a new folder created in the current folder. And the directory structure would look like this:

hanbo-jersey-sample
|_____src
       |_____main
              |_____resources
	      |_____webapp
	             |_____WEB-INF
	                    |_____web.xml
		     |_____index.jsp
|_____pom.xml

Now we have an empty web application project, it is time for us to add all the components to get an Jersey RESTful application to work.

Step 2 - Modify the POM file

The first thing I would do is to fix my maven project file, the pom.xml. What I typically do is add all the necessary dependencies, add a build step that generate the artifact (if not exist), and add a Jetty plugin that allows me to run the web application via Maven. For this tutorial, the modification is minimal. Here is the POM file after the modification:

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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.hanbo.jersey.sample</groupId>
  <artifactId>hanbo-jersey-sample</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Simple Jersey Sample Application</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>org.glassfish.jersey.core</groupId>
      <artifactId>jersey-server</artifactId>
      <version>2.22.1</version>
    </dependency>
    <dependency>
      <groupId>org.glassfish.jersey.containers</groupId>
      <artifactId>jersey-container-servlet</artifactId>
      <version>2.22.1</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>hanbo-jersey-sample</finalName>
    <plugins>
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>8.1.16.v20140903</version>
      </plugin>
    </plugins>
  </build>
</project>

You won't be able to tell what the modifications are. First, I added the dependencies for Jersey. This is a simple Hello World application, so only two dependencies are needed. Here they are:

XML
<dependency>
   <groupId>org.glassfish.jersey.core</groupId>
   <artifactId>jersey-server</artifactId>
   <version>2.22.1</version>
</dependency>
<dependency>
   <groupId>org.glassfish.jersey.containers</groupId>
   <artifactId>jersey-container-servlet</artifactId>
   <version>2.22.1</version>
</dependency>

Why these two jars are used will be explained later in this article. The next step would be creating the Java class that handles the RESTFul request from users.

Step 3 - Create Jersey based Request Handler

To do this, first the Java source folders must be created. Under the sub folder src/main, create the following folder structure:

src
|____main
      |____java
            |____org
	          |____hanbo
		        |____jersey
			      |____sample

You can either do this via command line, or use a file explorer. The directory hierarchy org/hanbo/jersey/sample would be the package name of the new class. As you might have guessed, under the folder sample, we will put a Java file there. This Java file would be the handler of the RESTFul request. My java file is called "HelloWorldService.java"

The source code of this Java file looks like this:

Java
package org.hanbo.jersey.sample;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;

@Path("/hello")
public class HelloWorldService
{
   @GET
   @Path("/{param}")
   public Response getMsg(@PathParam("param") String msg)
   {
      String output = "Jersey say : " + msg;
      return Response.status(200).entity(output).build();
   }
}

It seems very simple, isn't it? We have a class called HelloWorldServices. Inside there is a method called getMsg. Both have some annotation added to them. The annotation "Path" on the class name is setting the base path of the request. The annotation "Path" on the method name is the sub path of the request. Note that the sub path has the value of "{param}". This means the value of the path is some kind of value that can be received by the method to do work. As you can see in the parameter of the method, there is another annotation "PathParam" which has the same value as the Path annotation. This means whatever the value of "{param}" in the actual request path would be passed into the method as the value of parameter "msg". Don't worry about these detail for now. Once everything is in place, a simple test would better show how this class works.

 

The next step would be to fix the web.xml. Once this is done, we are ready to test.

Step 4 - Fix web.xml the deployment descriptor

We use maven to create a blank web application Java project. It comes with a simple web application deployment descriptor, the web.xml file. This web.xml is located in src/main/webapp/WEB-INF folder. The original content of this file looks like this:

XML
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
</web-app>

All it has is just the display name. It is used as a display name in the container's list of applications. In order to make our Jersey web application work, we need to add a number of new elements. Let me just list out the content:

XML
<web-app id="JerseyHelloWorld" version="2.4"
   xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
   <display-name>hanbo-jersey-sample</display-name>
  
   <servlet>
      <servlet-name>jersey-servlet</servlet-name>
      <servlet-class>
         org.glassfish.jersey.servlet.ServletContainer
      </servlet-class>
      <init-param>
         <param-name>jersey.config.server.provider.packages</param-name>
         <param-value>org.hanbo.jersey.sample</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
      <servlet-name>jersey-servlet</servlet-name>
      <url-pattern>/rest/*</url-pattern>
   </servlet-mapping>
</web-app>

This file might look intimidating. But it is actually quite simple. There are two sections:

  • The first section is the servlet section. A servlet is a Java class that receives the user input and returns a response. In this case we are using a predefined servlet call "org.glassfish.jersey.servlet.ServletContainer". More about this later.
  • The second section is the servlet-mapping, what this section does is to map the servlet name with a particular uri pattern. Basically any request from the root of the servlet when match with this uri pattern, will be routed to the servlet with the name specified here. This will be explain in the testing section, which is next.

Step 5 -- How to test this simple RESTFul web application

In the pom.xml, I added the Jetty plugin so that I can run my Jersey web application with maven. Now, we have everything together. To run it, use the following command:

mvn jetty:run

If all goes well, you will see the following output:

......
[INFO] --- jetty-maven-plugin:8.1.16.v20140903:run (default-cli) @ hanbo-jersey-sample ---
[INFO] Configuring Jetty for project: Simple Jersey Sample Application
[INFO] webAppSourceDirectory not set. Defaulting to C:\Users\hsun\workspace-ee\jerseysample\hanbo-jersey-sample\src\main\webapp
[INFO] Reload Mechanic: automatic
[INFO] Classes = C:\Users\hsun\workspace-ee\jerseysample\hanbo-jersey-sample\target\classes
[INFO] Context path = /
[INFO] Tmp directory = C:\Users\hsun\workspace-ee\jerseysample\hanbo-jersey-sample\target\tmp
[INFO] Web defaults = org/eclipse/jetty/webapp/webdefault.xml
[INFO] Web overrides =  none
[INFO] web.xml file = file:/C:/Users/hsun/workspace-ee/jerseysample/hanbo-jersey-sample/src/main/webapp/WEB-INF/web.xml
[INFO] Webapp directory = C:\Users\hsun\workspace-ee\jerseysample\hanbo-jersey-sample\src\main\webapp
2015-11-25 22:11:11.443:INFO:oejs.Server:jetty-8.1.16.v20140903
2015-11-25 22:11:12.984:INFO:oejpw.PlusConfiguration:No Transaction manager found - if your webapp requires one, please configure one.
2015-11-25 22:11:22.141:WARN:oejsh.RequestLogHandler:!RequestLog
2015-11-25 22:11:22.403:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server

So how do we test this? The url to RESTFul web application is:

http://localhost:8080/rest/hello/{somevalue}

You can replace "{somevalue}" with a string of anything. Then you hit enter, you will see the following output:

Jersey say : {somevalue}

How did I piece the url together to do this test? It took some time for me to figure out:

  • The base url will always be http://localhost:8080, it is a well know fact about J2EE containers.
  • The next part of the url is the application context root. In this sample application, we used Jetty, and never specified a application context root. So we can skip it.
  • Remember I added a servlet mapping and the value is "/rest/*", we need to add this in the url. The url looks like this: http://localhost:8080/rest
  • When we use the above url, it will be routed to our REST request handler class. But which class should it route to? For this sample application, we annotate the class HelloWorldService with Path("hello"), that means if we use url: http://localhost:8080/rest/hello, the request will be passed to our HelloWorldService.
  • In the class, the methhod getMsg has two annotation, the first specify what type of http method it will accept, in this example, the method getMsg will handle any GET request. The second annotation specify another Path. And this path specify the value that can be passed into this method as a parameter. Hence the final url we can try is: http://localhost:8080/rest/hello/{somevalue}. You can replace {somevalue} with a string value of your liking.

That is about it with this tutorial.

Points of Interest

What is the significance of this tutorial? Well, it gives any reader a chance to start out a RESTFul web application project. The reader can further expand this project with additional classes and packages of classes that handles other types of http methods, such as POST, PUT and DELETE operations. The reader can transform the project by adding meaningful request and response classes, and see the request/response handling via either XML/JSON.

In my next tutorial, I will show the readers how to handle POST, PUT and DELETE operations. We will expand the testing from simple browser based testing to PostMan. It will be a lot more fun than this one.

History

  • 11/25/2015 - Initial Draft

License

This article, along with any associated source code and files, is licensed under The Mozilla Public License 1.1 (MPL 1.1)