Ilias Tsagklis

About Ilias Tsagklis

Ilias Tsagklis is a senior software engineer working in the telecom domain. He is an applications developer in a wide variety of applications/services. Ilias is co-founder and Executive Editor at Java Code Geeks.

RESTful Web Services with RESTeasy JAX-RS on Tomcat 7 – Eclipse and Maven project

The RESTful approach of developing web services is constantly gaining more and more attention and seems to be pushing SOAP into deprecation. I am not going to discuss which approach is better, but I believe that we all agree that REST is much more lightweight. In this tutorial, I am going to show you how to develop RESTful services with RESTeasy and how to deploy them on a Tomcat server. An Eclipse based Maven project is also created along the way.

I recently wanted to test a REST client that I planned to use into an application I am building, so I needed a quick way to set up a RESTful infrastructure. Justin has written a cool guide on how to use Spring for providing RESTful services. However, I wanted something faster and not to mess with Spring for once. For that reason, I decided to go with JBoss RESTeasy. From the official site:

RESTEasy is a JBoss project that provides various frameworks to help you build RESTful Web Services and RESTful Java applications. It is a fully certified and portable implementation of the JAX-RS specification. JAX-RS is a new JCP specification that provides a Java API for RESTful Web Services over the HTTP protocol.
RESTEasy can run in any Servlet container, but tighter integration with the JBoss Application Server is also available to make the user experience nicer in that environment.

The latest RESTeasy version can be found here and the relevant documentation here. At the time being, the latest version is the 2.1.0.GA. You will also probably need the RESTeasy JavaDoc and the JAX-RS JavaDoc.

Since using JBoss AS would cancel the whole “lightweight” concept, I decided to go with our old friend Tomcat. I downloaded the latest version (7.0.5 beta) of the beloved servlet container from here. Note that at the time being this is in beta phase, but Tomcat has been proven very robust and I think no problems should occur.

Let’s start by creating an Eclipse based Maven project under the name “RESTeasyProject”. The archetype used is “webapp-jee5” as shown in the following image:

For the parameters, we use “com.javacodegeeks” as group Id and “resteasy” as artifact Id.

The next step is to add the RESTeasy dependencies in our pom.xml file. The repository URL is http://repository.jboss.org/maven2/ but unfortunately the latest version provided in that repository is 2.0-beta-2. Anyway, the lines that we need to add to the maven file are:

…
<repositories>
 <repository>
       <id>org.jboss.resteasy</id>
  <url>http://repository.jboss.org/maven2/</url>
 </repository>
</repositories>
…
<dependencies>
…
<dependency>
 <groupId>org.jboss.resteasy</groupId>
 <artifactId>resteasy-jaxrs</artifactId>
 <version>2.0-beta-2</version>
</dependency>
<dependency>
 <groupId>org.jboss.resteasy</groupId>
 <artifactId>resteasy-jaxb-provider</artifactId>
 <version>2.0-beta-2</version>
</dependency>
<dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-jettison-provider</artifactId>
      <version>2.0-beta-2</version>
</dependency>
…
</dependencies>
…

The resteasy-jaxrs artifact refers to the core RESTeasy class for the JAX-RS implementation. Additionally, we use both resteasy-jaxb-provider and resteasy-jettison-provider, since we want to support both XML and JSON response formats. The JAXB architecture is used for the XML serializations and the Jettison framework for writing JSON.

Here is the full pom.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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.javacodegeeks</groupId>
  <artifactId>resteasy</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>

  <name>resteasy JEE5 Webapp</name>
  <url>http://maven.apache.org</url>
  
  <repositories>
    <repository>
      <id>org.jboss.resteasy</id>
      <url>http://repository.jboss.org/maven2/</url>
    </repository>
    </repositories>

  <dependencies>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>2.0-beta-2</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxb-provider</artifactId>
        <version>2.0-beta-2</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jettison-provider</artifactId>
        <version>2.0-beta-2</version>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
    <finalName>resteasy</finalName>
  </build>
</project>

Let’s first see the model class that will be used in our service:

package com.javacodegeeks.resteasy.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "employee")
public class Employee {
    
    private String employeeId;
    private String employeeName;
    private String job;
    
    @XmlElement
    public String getEmployeeId() {
        return employeeId;
    }
    
    public void setEmployeeId(String employeeId) {
        this.employeeId = employeeId;
    }
    
    @XmlElement
    public String getEmployeeName() {
        return employeeName;
    }
    
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
    
    @XmlElement
    public String getJob() {
        return job;
    }
    
    public void setJob(String job) {
        this.job = job;
    }
    
}

