Jersey JAX-RS Restful CRUD Web Services Example

In this article, we will learn step by step how to develop CRUD RESTFul APIs using the Jersey JAX-RS framework.

In this article, we have used the Jersey version 2.27 with JDK 8. Deployment of a JAX-RS application using @ApplicationPath with Servlet 3.0 ( use @ApplicationPath("resources")annotation to configure Jersey Servlet Container).

Technology and tools used:

  • Maven 3
  • JDK 8
  • Jersey 2.27
  • Apache Tomcat 8.5
  • Eclipse Neon

1. Create a Maven Web Application Project

You can create a quick start Java web application project by using the Maven maven-archetype-webapp template. In a terminal (*Unix or Mac) or command prompt (Windows), navigate to the folder you want to create the project.
Type this command :
$ mvn archetype:generate -DgroupId={project-packaging} 
 -DartifactId={project-name} 
 -DarchetypeArtifactId=maven-archetype-webapp 
 -DinteractiveMode=false

//for example 
$ mvn archetype:generate -DgroupId=com.ramesh
 -DartifactId=Jersey-crud-example
 -DarchetypeArtifactId=maven-archetype-webapp 
 -DinteractiveMode=false
Or You can use Guide to Create a Simple Maven Web Application
guide to creating a maven web project in eclipse.

2. Project Packaging Structure

In a typical Jersey application, the project packaging structure may look:

── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── javadevelopersguide
    │   │           └── jersey
    │   │               ├── model
    │   │               │   └── User.java
    │   │               ├── service
    │   │               │   ├── UserService.java
    │   │               │   └── impl
    │   │               │       └── UserServiceImpl.java
    │   │               └── resources
    │   │               |    └── UserResource.java
    │   │               └── client
    │   │                     └── UserResourceClient.java
    │   ├── resources
            └── logback.xml
    │   └── webapp
    │       ├── WEB-INF
    │       │   ├── classes
    │       │   └── web.xml
    │       ├── images
    │       └── styles
    └── test
        ├── java
        │   └── com
        │       └── javadevelopersguide
        │           └── jersey
        │               └── resources
        │                   └── UserResourceTest.java
        └── resources
            └── logback-test.xml

3. Update Jersey Dependencies in a Pom.Xml File

<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/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.javadevelopersguide.jersey</groupId>
 <artifactId>jersey-crud-example</artifactId>
 <packaging>war</packaging>
 <version>0.0.1-SNAPSHOT</version>
 <name>jersey-crud-example Maven Webapp</name>
 <url>http://maven.apache.org</url>

 <dependencies>
     <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
     <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <scope>provided</scope>
     </dependency>

     <dependency>
          <groupId>org.glassfish.jersey.core</groupId>
          <artifactId>jersey-server</artifactId>
          <version>${jersey.version}</version>
     </dependency>
     <dependency>
          <groupId>org.glassfish.jersey.containers</groupId>
          <artifactId>jersey-container-servlet</artifactId>
          <version>${jersey.version}</version>
     </dependency>

     <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-moxy -->
     <dependency>
          <groupId>org.glassfish.jersey.media</groupId>
          <artifactId>jersey-media-moxy</artifactId>
          <version>${jersey.version}</version>
     </dependency>

     <dependency>
          <groupId>org.glassfish.jersey.inject</groupId>
          <artifactId>jersey-hk2</artifactId>
          <version>${jersey.version}</version>
     </dependency>

      <!-- Required only when you are using JAX-RS Client -->
     <dependency>
          <groupId>org.glassfish.jersey.core</groupId>
          <artifactId>jersey-client</artifactId>
          <version>${jersey.version}</version>
     </dependency>
 </dependencies>

 <build>
     <finalName>jersey-crud-example</finalName>
         <plugins>
             <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-war-plugin</artifactId>
                  <configuration>
                      <failOnMissingWebXml>false</failOnMissingWebXml>
                  </configuration>
            </plugin>
            <plugin>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>2.0.2</version>
                 <configuration>
                     <source>1.8</source>
                     <target>1.8</target>
                 </configuration>
            </plugin>
            <plugin>
                 <groupId>org.apache.tomcat.maven</groupId>
                 <artifactId>tomcat7-maven-plugin</artifactId>
                 <version>2.2</version>
            </plugin>
        </plugins>
 </build>

 <properties>
      <jersey.version>2.26</jersey.version>
 </properties>

