Home > Software Development > REST API Service Made Easy with Jersey Framework in Java

REST API Service Made Easy with Jersey Framework in Java

August 25th, 2013 Leave a comment Go to comments

Because REST APIs are easy to get started with, I see more products are adopting it for remote management APIs. To implement the REST on the server side, you can use different programming lanaguages and frameworks. In Java, you can use the Jersey framework which is a reference implementation of the JAX-RS (JSR 311 & JSR 339).

As I tried several tutorials, I found them mostly no longer working with latest versions of Jersey and Tomcat 7 which implements Java Servlet 3.0. After getting a sample working finally, I think it’s beneficial to share it so that you can avoid the issues I had gone through.

Time to learn how to "Google" and manage your VMware and clouds in a fast and secure

HTML5 App

Working Sample First

If you use Eclipse, you can create a Dynamic Web project first. Then add the following Java class into the src folder.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package org.doublecloud.rest.demo;
 
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
 
@Path("/hi")
public class HelloWorldService
{
  @GET
  @Path("/{name}")
  public Response getMessage(@PathParam("name") String name)
  {
    String outMsg = "Hello " + name + "!";
    return Response.status(200).entity(outMsg).build();
  }
}

To help the Tomcat to locate your service and hook it up with incoming request from clients, you need to either use web.xml or another class with annotation.

Let’s first look at the annotation approach. You need to create another class as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.doublecloud.rest.demo;
 
import java.util.HashSet;
import java.util.Set;
 
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
 
@ApplicationPath("/rest")
public class HelloApp extends Application
{
  @Override
  public Set<Class<?>> getClasses()
  {
    Set<Class<?>> s = new HashSet<Class<?>>();
    s.add(HelloWorldService.class);
    return s;
  }
}

For the second alternative approach, you create a file called web.xml in the WebContent\WEB-INF folder as the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>REST Web Application Demo</display-name>
	<servlet>
		<servlet-name>jersey-serlvet</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.doublecloud.rest.demo</param-value>
		</init-param>
	</servlet>
 
	<servlet-mapping>
		<servlet-name>jersey-serlvet</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>
</web-app>

Note that the servlet class from previous versions no longer work in Jersey 2.

1
2
3
4
5
6
7
8
    <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>org.doublecloud.rest.demo</param-value>
		</init-param>
	</servlet>

Once you are done with either one of the above two approaches, you can simply type in the following URL in your browser to get a string “hello steve!” back. In real project, you will either use XML or JSON as response body.

http://localhost:8080/RestDemo/rest/hi/steve

Update: Maven Dependencies

I used Maven in NetBeans for a REST project in Feb 2014. Here are the dependencies required by Jersey and JSON using Gson. Depending on your project, you may need more dependencies.

    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-server</artifactId>
            <version>2.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
            <version>2.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
            <version>2.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.2.4</version>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

Trouble Shooting Tips

While working on the sample, I got into several issues which turned out to be dependency issue mostly. As the Jersey project relies on the Maven to manage the dependent jars, it may be easier to go that way. But to simplify the creation process, I just decided to explicitly add required jar files.

Initially, I just downloaded and added the binary jaxrs-ri-2.1.jar file from repository and it did not work. After trying various combination leads to several exceptions as listed below, I finally decided to add all the libraries from the jaxrs-ri\ext\ folder plus javax.ws.rs-api-2.0.jar in the jarxrs-ri\api folder from jaxrs-ri-2.1.zip. With the 16 or so jar files in the WebContent\WEB-INFO\lib folder, things start to work. It’s possible that not all the 16 jar files are necessary, but as it worked I didn’t bother to try them out one by one. The tricky part of trying that out is that checking compilation error is not enough and you have to call the REST service due to the dynamic class loading in the framework.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Caused by: java.lang.ClassNotFoundException: com.google.common.base.Function
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
	... 12 more
 
<== the class com.google.common.base.Function is included in the guava-14.0.1.jar file.
 
