Build a RESTful Web service using Jersey and Apache Tomcat

Yi Ming Huang with Dong Fei Wu, Qing Guo
Published on September 24, 2009
 
20

RESTful Web service introduction

Representational State Transfer, or REST, was introduced and defined in 2000 by the doctoral dissertation of Roy Fielding, one of the principal authors of the HTTP specification versions 1.0 and 1.1.

The most important concept in REST is resources, which are identified by global IDs— typically using URIs. Client applications use HTTP methods (GET/ POST/ PUT/ DELETE) to manipulate the resource or collection of resources. A RESTful Web service is a Web service implemented using HTTP and the principles of REST. Typically, a RESTful Web service should define the following aspects:

  • The base/root URI for the Web service such as http://host/<appcontext>/resources.
  • The MIME type of the response data supported, which are JSON/XML/ATOM and so on.
  • The set of operations supported by the service. (for example, POST, GET, PUT or DELETE).

Table 1 illustrates the resource URI and HTTP methods used in typical RESTful Web services.

Table 1. Example of a RESTful Web service
Method / Resource Collection of resources, URI like:
http://host/<appctx>/resources
Member resources, URI like:
http://host/<appctx>/resources/1234
GET List all the members of the collection resources. Retrieve a representation of one resource identified as 1234.
PUT Update (replace) the collection with another one. Update the member resource identified as 1234.
POST Create a member resource in the collection where the ID of it is automatically assigned. Create a sub resource under it.
DELETE Delete the entire collection of resources. Delete the member resource identified as 1234.

JSR 311 (JAX-RS) and Jersey

The proposal for JSR 311 or JAX-RS (The Java API for RESTful Web Services) was started in 2007, and the release of version 1.0 was finalized in October 2008. Currently, JSR 311 version 1.1 is in the draft state. The purpose of this JSR is to provide a set of APIs that can simplify the development of REST-style Web services.

Before the JAX-RS specification there were frameworks like Restlet and RestEasy that could help you implement the RESTful Web services, but they were not intuitive. Jersey is the reference implementation for JAX-RS, and it contains three major parts.

  • Core Server: By providing annotations and APIs standardized in JSR 311, you can develop a RESTful Web service in a very intuitive way.
  • Core Client: The Jersey client API helps you to easily communicate with REST services.
  • Integration: Jersey also provides libraries that can easily integrate with Spring, Guice, Apache Abdera, and so on.

In the following sections of the article, I introduce all of these components, but will focus more on the Core Server.

Build a RESTful Web service

I'll begin with a "hello world" application that can be integrated into Tomcat. This application will get you through setting up the environment and will cover the basics of Jersey and JAX-RS.

Then, I'll introduce a more complicated application to go deeper into the essentials and features of JAX-RS, such as multiple MIME type representations support, JAXB support, and so on. I will excerpt code snippets from the sample to introduce the important concepts.

Hello World: The first Jersey Web project

To set up the development environment you need the following artifacts:

  • IDE: Eclipse IDE for JEE (v3.4+) or IBM Rational Application Developer 7.5
  • Java SE5 or above
  • Web container: Apache Tomcat 6.0 (Jetty and others will also work)
  • Jersey libraries: Jersey 1.0.3 archive, which includes all the necessary libraries

Setting up the environment for Jersey

First, create a server run time for Tomcat 6.0 on Eclipse. This is the Web container for your RESTful Web application. Then create a dynamic Web application named "Jersey," and specify the target run time to be Tomcat 6.0.

Finally, copy the following libraries from the Jersey archive to the lib directory under WEB-INF:

  • Core Server: jersey-core.jar, jersey-server.jar, jsr311-api.jar, asm.jar
  • Core Client: (Used for testing) jersey-client.jar
  • JAXB support: (Used in the advanced example) jaxb-impl.jar, jaxb-api.jar, activation.jar, stax-api.jar, wstx-asl.jar
  • JSON support: (Used in the advanced example) jersey-json.jar