Typical model class with some fields and the respective getters/setters. The JAXB annotations are used in order to indicate which fields will be serialized and to what elements they will be mapped to. Mores specifically, the XmlRootElement annotation is used in order to indicate a top-level class element. Similarly, the getters are annotated with XmlElement in order to map the respective JavaBean property to a XML element. By default the property name is used, but we can override that by providing a custom name.

Let’s create now our first RESTeasy enabled class, named “SampleService”.

package com.javacodegeeks.resteasy;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

import com.javacodegeeks.resteasy.model.Employee;

@Path("/sampleservice")
public class SampleService {
    
    private static Map<String, Employee> employees = new HashMap<String, Employee>();
    
    static {
        
        Employee employee1 = new Employee();
        employee1.setEmployeeId("1");
        employee1.setEmployeeName("Fabrizio");
        employee1.setJob("Software Engineer");
        employees.put(employee1.getEmployeeId(), employee1);
        
        Employee employee2 = new Employee();
        employee2.setEmployeeId("2");
        employee2.setEmployeeName("Justin");
        employee2.setJob("Business Analyst");
        employees.put(employee2.getEmployeeId(), employee2);
        
    }

    @GET
    @Path("/hello")
    @Produces("text/plain")
    public String hello(){
        return "Hello World";    
    }
    
    @GET
    @Path("/echo/{message}")
    @Produces("text/plain")
    public String echo(@PathParam("message")String message){
        return message;    
    }
    
    @GET
    @Path("/employees")
    @Produces("application/xml")
    public List<Employee> listEmployees(){
        return new ArrayList<Employee>(employees.values());
    }
    
    @GET
    @Path("/employee/{employeeid}")
    @Produces("application/xml")
    public Employee getEmployee(@PathParam("employeeid")String employeeId){
        return employees.get(employeeId);        
    }
    
    @GET
    @Path("/json/employees/")
    @Produces("application/json")
    public List<Employee> listEmployeesJSON(){
        return new ArrayList<Employee>(employees.values());
    }

    @GET
    @Path("/json/employee/{employeeid}")
    @Produces("application/json")
    public Employee getEmployeeJSON(@PathParam("employeeid")String employeeId){
        return employees.get(employeeId);        
    }
    
}

As you can see, our service is heavily annotated. We can define declaratively the HTTP method that each method responds to, for example GET or POST. For the URL under which resources are served, we use PATH, both in service and method level. If a method accepts a parameter or falls under a specific path segment, that is denoted by PathParam. Finally, the Consumes annotation defines the media types that the methods of a resource can accept and Produces defines the types that can be produced.

Let’s examine some more details. We store some mock data on a static map, which on a real application would be replaced by a DAO. Note that the model classes will be serialized by the library both for XML and JSON representations. Let’s see now the exposed methods:

  • hello: A method that simply prints a predefined string with text/plain content type.
  • echo: This methods returns whatever argument is provided. Note that the field name inside the brackets must match the parameter name. Similar content type with above.
  • listEmployees: This methods provides an XML representation of a list of model objects. The format is indicated by the Produces annotation.
  • getEmployee: Same with previous but returns only one model object based on the ID argument.
  • listEmployeesJSON: Similar to the XML counterpart, but the produced format is JSON.
  • getEmployeeJSON: Same with previous but returns only one model object based on the ID argument.

Next we have to setup our web apps’ web.xml file accordingly so that RESTeasy takes care of the incoming REST requests. In our Maven project, this can be found under the “src/main/webapp/WEB-INF” directory. Here what our declaration file looks like:

<?xml version="1.0" encoding="UTF-8"?>

