Thursday 8 March 2012

How to create a web service using Jersey, Maven and Tomcat

This post will describe how to create a "HelloWorld" web service using Jersey, Tomcat and Maven.  The finished project can be downloaded from GitHub at https://github.com/Naptimecoder/hello.git.

Technologies used

The following technologies were used.
  • Tomcat (version 7.0.26 was used with this project)
  • Maven (version 3.0.3 was used with this project)
  • An IDE of your choice - I'm using IntelliJ ( community edition)
  • Jersey - but we will get it using Maven.

Create the maven project

Create a new maven web-app archetype project either through your IDE (if it supports Maven integration) or via the command line.  If you are using the command line, the command will be:

mvn archetype:generate -DgroupId=foo.bar -DartifactId=hello -DarchetypeArtifactId=maven-archetype-webapp

After creating the project you should see a directory structure like the following:



Add the Jersey dependencies

Next modify the pom.xml file to include the jersey dependencies.

Note: In the latest release of jersey the com.sun.jersey.spi.container.servlet.ServletContainer class has been moved, so the jersey-servlet dependency is now required.  If you do not include the dependency you will get a nasty "java.lang.ClassNotFoundException: com.sun.jersey.spi.container.servlet.ServletContainer" error in your tomcat log file.

The decencies section of the pom.xml file should look like this:
<dependencies>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.12</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-servlet</artifactId>
            <version>1.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


Create the web-service

Next create the java web-service class.  This is known as the "Root Resource Class" and is a POJO that is annotated with a @Path or has a method annotated with the @Path or a request type (i.e. @GET).

Here is the HelloWorld class I created:


package foo.bar;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/world")
public class HelloWorld {

    @GET
    @Produces(MediaType.TEXT_HTML)
    public String sayHtmlHello() {
        return "Hello!Hello, hello! ";
    }
}

The "Path" annotation indicates the URI this class will be available at relative to your base URL. For example, if this web-app is launched at localhost using a context of "hello" and no URL pattern is defined in the web.xml servlet mapping section, then the web service will be available at http://localhost:8080/hello/world.

The "GET" annotation indicates this method will respond to HTTP Get requests.

The "Produces" annotation indicates the MIME response the method will return.

Setup the web.xml file


Next, the web.xml file needs to be setup. Here is mine:

<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" >
     <servlet >
         <servlet-name >HelloWorld Jersey 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 >foo.bar </param-value >
         </init-param >
         <load-on-startup >1 </load-on-startup >
     </servlet >
     <servlet-mapping >
         <servlet-name >HelloWorld Jersey Service </servlet-name >
         <url-pattern >/* </url-pattern >
     </servlet-mapping >
 </web-app >

The web.xml file does the following:
  •  The init-param tells the jersey ServletContainer to look for our Root Resource Class (i.e. our HelloWorld class) in the foo.bar package. There are other ways to register this; see the jersey documentation for more details
  • Loads the ServletContainer at startup.  A value of 1 indicates the ServletContainer is a high priority servlet to load
  • The url-pattern can be used to define your URL. For example, running local host with a context of "hello" and path annotation of "world" on the HelloWorld class:


Build the project

If you use maven from the command line then use the following to build the project:

mvn package

Otherwise, use your IDE to do the maven package phase. Either way, the result should be a hello.war file created in the target directory.

Deploy to Tomcat

There are several ways to deploy the hello.war file to Tomcat. See the Tomcat Documentation for the option best for you.

For myself, I just dropped the hello.war file into the CATALINA_HOME/webapps  directory and started tomcat up.

View the web service

Point a browser to http://localhost:8080/hello/world and you should see the output of "Hello, hello!"

References

Help documents and tutorials for jersey:
http://docs.oracle.com/cd/E19776-01/820-4867/index.html
http://jersey.java.net/nonav/documentation/latest/user-guide.html
http://www.vogella.de/articles/REST/article.html

Overview of what a Restful web service is:
http://www.ibm.com/developerworks/webservices/library/ws-restful/

Technologies used:
http://jersey.java.net/
http://maven.apache.org/
http://tomcat.apache.org/

5 comments:

  1. Appreciate this info. Made my life easier.

    ReplyDelete
  2. I must have missed something someplace because when I try to create the war it fails. Any ideas?

    mvn package
    [INFO] Scanning for projects...
    [ERROR] The build could not read 1 project -> [Help 1]
    [ERROR]
    [ERROR] The project foo.bar:hello:1.0-SNAPSHOT (/Users/eddie/Documents/workspace/hello/pom.xml) has 3 errors
    [ERROR] Malformed POM /Users/eddie/Documents/workspace/hello/pom.xml: Unrecognised tag: 'groupid' (position: START_TAG seen ...\n ... @12:22) @ /Users/eddie/Documents/workspace/hello/pom.xml, line 12, column 22 -> [Help 2]
    [ERROR] 'dependencies.dependency.artifactId' for null:null:jar is missing. @ line 21, column 21
    [ERROR] 'dependencies.dependency.groupId' for null:null:jar is missing. @ line 21, column 21
    [ERROR]
    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
    [ERROR] Re-run Maven using the -X switch to enable full debug logging.
    [ERROR]
    [ERROR] For more information about the errors and possible solutions, please read the following articles:
    [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/ProjectBuildingException
    [ERROR] [Help 2] http://cwiki.apache.org/confluence/display/MAVEN/ModelParseException

    ReplyDelete
  3. Sorry, got it. I am running on a Mac and it is case sensitive.

    ReplyDelete
  4. groupid needs to be groupId
    artifactid needs to be artifactId

    (see upper case versus lower case i)

    ReplyDelete
    Replies
    1. Ah yes, good catch. I've updated the post. The code checked into github did have correct case. Thanks.

      Delete