1. Introduction

JAX-RS (Java API for RESTful Web Services) is a set of Java API that provides support in creating REST APIs. And the framework makes good use of annotations to simplify the development and deployment of these APIs.

In this tutorial, we’ll use RESTEasy, the JBoss provided portable implementation of JAX-RS specification, in order to create a simple RESTful Web services.

2. Project Setup

We are going two consider two possible scenarios:

  • Standalone Setup – intended for working on every application server
  • JBoss AS Setup – to consider only for deployment in JBoss AS

2.1. Standalone Setup

Let’s start by using JBoss WildFly 10 with standalone setup.

JBoss WildFly 10 comes with RESTEasy version 3.0.11, but as you’ll see, we’ll configure the pom.xml with the new 3.0.14 version.

And thanks to the resteasy-servlet-initializer, RESTEasy provides integration with standalone Servlet 3.0 containers via the ServletContainerInitializer integration interface.

Let’s have a look at the pom.xml:

<properties>
    <resteasy.version>3.0.14.Final</resteasy.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-servlet-initializer</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-client</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
</dependencies>

jboss-deployment-structure.xml

Within JBoss everything that is deployed as WAR, JAR or EAR is a module. These modules are referred to as dynamic modules.

Beside these, there are also some static modules in $JBOSS_HOME/modules. As JBoss has the RESTEasy static modules – for standalone deployment, the jboss-deployment-structure.xml is mandatory in order to exclude some of them.

In this way, all classes and JAR files contained in our WAR will be loaded:

<jboss-deployment-structure>
    <deployment>
        <exclude-subsystems>
            <subsystem name="resteasy" />
        </exclude-subsystems>
        <exclusions>
            <module name="javaee.api" />
            <module name="javax.ws.rs.api"/>
            <module name="org.jboss.resteasy.resteasy-jaxrs" />
        </exclusions>
        <local-last value="true" />
    </deployment>
</jboss-deployment-structure>

2.2. JBoss as Setup

If you are going to run RESTEasy with JBoss version 6 or higher you can choose to adopt the libraries already bundled in the application server, thus simplifying the pom:

<dependencies>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
<dependencies>

Notice that jboss-deployment-structure.xml is no longer needed.

3. Server Side Code

3.1. Servlet Version 3 web.xml

Let’s now have a quick look at the web.xml of our simple project here:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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_3_0.xsd">

   <display-name>RestEasy Example</display-name>

   <context-param>
      <param-name>resteasy.servlet.mapping.prefix</param-name>
      <param-value>/rest</param-value>
   </context-param>

</web-app>

resteasy.servlet.mapping.prefix is needed only if you want prepend a relative path to the API application.

At this point, it’s very important to notice that we haven’t declared any Servlet in the web.xml because resteasy servlet-initializer has been added as dependency in pom.xml. The reason for that is – RESTEasy provides org.jboss.resteasy.plugins.servlet.ResteasyServletInitializer class that implements javax.server.ServletContainerInitializer.

ServletContainerInitializer is an initializer and it’s executed before any servlet context will be ready – you can use this initializer to define servlets, filters or listeners for your app.

3.2. The Application Class

The javax.ws.rs.core.Application class is a standard JAX-RS class that you may implement to provide information on your deployment:

@ApplicationPath("/rest")
public class RestEasyServices extends Application {

    private Set<Object> singletons = new HashSet<Object>();

    public RestEasyServices() {
        singletons.add(new MovieCrudService());
    }

    @Override
    public Set<Object> getSingletons() {
        return singletons;
    }
}

As you can see – this is simply a class the lists all JAX-RS root resources and providers, and it is annotated with the @ApplicationPath annotation.

If you return any empty set for by classes and singletons, the WAR will be scanned for JAX-RS annotation resource and provider classes.

3.3. A Services Implementation Class

Finally, let’s see an actual API definition here:

@Path("/movies")
public class MovieCrudService {

    private Map<String, Movie> inventory = new HashMap<String, Movie>();

    @GET
    @Path("/getinfo")
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Movie movieByImdbId(@QueryParam("imdbId") String imdbId) {
        if (inventory.containsKey(imdbId)) {
            return inventory.get(imdbId);
        } else {
            return null;
        }
    }

    @POST
    @Path("/addmovie")
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Response addMovie(Movie movie) {
        if (null != inventory.get(movie.getImdbId())) {
            return Response
              .status(Response.Status.NOT_MODIFIED)
              .entity("Movie is Already in the database.").build();
        }

        inventory.put(movie.getImdbId(), movie);
        return Response.status(Response.Status.CREATED).build();
    }
}

4. Conclusions

In this quick tutorial we introduced RESTEasy and we built a super simple API with it.

The example used in this article is available as a sample project in GitHub.


» 下一篇: Java Web周报112