SEVERE: Allocate exception for servlet jersey-serlvet
java.lang.ClassNotFoundException: com.sun.jersey.spi.container.servlet.ServletContainer
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
	at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:532)
	at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:514)
	at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:133)
	at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1137)
	at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:858)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:136)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:662)
 
 
	SEVERE: Allocate exception for servlet jersey-serlvet
java.lang.ClassNotFoundException: org.glassfish.hk2.utilities.binding.AbstractBinder
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)

More Tutorial and Samples

The above sample just touched the tip of the iceberg. There are many other features you want to explore. For that, you may find the Jersey 2.1 User Guide and the samples included in the Jersey project very helpful.
More samples at https://github.com/jersey/jersey/tree/master/examples, or http://jersey.java.net/documentation/latest/user-guide.html

  1. Yannick
    September 9th, 2013 at 08:56 | #1

    Hi, thanks for this tutorial ! I’ve been searching for hours and I finally found a simple yet effective example !

    One thing, though : if you’re going to use “http://localhost:8080/RestDemo/rest/hi/steve” as the demo URL, then you should annotate your HelloApp class with @ApplicationPath(“/rest”).

    That way, both configurations are the same. Otherwise, you have to use “http://localhost:8080/RestDemo/hi/steve”.

    Cheers, and thanks again !

  2. September 10th, 2013 at 14:19 | #2

    Hi Yannick,

    I am glad you like this example.

    You are right. The HelloApp should be annotated as you pointed out. I am updating the sample now.

    Thanks a lot for the help!

    Steve

  3. Maxrunner
    October 24th, 2013 at 11:24 | #3

    Hi! This article helped me. so thanks for that. Just want to add a tip too. If you want to use jersey with jackson json, just change this:

    org.doublecloud.rest.demo

    to:

    org.doublecloud.rest.demo;com.fasterxml.jackson.jaxrs.json

    This worked for me and i would at same time find the the resource classes and my JacksonObjectMapper class that implements the ContextResolver.

  4. Gavin
    November 15th, 2013 at 14:11 | #4

    Steve,

    You’re awesome. I appreciate you taking the time to post your example. It really helped me out in trying to figure out RESTful services and the configuration under Jersey 2.0 with NetBeans 7.4.

    Gavin

  5. November 15th, 2013 at 14:25 | #5

    You are very welcome Gavin, I am glad it helped.

    Steve

  6. Kevin
    November 19th, 2013 at 18:41 | #6

    Coming to this post after two days of trying out various tutorials, none working. Followed yours exactly but it does not work either (tried both URLs). Could you please double check what you posted? Thanks.

    HTTP Status 404 – /RestDemo/rest/hi/steve
    type Status report
    message /RestDemo/rest/hi/steve
    description The requested resource (/RestDemo/rest/hi/steve) is not available.

    I’m using Eclipse Kepler, Apache Tomcat/7.0.12, Jersey 2.4.1 (latest)

  7. November 20th, 2013 at 01:32 | #7

    Sorry to hear that. It seems the service is not found. Did you use web.xml or annotation?

    Steve

  8. Maxrunner
    November 26th, 2013 at 07:56 | #8

    Hi Steve! Currently i’m trying to use multi-part resource to receive files with other json data, from Android. I’m yet to understand how to do this on Jersey, but its possible, according to the documentation:
    https://jersey.java.net/documentation/latest/user-guide.html#multipart

    Still how do i activate the Multipart.class thing on the web.xml?I assume i can also activate this on the web.xml file instead of the other alternative.

  9. Maxrunner
    November 26th, 2013 at 13:15 | #9

    Here’s how you set the web.xml with using the application class:

    Jersey REST Service
    org.glassfish.jersey.servlet.ServletContainer

    javax.ws.rs.Application
    com.mobile.rest.MyApplication

    1

    Jersey REST Service
    /rest/*

  10. Rick
    November 26th, 2013 at 16:35 | #10

    Thanks man! All the other tutorials out there were outdated. Replacing with jersey.config.server.provider.packages in the web.xml was critical since all the other examples, as you mention, use com.sun.jersey.config.property.packages

    For those declaring their maven dependencies (which is also confusing when you look at various tutorials)..For Tomcat 6 I used (server not client): (Removed
    groupId>org.glassfish.jersey.containers /groupId>
    artifactId>jersey-container-servlet-core /artifactId>
    version>2.4.1
    /dependency>

  11. Maxrunner
    January 3rd, 2014 at 09:02 | #11

    @Rick
    using maven do you only need to add serveletc-core? what about the extensions?

  12. RAdil
    December 12th, 2014 at 07:10 | #12

    Do you have a maven project that you can share? I am using JDK 1.7

    For some reason Maven does not find PathParam and also the status method used in the here.

    cannot find symbol
    [ERROR] symbol: class PathParam

    cannot find symbol
    [ERROR] symbol: method status(int)
    [ERROR] location: interface javax.xml.ws.Response

    @GET
    @Path(“/{name}”)
    public Response getMessage(@PathParam(“name”) String name)
    {
    String outMsg = “First Jersey Service ” + name + “!”;
    return Response.status(200).entity(outMsg).build();
    }

    My pom file looks like this

    javax.xml.ws
    jaxws-api
    2.2.8

    com.sun.jersey
    jersey-json
    1.1.1-ea

    com.sun.jersey
    jersey-core
    1.1.1-ea

    com.sun.jersey
    jersey-client
    1.1.1-ea

    javax.ws.rs
    jsr311-api
    1.1

    com.google.code.gson
    gson
    2.2.4

    javax
    javaee-web-api
    6.0
    provided

    org.glassfish.jersey.bundles.repackaged
    jersey-guava
    2.6

    maven-compiler-plugin
    3.0

    1.7
    1.7

    maven-war-plugin
    2.2

    ${project.artifactId}

  13. Sachin G N
    July 28th, 2015 at 21:24 | #13

    Working on REST webservice using Jersey implementation. Please help me to resolve this issue.
    Java -1.7
    Maven
    Dynamic Web Module Project Facet – 2.4

    pom.xml:

    maven2-repository.java.net
    Java.net Repository for Maven
    http://download.java.net/maven/2/
    default

    junit
    junit
    4.8.2
    test

    com.sun.jersey
    jersey-server
    1.8

    Stacktrace:
    2015-07-28 19:19:16.809:INFO:oejs.Server:jetty-8.1.16.v20140903
    2015-07-28 19:19:16.984:WARN:oejw.WebAppContext:Failed startup of context o.e.j.w.WebAppContext{null,file:/Users/ctsuser/Documents/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/RESTfulExample/},/Users/ctsuser/Documents/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/RESTfulExample
    java.lang.IllegalStateException: Null contextPath
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:693)
    at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:494)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64)
    at org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:229)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64)
    at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:95)
    at org.eclipse.jetty.server.Server.doStart(Server.java:282)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64)
    at org.eclipse.wst.server.preview.internal.PreviewStarter.run(PreviewStarter.java:72)
    at org.eclipse.wst.server.preview.internal.PreviewStarter.main(PreviewStarter.java:29)
    2015-07-28 19:19:17.407:WARN:oejs.Holder:
    java.lang.ClassNotFoundException: com.sun.jersey.spi.container.servlet.ServletContainer

  14. Sachin G N
    August 7th, 2015 at 17:46 | #14

    Hi All,

    We get this error because of build path issue. You should add “Server Runtime” libraries in Build Path.

    “java.lang.ClassNotFoundException: com.sun.jersey.spi.container.servlet.ServletContainer”

    Please follow below steps to resolve class not found exception.

    Right click on project –> Build Path –> Java Build Path –> Add Library –> Server Runtime –> Apache Tomcat v7.0

    Thanks,
    Sachin G N

  15. Sanchita
    May 3rd, 2016 at 03:44 | #15

    Thanks a lot! my jars were in different folders and Iwas getting class not found exception. After I copied all the jars directly under WEB_INF/lib directly the error was solved

  16. May 14th, 2016 at 01:55 | #16

    Thanks for sharing your thoughts on framework.
    Regards

  1. March 27th, 2017 at 19:02 | #1