Developing the REST service

Now that you have set up the environment you are ready to develop your first REST service, which simply says "Hello" to the client.

To do this, you need to direct all the REST requests to the Jersey container by defining a servlet dispatcher in the application's web.xml file. (See Listing 1.) Besides declaring the Jersey servlet, it also defines an initialization parameter indicating the Java package that contains the resources.

Listing 1. Define the Jersey servlet dispatcher in the web.xml file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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>sample.hello.resources</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>

Now you will write a resource named HelloResource, which accepts the HTTP GET and responses with the cliché "Hello Jersey."

Listing 2. HelloResource in package sample.hello.resources
1
2
3
4
5
6
7
8
@Path("/hello")
public class HelloResource {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHello() {
        return "Hello Jersey";
    }
}

There are several points in the code that need highlighting:

  • Resource Class: Notice the resource class is a plain old java object (POJO) and is not restricted from implementing any interface. This adds many advantages such as reusability and simplicity.
  • Annotations: They are defined in javax.ws.rs.*, which are part of the JAX-RS (JSR 311) specification.
  • @Path: This defines the resource base URI. Formed with context root and hostname, the resource identifier will be something like http://localhost:8080/Jersey/rest/hello.
  • @GET: This means that the following method responds to the HTTP GET method.
  • @Produces: Defines the response content MIME type as plain/text.

Testing the Hello app

To test the app, open your browser and enter the URL http://<host>:<port>/<appctx>/rest/hello. You will see the response "Hello Jersey." This is quite simple, with annotations taking care of the request, response, and methods.

The following sections will cover the essential parts of the JAX-RS specification and will be introduced using some code snippets from the Contacts example application. You can find all the code for this more advanced sample in the source code package (see Download).

Resources

Resources are the key parts that compose a RESTful Web service. You manipulate resources using HTTP methods like GET, POST, PUT, and DELETE. Anything in the application can be a resource: employees, contacts, organizations, everything. In JAX-RX, resources are implemented by a POJO, with an @Pathannotation to compose its identifier. A resource can also have sub resources. In this case, the parent resource is a resource collection while the sub resources are member resources.

In the sample Contacts application, you will manipulate individual contacts and collections of contacts.ContactsResource is the collection resource with the URI of /contacts, and ContactResource is the member resource with the URI of /contacts/{contactId}. The underlining JavaBean is a simple Contact class with id, name, and address as its member fields. See Listings 3 and 4 for details. You can also download the full source code package at the end of this article (see Download).

Listing 3. ContactsResource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Path("/contacts")
public class ContactsResource {
    @Context
    UriInfo uriInfo;
    @Context
    Request request;
 
    @GET
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public List<Contact> getContacts() {
        List<Contact> contacts = >new ArrayList<Contact>();
        contacts.addAll( ContactStore.getStore().values() );
        return contacts;
    }
 
@Path("{contact}")
    public ContactResource getContact(
            @PathParam("contact") String contact) {
        return new ContactResource(uriInfo, request, contact);
    }
}

There are several interesting things here that you should note.

  • @Context: Use this annotation to inject the contextual objects such as Request, Response, UriInfo, ServletContext, and so on.
  • @Path("{contact}"): This is the @Path annotation combined with the root path "/contacts" that forms the sub resources' URI.
  • @PathParam("contact"): This annotation injects the parameters into the path, contact id in this case, to the method parameter. Other available annotations are @FormParam@QueryParam, and so on.
  • @Produces: Multiple MIME types are supported for responses. In this and the preceding case, application/xml will be the default MIME type.

You may also notice that the GET methods return custom Java objects instead of a String (plain text), as is shown in the previous Hello World example. The JAX-RS specification requires that the implementation support multiple representation types like InputStream, byte[], JAXB elements, collections of JAXB elements, and so on, as well as the ability to serialize them to XML, JSON, or plain text as responses. I will provide more information on representation techniques, and especially on the JAXB element representation, later in this article.