</project>

4. Data Model - User

Let's create a User class, which is a data model for this RESTful CRUD services. 
I have used jersey-moxy- json support for JSON binding feature from jersey-media-moxy.
package com.javadevelopersguide.jersey.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User {
     private long id;
     private String name;
     private String email;
 
     public User() {
  
     }
 
 
     public User(long id, String name, String email) {
         super();
         this.id = id;
         this.name = name;
         this.email = email;
     }
     public long getId() {
         return id;
     }
     public void setId(long id) {
         this.id = id;
     }
     public String getName() {
         return name;
     }
     public void setName(String name) {
         this.name = name;
     }
     public String getEmail() {
         return email;
     }
     public void setEmail(String email) {
         this.email = email;
     }
}

5. Create a Resource class - UserResource.java

Let's create a resource class named UserResource class with following RESTFul APIs:
- Create User
- Get All User
- Update User
- Delete User
- Get User By Id
package com.javadevelopersguide.jersey.resources;

import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import com.javadevelopersguide.jersey.model.User;
import com.javadevelopersguide.jersey.services.UserService;

@Path("/users")
public class UserResource {

    private UserService userService = new UserService();

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<User> fetchAll() {
        return userService.fetchAll();
    }

    @GET
    @Path("user/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response get(@PathParam("id") int id) {
        return Response.ok().entity(new User(100, "me", "[email protected]")).build();
    }
 
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response create(User user) {
        // create notification
        userService.create(user);
        return Response.status(Status.CREATED).build();
    }
 
    @PUT
    @Path("/user/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response update(@PathParam("id") long id, User user) {
        userService.update(user);
        return Response.noContent().build();
    }

    @DELETE
    @Path("/user/{id}")
    public Response delete(@PathParam("id") long id) {
        userService.delete(id);
        return Response.status(202).entity("User deleted successfully !!").build();
    }
}

6. Descriptor-Less Deployment Configuration

Here are multiple deployment options in the Servlet 3.0 container for a JAX-RS application defined by implementing a custom Application subclass. For simple deployments, no web.xml is necessary at all. 

Instead, an @ApplicationPath annotation can be used to annotate the custom Application subclass and define the base application URI for all JAX-RS resources configured in the application:
import javax.ws.rs.ApplicationPath;

// Deployment of a JAX-RS application using @ApplicationPath with Servlet 3.0
// Descriptor-less deployment
import org.glassfish.jersey.server.ResourceConfig;

@ApplicationPath("/api")
public class JerseyServletContainerConfig extends ResourceConfig {
    public JerseyServletContainerConfig() {
        packages("com.javadevelopersguide.jersey.resources");
    }
}

7. Create Sample UserService class

Let's create a UserService class to serve in-memory objects to UserResource class.
package com.javadevelopersguide.jersey.services;

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.NotFoundException;

import com.javadevelopersguide.jersey.model.User;

public class UserService {

    private List<User> users = new ArrayList<User>();

    public List<User> fetchAll() {

        users.add(new User(100, "A", "[email protected]"));
        users.add(new User(101, "B", "[email protected]"));
        users.add(new User(102, "C", "[email protected]"));
        return users;
    }

    public User fetchBy(long id) throws NotFoundException {
        for (User user2 :  fetchAll()) {
             if (id == user2.getId()) {
                return user2;
             }else{
                throw new NotFoundException("Resource not found with Id :: " + id);
             }
         }
         return null;
     }

    public void create(User user) {
         users.add(user);
    }

    public void update(User user) {
         for (User user2 : users) {
            if (user.getId() == user2.getId()) {
                users.remove(user2);
                users.add(user);
            }
         }
    }

    public void delete(long id) throws NotFoundException {
      // TODO: delete operation
    }
}

8. Jersey JAX-RS Client for Rest API