<web-app 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>resteasy</display-name>

    <listener>
        <listener-class>
            org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>Resteasy</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Resteasy</servlet-name>
        <url-pattern>/restful-services/*</url-pattern>
    </servlet-mapping>
    
    <context-param>
         <param-name>resteasy.scan</param-name>
        <param-value>true</param-value>    
    </context-param>

    
    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/restful-services</param-value>
    </context-param>
    
</web-app>

The ResteasyBootstrap context listener has to be deployed in order to create the registry for resteasy ,while the HttpServletDispatcher servlet is used so that incoming requests are correctly routed to the appropriate services. We have configured the specific servlet, named “Resteasy”, to intercept requests under the “/restful-services/*” path. We need to define that to the RESTeasy framework by using the resteasy.servlet.mapping.prefix configuration option. Note that the value does not containing the trailing slash nor the wildcard. Finally, we use the resteasy.scan switch to automatically scan WEB-INF/lib jars and WEB-INF/classes directory for the various annotated classes. There are also a number of other RESTeasy configuration switches you can use in order to fine tune your application’s behavior.

The final step is to build the project and deploy to the servler container. Run the Eclipse configuration and choose “Maven install”. Assuming everything is fine, this will generate a web archive named “resteasy.war” under the “target” folder of your project. The exploded folder can also be found in the same directory. Copy the WAR file to Tomcat’s application repository, i.e. the “apache-tomcat-7.0.5\webapps” folder. Start the server if you do not have already done so and you should see the following line at the console:

Adding scanned resource: com.javacodegeeks.resteasy.SampleService

Now that the application is deployed, let’s test it. Note that, since all methods handle GET requests, testing can be performed by using your favorite browser and just writing the URL. For the lazy developer, here they are (in the XML and JSON cases I also add a public link with the expected result):

http://localhost:8080/resteasy/restful-services/sampleservice/hello

http://localhost:8080/resteasy/restful-services/sampleservice/echo/message

http://localhost:8080/resteasy/restful-services/sampleservice/employees
(link)

http://localhost:8080/resteasy/restful-services/sampleservice/employee/1
(link)

http://localhost:8080/resteasy/restful-services/sampleservice/json/employees
(link)

http://localhost:8080/resteasy/restful-services/sampleservice/json/employee/1
(link)

Note that the full path consists of the web application context (“resteasy”), the context we defined RESTeasy to handle (“restful-services”), the service path (“sampleservice”) and finally the corresponding method path.

That would be all. As always, you can find the Eclipse project here.

Related Articles :

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

11 Responses to "RESTful Web Services with RESTeasy JAX-RS on Tomcat 7 – Eclipse and Maven project"

  1. andrew d says:

    can you make an oauth 2 legged tutorial

  2. lilyju says:

    This sample is the best

  3. Tomcat 7 runs the Java EE web-profile so JAX-RS should be build right in. 

  4. Marco Antonio says:

    Nice work. Thanks for the RESTEasy sample, I have successfully deployed in Tomcat 7 with eclipse. As I am working in a project that uses RESIN, I tried to deploy it under Resin, I got the following error when going to the urls:

    404 Could not find resource for relative : /RESTfulExample/restful-services/sampleservice/hello of full path: http://localhost:8080/RESTfulExample/restful-services/sampleservice/hello/

    If anyone has some clue on this or can helpo me to fix the issue, it would be greatly apreciated.

  5. Marco Antonio says:

    Yes you can, I just deployed the example in Tomcat7 and eclipse.

  6. Fred says:

    Hi My maven install is failing with followinf error:
    Downloading: http://repository.jboss.org/maven2/org/scannotation/scannotation/1.0.2/scannotation-1.0.2.pom
    [INFO] ————————————————————————
    [INFO] BUILD FAILURE
    [INFO] ————————————————————————
    [INFO] Total time: 3.036s
    [INFO] Finished at: Fri Aug 09 15:19:08 CST 2013
    [INFO] Final Memory: 4M/15M
    [INFO] ————————————————————————
    [ERROR] Failed to execute goal on project resteasy: Could not resolve dependencies for project com.javacodegeeks:resteasy:war:0.0.1-SNAPSHOT: Failed to collect dependencies for [javax.servlet:servlet-api:jar:2.5 (provided), javax.servlet.jsp:jsp-api:jar:2.1 (provided), junit:junit:jar:3.8.1 (test), org.jboss.resteasy:resteasy-jaxrs:jar:2.0-beta-2 (compile), org.jboss.resteasy:resteasy-jaxb-provider:jar:2.0-beta-2 (compile), org.jboss.resteasy:resteasy-jettison-provider:jar:2.0-beta-2 (compile)]: Failed to read artifact descriptor for org.scannotation:scannotation:jar:1.0.2: Could not transfer artifact org.scannotation:scannotation:pom:1.0.2 from/to org.jboss.resteasy (http://repository.jboss.org/maven2/): Access denied to http://repository.jboss.org/maven2/org/scannotation/scannotation/1.0.2/scannotation-1.0.2.pom. Error code 403, Forbidden -> [Help 1]

  7. Majid says:

    Hi,
    Thank you for this tutorial,
    I imported it in eclipse, but I got this error :

    Description Resource Path Location Type
    The container ‘Maven Dependencies’ references non existing library ‘/Users/majid/.m2/repository/org/jboss/resteasy/resteasy-jaxrs/2.0-beta-2/resteasy-jaxrs-2.0-beta-2.jar’ resteasy Build path Build Path Problem

    Thanks, your help is appreciated.

  8. amir says:

    Hello

    My war file (resteasy.war) contains class files, lib and web.xml. I am trying to deploy the war on Apache Tomcat 7. But I get this error during deploying the war file:
    Error listenerStart.

    Thank you for any help.

  9. Thai Students from SIIT Thammasat University says:

    Thank you so much

Leave a Reply


four × = 16



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close