Listing 4. ContactResource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ContactResource {
    @Context
    UriInfo uriInfo;
    @Context
    Request request;
    String contact;
     
    public ContactResource(UriInfo uriInfo, Request request,
            String contact) {
        this.uriInfo = uriInfo;
        this.request = request;
        this.contact = contact;
    }
     
    @GET
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Contact getContact() {
        Contact cont = ContactStore.getStore().get(contact);
        if(cont==null)
            throw new NotFoundException("No such Contact.");
        return cont;
    }
}

The code for ContactResource is straightforward. And, note the following items:

  • Representation Type Contact: Contact is a simple JavaBean annotated by @XmlRootElement, which makes it possible to be represented as XML or JSON.
  • ContactStore: It's a HashMap-based in-memory data store whose implementation is not important for this article.

Method

HTTP methods are mapped to CRUD (create, read, update and delete) actions for a resource. Although you can make slight modifications such as making the PUT method to be create or update, the basic patterns are listed as follows.

  • HTTP GET: Get/List/Retrieve an individual resource or a collection of resources.
  • HTTP POST: Create a new resource or resources.
  • HTTP PUT: Update an existing resource or collection of resources.
  • HTTP DELETE: Delete a resource or collection of resources.

Because I have already introduced the GET method, I will start my descriptions with POST. I will continue using the Contact example as I explain these other methods.

POST

Usually a new contact is created by filling in a form. That is, an HTML form will be POSTed to the server, and the server creates and persists the newly created contact. Listing 5 demonstrates the server-side logic for this.

Listing 5. Accept the form submission (POST) and create a new contact
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@POST
@Produces(MediaType.TEXT_HTML)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void newContact(
        @FormParam("id") String id,
        @FormParam("name") String name,
        @Context HttpServletResponse servletResponse
) throws IOException {
    Contact c = new Contact(id,name,new ArrayList<Address>());
    ContactStore.getStore().put(id, c);
         
    URI uri = uriInfo.getAbsolutePathBuilder().path(id).build();
    Response.created(uri).build();
         
    servletResponse.sendRedirect("../pages/new_contact.html");
}

Note that the following parts make this example work.

  • @Consumes: Declares that the method consumes an HTML FORM.
  • @FormParam: Injects the form input identified by the HTML name attribute to this method.
  • @Response.created(uri).build(): Builds a new URI for the newly created contact as /contacts/{id}and set the response code as 201/created. You can access the new contact using http://localhost:8080/Jersey/rest/contacts/<id>.

PUT

I use the PUT method to update an existing resource. However, this can also be implemented as an update or by creating a resource as shown in the code snippet in Listing 6.

Listing 6. Accept PUT request and create or update a contact
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@PUT
@Consumes(MediaType.APPLICATION_XML)
public Response putContact(JAXBElement<Contact> jaxbContact) {
    Contact c = jaxbContact.getValue();
    return putAndGetResponse(c);
}
 
private Response putAndGetResponse(Contact c) {
    Response res;
    if(ContactStore.getStore().containsKey(c.getId())) {
        res = Response.noContent().build();
    } else {
        res = Response.created(uriInfo.getAbsolutePath()).build();
    }
    ContactStore.getStore().put(c.getId(), c);
    return res;
}

I cover a number of different concepts in this example, highlighting the following concepts.

  • Consume XML: The putContact() method accepts the request content type of APPLICATION/XML, while this input XML will bind to the Contact object using JAXB. You will find the client code in next section.
  • Empty response with different status code: The response of the PUT request will not have any content, but will have a different status code. If the contact exists in the data store, I update this contact and return 204/no content. If there is a new contact, I create it and return 201/created.

DELETE

It's quite simple to implement a DELETE method. Take a look at Listing 7 for an example.