Jersey Test Framework originated as an internal tool used for verifying the correct implementation of server-side components. 
If you want to develop a test using Jersey Test Framework, you need to subclass JerseyTest and configure the set of resources and/or providers that will be deployed as part of the test application.
The below short code snippet shows basic resource class UserResource used in tests defined as part of the UserResourceTest class. The overridden configure method returns a ResourceConfig of the test application, that contains only the UserResource resource class. ResourceConfig is a sub-class of JAX-RS Application. It is a Jersey convenience class for configuring JAX-RS applications. ResourceConfig also implements JAX-RS Configurable interface to make the application configuration more flexible. 
package com.javadevelopersguide.jersey.client;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.javadevelopersguide.jersey.model.User;

public class UserResourceClient {

    public static void main(String[] args) {
        //getUsers();
        getUser();
       // createUser();
       // updateUser();
       //deleteUser();
    }

    private static void getUsers() {
        Client client = ClientBuilder.newClient();

        String entity = client.target("http://localhost:8080/jersey-crud-example/api").path("users")
        .request(MediaType.APPLICATION_JSON).header("some-header", "true").get(String.class);

        System.out.println(entity);
    }

    private static void getUser() {
        Client client = ClientBuilder.newClient();

        String entity = client.target("http://localhost:8080/jersey-crud-example/api").path("users").path("user/100")
       .request(MediaType.APPLICATION_JSON).header("some-header", "true").get(String.class);

        System.out.println(entity);
    }
 
    private static void createUser() {
        Client client = ClientBuilder.newClient();
        WebTarget webTarget = client.target("http://localhost:8080/jersey-crud-example/api").path("users");

        User user = new User();
        user.setId(1);
        user.setName("Ramesh");

        Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON);
        Response response = invocationBuilder.post(Entity.entity(user, MediaType.APPLICATION_JSON));

        System.out.println(response.getStatus());
        System.out.println(response.readEntity(String.class));
    }

    private static void updateUser() {
        Client client = ClientBuilder.newClient();
        WebTarget webTarget = client.target("http://localhost:8080/jersey-crud-example/api").path("users")
        .path("user/1");

        User user = new User();
        user.setId(1);
        user.setName("Ramesh");

        Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON);
        Response response = invocationBuilder.put(Entity.entity(user, MediaType.APPLICATION_JSON));

        String userJson = response.readEntity(String.class);

        System.out.println(response.getStatus());
        System.out.println(userJson);
    }

    private static void deleteUser() {

         Client client = ClientBuilder.newClient();
         WebTarget webTarget = client.target("http://localhost:8080/jersey-crud-example/api").path("users")
        .path("user/100");

         User user = new User();
         user.setId(1);
         user.setName("Ramesh");

         Invocation.Builder invocationBuilder = webTarget.request();
         Response response = invocationBuilder.delete();

         System.out.println(response.getStatus());
         System.out.println(response.readEntity(String.class));
    }
}

9. Deployment

Development is completed, it's time to deploy this web application, so either it can be deployed from an external Tomcat server or run from eclipse.

Rest endpoint URLs, request and response details for your reference.

To fetch all the users.

Http Method : GET
http://localhost:8080/jersey-spring-integration/users
Response JSON :
[{"email":"[email protected]","id":100,"name":"A"},{"email":"[email protected]","id":101,"name":"B"},{"email":"[email protected]","id":102,"name":"C"}]

Get specific user by id

Http Method : GET
http://localhost:8080/jersey-spring-integration/users/user/100
Response : {"email":"[email protected]","id":100,"name":"me"}

Create a new user

Http Method : POST
http://localhost:8080/jersey-spring-integration/users
Request JSON : {"email":"[email protected]","id":106,"name":"D"}
Response : 201

Update a user

Http Method : PUT
http://localhost:8080/jersey-spring-integration/users/user/100
Request JSON : {"email":"[email protected]","id":100,"name":"D"}
Response : 200

Delete a user

Http Method : DELETE
http://localhost:8080/jersey-spring-integration/users/user/100
Response : 204

10. Conclusion

This article illustrated how to implement a Jersey JAX-RS Restful CRUD Web Services Example using latest jersey rest 2.27, jersey client and ResourceConfig @ApplicationPath annotation based configuration.

In the next article of the series, we will focus on more Jersey rest examples, concepts, and more.
All the code of this article is available over on Github. This is a Maven-based project, so it should be easy to import and run as it is.

Github Repository: Jersey JAX-RS Restful CRUD Web Services Example

Comments