Listing 7. Delete a contact identified by its ID
1
2
3
4
5
6
@DELETE
public void deleteContact() {
    Contact c = ContactStore.getStore().remove(contact);
    if(c==null)
        throw new NotFoundException("No such Contact.");
}

Representation

In the previous sections, I illustrated several representation types. Now I'll briefly go through them and give you a close look at the JAXB representation. Other supported representation types are byte[], InputStream, File, and so on.

  • String: Plain text.
  • Response: A generic HTTP response that can contain your custom content with a different response code.
  • Void: An empty response with a status code of 204/no content.
  • Resource Class: Delegate the process to this resource class.
  • POJO: JavaBeans that are annotated with @XmlRootElement, which makes it a JAXB bean, and which you can bind to XML.
  • Collection of POJOs: A collection of JAXB beans.

JAX-RS supports the use of JAXB (Java API for XML Binding) to bind a JavaBean to XML or JSON and vise versa. The JavaBean must be annotated with @XmlRootElement. Listing 8 takes a Contact bean as an example. The fields without an explicit @XmlElement annotation will have the XML element named the same as themselves. Listing 9 displays the serialized XML and JSON representation for one Contact bean. Representation for a collection of contacts is much the same and has <Contacts> as the wrapper element by default.

Listing 8. Contact bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@XmlRootElement
public class Contact {
    private String id;
    private String name;
    private List<Address> addresses;
     
    public Contact() {}
     
    public Contact(String id, String name, List<Address> addresses) {
        this.id = id;
        this.name = name;
        this.addresses = addresses;
    }
 
    @XmlElement(name="address")
    public List<Address> getAddresses() {
        return addresses;
    }
 
    public void setAddresses(List<Address> addresses) {
        this.addresses = addresses;
    }
    // Omit other getters and setters
}
Listing 9. The representation for one Contact
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<strong>XML representation:</strong>
<contact>
  <address>
    <city>Shanghai</city>
    <street>Long Hua Street</street>
  </address>
  <address>
    <city>Shanghai</city>
    <street>Dong Quan Street</street>
  </address>
  <id>huangyim</id>
    <name>Huang Yi Ming</name>
</contact>
 
 
<strong>JSON representation:</strong>
{"contact":[{"address":[{"city":"Shanghai","street":"Long
            Hua Street"},{"city":"Shanghai","street":"Dong Quan
            Street"}],"id":"huangyim","name":"Huang Yi Ming"}]}

Clients that communicate with REST services

In the example so far, I have developed a RESTful Web service that supports CRUD contacts. Now I'll explain how to communicate with this REST service using curl and Jersey client APIs. In doing so, I'll test the server-side code and give you more information about the client-side technologies.

Use curl to communicate with the REST service

Curl is a popular command-line tool that can send requests to a server using protocols like HTTP and HTTPS. It is a good tool to communicate with RESTful Web services because it can send content by any HTTP method. Curl is already distributed with Linux® and Mac, and there is a utility you can install for Windows.

Now, let's initialize the first curl command that gets all the contacts. You can refer to Listing 3 for the server-side code.

curl http://localhost:8080/Jersey/rest/contacts

The response will be in XML and will contain all the contacts.

Notice the getContacts() method also produces an application/json MIME-type response. You can request content in this type also.

curl –HAccept:application/json http://localhost:8080/Jersey/rest/contacts

The response will be a JSON string that contains all the contacts.

Now I will PUT a new contact. Notice that the putContact() method in Listing 6 accepts XML and uses JAXB to bind the XML to the Contact object.

1
2
curl -X PUT -HContent-type:application/xml --data "<contact><id>foo</id>
                <name>bar</name></contact>" http://localhost:8080/Jersey/rest/contacts/foo

A new contact identified by "foo" is added to the contacts store. You can use URI /contacts or /contacts/foo to verify the contacts collection or individual contact.

Using the Jersey Client to communicate with the REST service

Jersey also provides a client library that helps you to communicate with the server as well as unit test the RESTful services. The library is a generic implementation that can cooperate with any HTTP/HTTPS-based Web service.

The core class for the client is the WebResource class. You use it to build a request URL based on the root URI, and then send requests and get responses. Listing 10 shows how to create a WebResource instance. Notice that WebResource is a heavy object, so you create it once.

Listing 10. Create the WebResource instance
1
2
Client c = Client.<em>create</em>();
WebResource r=c.resource("http://localhost:8080/Jersey/rest/contacts");

The first Jersey client example is to send a GET request to fetch all the contacts and print the response status code and response content. See Listing 11.

Listing 11. GET all contacts and print the response
1
2
3
4
5
ClientResponse response = r.get(ClientResponse.class);
System.out.println( response.getStatus() );
System.out.println( response.getHeaders().get("Content-Type") );
String entity = response.getEntity(String.class);
System.out.println(entity);

Listing 12 shows a second example that creates a new contact identified by "foo".

Listing 12. Create one contact
1
2
3
4
5
6
7
8
9
10
Address[] addrs = {
    new Address("Shanghai", "Ke Yuan Street")
};
Contact c = new Contact("foo", "Foo Bar", Arrays.asList(addrs));
 
ClientResponse response = r
    .path(c.getId())
    .accept(MediaType.APPLICATION_XML)
    .put(ClientResponse.class, c);
System.out.println(response.getStatus());

Notice the APIs for the WebResource instance. It builds the URI, sets the request headers, and invokes the request in one line of code. The content (Contact object) is bound to XML automatically.

Listing 13 shows the last example that retrieves the contact identified by "foo" (which I created in the last example) and then deletes it.

List 13. Retrieve "foo" contact and delete it
1
2
3
4
5
6
7
8
9
10
GenericType<JAXBElement<Contact>> generic = new GenericType<JAXBElement<Contact>>() {};
JAXBElement<Contact> jaxbContact = r
    .path("foo")
    .type(MediaType.APPLICATION_XML)
    .get(generic);
Contact contact = jaxbContact.getValue();
System.out.println(contact.getId() + ": " + contact.getName());
 
ClientResponse response = r.path("foo").delete(ClientResponse.class);
System.out.println(response.getStatus());

Notice here that when you want to get a response that is a JAXB bean, you need to use the generic type feature introduced in Java 2 Platform, Standard Edition (J2SE).

Play with these examples using the Jersey client. You can find more sample code in the source package too (see Download). Also refer to the Jersey website for more information.

Conclusion

Jersey can be integrated with other frameworks or utility libraries using the Jersey integration libraries. Currently, Jersey can integrate with Spring, Guice, and can support ATOM representation with apache-adbera integration. You'll find APIs and guides on getting started on Jersey project home.

 

Downloadable resources

 

Related topics

【转】 Build a RESTful Web service using Jersey and Apache Tomcat 2009的更多相关文章

  1. 使用 Jersey 和 Apache Tomcat 构建 RESTful Web 服务

    作者: Yi Ming Huang, 软件工程师, IBM Dong Fei Wu, 软件工程师, IBM Qing Guo, 软件工程师, IBM 出处: http://www.ibm.com/de ...

  2. 怎样封装RESTful Web Service

    所谓Web Service是一个平台独立的,低耦合的.自包括的.可编程的Web应用程序.有了Web Service异构系统之间就能够通过XML或JSON来交换数据,这样就能够用于开发分布式的互操作的应 ...

  3. 如何封装RESTful Web Service

    所谓Web Service是一个平台独立的,低耦合的,自包含的.可编程的Web应用程序,有了Web Service异构系统之间就可以通过XML或JSON来交换数据,这样就可以用于开发分布式的互操作的应 ...

  4. 用Jersey为Android客户端开发Restful Web Service

    平时在做Android客户端的时候经常要与服务器之间通信,客户端通过服务端提供的接口获取数据,然后再展示在客户端的界面上,作为Android开发者,我们平时更多的是关注客户端的开发,而对服务端开发的关 ...

  5. 使用Java创建RESTful Web Service

    REST是REpresentational State Transfer的缩写(一般中文翻译为表述性状态转移).2000年Roy Fielding博士在他的博士论文“Architectural Sty ...

  6. 使用Java创建RESTful Web Service(转)

    REST是REpresentational State Transfer的缩写(一般中文翻译为表述性状态转移).2000年Roy Fielding博士在他的博士论文“Architectural Sty ...

  7. 使用JAX-RS创建RESTful Web Service

    guice resteasy http://www.cnblogs.com/ydxblog/p/7891224.html http://blog.csdn.net/withiter/article/d ...

  8. 【转】基于CXF Java 搭建Web Service (Restful Web Service与基于SOAP的Web Service混合方案)

    转载:http://www.cnblogs.com/windwithlife/archive/2013/03/03/2942157.html 一,选择一个合适的,Web开发环境: 我选择的是Eclip ...

  9. Building a RESTful Web Service Using Spring Boot In Eclipse

    一.构建restful web service 创建Maven的java web工程,maven的pom文件加入依赖包 创建包hello Greeting.java package hello; pu ...

随机推荐

  1. MATLAB学习笔记(三)——程序设计

    (一)M文件 一.概述 1.自己的体会就是把相应的操作写成一个文本文件,这样子的话方便进行修改(记事本就行了),又可以达到封装的目的,当然我发现2014a版本的Matlab貌似已经采用的面向对象的设计 ...

  2. mvc-4控制器和状态(1)

    导语 将状态保存在客户端可以加快页面反映:但应当避免状态或数据保存在DOM中:在MVC中,状态应该保存在控制器中 控制器是视图和模型的纽带,只有控制器知道视图和模型的存在并将它们连接在一起:当加载页面 ...

  3. 寒假D3 A Find the Lost Sock

    Alice bought a lot of pairs of socks yesterday. But when she went home, she found that she has lost ...

  4. LightOJ1060 nth Permutation(不重复全排列+逆康托展开)

    一年多前遇到差不多的题目http://acm.fafu.edu.cn/problem.php?id=1427. 一开始我还用搜索..后来那时意外找到一个不重复全排列的计算公式:M!/(N1!*N2!* ...

  5. xml文件读写

    创建xml文件,对xml文件进行添加新节点.删除节点.更新节点.创建的如下的xml文件. <?xml version="1.0" encoding="UTF-8&q ...

  6. .NET中的视图和过滤器 (DefaultView和RowFilter)

    NET中的视图和过滤器 (DefaultView和RowFilter) ADO.NET中有一层对象,用来创建任意数据源的抽象模型.其中包括DataSet,DataTable,DataRow,DataV ...

  7. 洛谷 P1008 三连击 Label:水

    题目描述 将1,2,…,9共9个数分成三组,分别组成三个三位数,且使这三个三位数构成1:2:3的比例,试求出所有满足条件的三个三位数. 输入输出格式 输入格式: 木有输入 输出格式: 若干行,每行3个 ...

  8. weblogic sockets 和 thread 问题解决

    原创文章,转载须注明出处. 这个问题网上很多答案,可惜没一个能解决.后来发现是weblogic 必须适配JDK 版本. 一般会报这个错误,There are: 5 active sockets, bu ...

  9. easyui datagrid分页要点总结

    easyui的datagird插件比较好用,也很方便.网上也有很多热的网友贴出了使用代码,但是很少有网友指出在使用过程应该注意的地方,让我实在搞不清分页应该怎么使用.我就说下使用分页功能中要注意的一个 ...

  10. YII 查找View的5种方式

    别名开头,路径指定view文件@app/views/site/about.php //开头,使用 app目录下面的views//site/about.php /开头,使用当前Module中的views ...