Java SE 8: Creating a JSON REST Web Service with Grizzly and Jersey


Options



Before You Begin

Purpose

This tutorial explains how to develop a RESTful web service in Java with the JAX-RS reference implementation Jersey in a Grizzly container. The implemented operations are the basic REST operations: put, get, post and delete. Json and XML format are used for data interchange. No database is used to persist the data to keep the tutorial simple.

Time to Complete

Approximately 45 minutes.

Background

This section explains the basic concepts of REST, JAX-RS, JSON, Jersey and Grizzly.

What is REST?

REpresentational State Transfer.It is an architectural style for designing networked applications, that describes how one system can communicate state with another. One example would be the state of a Customer (its id, name, last name etc) represented as XML, JSON, or plain text. It is usually used to develop Web Services as a simpler alternative to SOAP and WSDL-based Web Services, a service based on REST is called a RESTful service. REST is not dependent on any protocol, but almost every RESTful service uses HTTP as its underlying protocol.

The REST style emphasizes that interactions between clients and services is enhanced by having a limited number of operations:

DELETE. Delete an existing resource.
GET. Retrieve a representation of a resource.
POST.Create a new resource to an existing URL.
PUT. Create a new resource to a new URL, or modify an existing resource to an existing URL.

There are a couple of other operations too, but they are utilized less frequently.

REST's lighter weight communications between producer and consumer make it a popular building style for cloud-based APIs.

What is JAX-RS and Jersey and how are they related?

Java defines REST support via the Java Specification Request (JSR) 311. This specification is called JAX-RS which is a standard API that simplifies the development of RESTful Web services and their clients in Java. JAX-RS uses annotations to aid with the development and deployment of web service clients and endpoints.

Jersey is an open source framework and is the JAX-RS reference implementation, which means that every specification defined in JAX-RS is implemented by Jersey. Jersey also provides it's own API that extends JAX-RS with additional features and utilities to further simplify RESTful service and client development.

Embedded servers and Grizzly

Most java web applications or service-oriented applications run within a container, these apps are packaged for distribution in a WAR file that contains all of libraries and application-level dependencies needed at runtime. Then, the WAR file can be deployed in a server container like Tomcat, JBOSS or GlassFish. However there is another option: embedded servers. With this approach, Java applications are packaged for command-line execution like any other app but rather being deployed to a container, an embedded container is deployed within the application itself and it's a lighter alternative to conventional servers.

Grizzly is a multi-protocol framework built on top of Java NIO. Grizzly aims to simplify development of robust and scalable servers and Jersey provides a container extension module that enables support for using Grizzly as an embedded plain vanilla HTTP container that runs JAX-RS applications. Starting a Grizzly server to run a JAX-RS or Jersey application is one of the most lightweight and easy ways how to expose a functional RESTful services application.

What is JSON?

JSON is short for JavaScript Object Notation and is an open standard format that store information in an organized and easy-to-access manner. This means that human-readable text is used to transmit data objects consisting of attribute–value pairs. JSON text is used primarily to transmit data between a server and web application, as an alternative to XML.

RESTful services are easy to develop and deploy, lightweight, inexpensive to host and maintain, and ideal for typical online applications. They are completely stateless and particularly useful for restricted-profile devices such as mobile and PDAs because they don't have native support for SOAP services but they do for HTTP, XML and JSON.

What Do You Need?

Install JDK8 and Maven following the instructions provided with the downloads.

Creating a new Maven project

In this section, you create a Jersey Maven project from an archetype project.

  1. Open a command line window (or Terminal in Linux).
  2. Navigate to the directory where the new project should reside.
  3. Execute the following Maven command:

    mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false -DgroupId=com.example.rest -DartifactId=jersey-service -Dpackage=com.example.rest -DarchetypeVersion=2.17

    Note: You can change the groupId, package and/or artifactId of this command for your particular project.

    This command creates a standard Maven structure, once it is finished, you should see the new jersey-service project directory created in your current location.

    Project structure
    Description of this image

You can open the project in Netbeans (File -> Open project) or in Eclipse (File -> Import -> Maven-> Existing Maven Project) but Maven must be configured in your IDE.

Exploring the new created project

The directory created contains the following structure:

  1. Project sources: Located under src/main/java. Contains 2 classes in the com.example.rest package:
    • The Main class responsible for configuring and deploying the project's JAX-RS application to the Grizzly container. This class configures:
      • The URI the Grizzly HTTP Server listens on.
      • The packages the Grizzly HTTP Server scans for JAX-RS resources.
      • And starts a new instance of Grizzly HTTP server.
      
                  public class Main {
                      // Base URI the Grizzly HTTP server will listen on
                      public static final String BASE_URI = "http://localhost:8080/myapp/";
                  
                      /**
                       * Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
                       * @return Grizzly HTTP server.
                       */
                      public static HttpServer startServer() {
                          // create a resource config that scans for JAX-RS resources and providers
                          // in com.example.rest package
                          final ResourceConfig rc = new ResourceConfig().packages("com.example.rest");
                  
                          // create and start a new instance of grizzly http server
                          // exposing the Jersey application at BASE_URI
                          return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
                      }
                  
                      /**
                       * Main method.
                       * @param args
                       * @throws IOException
                       */
                      public static void main(String[] args) throws IOException {
                          final HttpServer server = startServer();
                          System.out.println(String.format("Jersey app started with WADL available at "
                                  + "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
                          System.in.read();
                          server.stop();
                      }
                  }                                
    • The MyResource class, contains an implementation of a simple JAX-RS resource with one resource method. For the purpose of this tutorial this class is not used.
  2. Project test sources: Located under src/test/java. Contains a unit test class MyResourceTest in the com.example.rest package responsible for testing myresource.
  3. A pom.xml located in the project root directory. Contains all dependencies needed for a Jersey project that runs on a Grizzly container. In the pom.xml also is specified the class that contains the main method, in this case is the Main class, that is called when mvn exec:java command is executed (this command is covered in Running the service section).

Configuring the pom.xml

This section explains how to make changes to pom.xml in order to get JSON and java 1.8 support.

Jersey provides four different ways to integrate JSON support:

  • Jackson
  • Jettison
  • Java API for JSON Processing (JSON-P)
  • MOXy

MOXy is the default and preferred way of supporting JSON binding in Jersey applications, and it requires the entity setters methods. Since this tutorial uses the Builder Pattern, where setters are not allowed, Jackson is used to add support for JSON instead.

  1. Open the pom.xml.

  2. Add the jersey-media-json-jackson dependency for JSON support.

    <dependency>
      <groupId>org.glassfish.jersey.media</groupId>
      <artifactId>jersey-media-json-jackson</artifactId>
    </dependency>                                        
  3. Change maven-compiler-plugin to support java 1.8.

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>2.5.1</version>
      <inherited>true</inherited>
      <configuration>
      <source>1.8></source>
      <target>1.8</target>
      </configuration>
    </plugin>

The Customer Class Model

To model the Customer representation, you create a plain old java class with fields, constructors, and accessors for the fields. The Builder pattern is used in order to make the Customer class inmmutable.

  1. Create a new class called Customer in the com.example.rest package.

  2. Copy and paste the following code that creates a model of customer using the builder pattern.
    package com.example.rest;
    
    import java.util.concurrent.atomic.AtomicLong;
    
    public class Customer {
      private final long id;
      private final String firstName;
      private final String lastName;
      private final String email;
      private final String city;
      private final String state;
      private final String birthday;
      private static final AtomicLong counter = new AtomicLong(100);
     
      private Customer(CustomerBuilder builder){
        this.id = builder.id;
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.email = builder.email;
        this.city = builder.city;
        this.state = builder.state;
        this.birthday = builder.birthday;
      }
      
      public Customer(){
        Customer cust = new Customer.CustomerBuilder().id().build();
          this.id = cust.getId();
          this.firstName = cust.getFirstName();
          this.lastName = cust.getLastName();
          this.email = cust.getEmail();
          this.city = cust.getCity();
          this.state = cust.getState();
          this.birthday = cust.getBirthday();
      }
      
      public Customer(long id, String firstName, String lastName,
          String email, String city, String state, String birthday){
          Customer cust = new Customer.CustomerBuilder().id()
               .firstName(firstName)
               .lastName(lastName)
               .email(email)
               .city(city)
               .state(state)
               .birthday(birthday)
               .build();
          this.id = cust.getId();
          this.firstName = cust.getFirstName();
          this.lastName = cust.getLastName();
          this.email = cust.getEmail();
          this.city = cust.getCity();
          this.state = cust.getState();
          this.birthday = cust.getBirthday();
      }
      
      public long getId(){
        return this.id;
      }
    
      public String getFirstName() {
        return this.firstName;
      }
    
      public String getLastName() {
        return this.lastName;
      }
      
      public String getEmail(){
        return this.email;
      }
    
      public String getCity() {
        return this.city;
      }
    
      public String getState() {
        return this.state;
      } 
      
      public String getBirthday(){
        return this.birthday;
      }
      
      @Override
      public String toString(){
        return "ID: " + id 
            + " First: " + firstName
            + " Last: " + lastName + "\n"
            + "EMail: " + email + "\n"
            + "City: " + city
            + " State: " + state
            + " Birthday " + birthday;
      }  
      
      public static class CustomerBuilder{
        private long id;
        private String firstName = "";
        private String lastName = "";
        private String email = "";
        private String city = "";
        private String state = "";
        private String birthday = "";
        
        public CustomerBuilder id(){
          this.id = Customer.counter.getAndIncrement();
          return this;
        }
        
        public CustomerBuilder firstName(String firstName){
          this.firstName = firstName;
          return this;
        }
    
        public CustomerBuilder lastName(String lastName){
          this.lastName = lastName;
          return this;
        }
        
        public CustomerBuilder email(String email){
          this.email = email;
          return this;
        }
        
        public CustomerBuilder city(String city){
          this.city = city;
          return this;
        }
        
        public CustomerBuilder state(String state){
          this.state = state;
          return this;
        }
        
        public CustomerBuilder birthday(String birthday){
          this.birthday = birthday;
          return this;
        }
        
        public Customer build(){
          return new Customer(this);
        }
        
      }    
    }
    
Download Customer.java

Creating a mock Customer list.

In this section, you create a helper class to create a list of customers for testing purposes.

  1. Create a new class called MockCustomerList in the com.example.rest package.

  2. Copy and paste the following code to create a list of customers.
    
    package com.example.rest;
    
    import java.util.concurrent.CopyOnWriteArrayList;
    import java.util.stream.Collectors;
    
    public class MockCustomerList {
      private static final CopyOnWriteArrayList<Customer> cList = new CopyOnWriteArrayList<>();
    
      static {
        // Create list of customers
        cList.add(
            new Customer.CustomerBuilder().id()
            .firstName("George")
            .lastName("Washington")
            .email("gwash@example.com")
            .city("Mt Vernon")
            .state("VA")
            .birthday("1732-02-23")
            .build()
        );
    
        cList.add(
            new Customer.CustomerBuilder().id()
            .firstName("John")
            .lastName("Adams")
            .email("jadams@example.com")
            .city("Braintree")
            .state("MA")
            .birthday("1735-10-30")
            .build()
        );
    
        cList.add(
            new Customer.CustomerBuilder().id()
            .firstName("Thomas")
            .lastName("Jefferson")
            .email("tjeff@example.com")
            .city("CharlottesVille")
            .state("VA")
            .birthday("1743-04-13")
            .build()
        );
    
        cList.add(
            new Customer.CustomerBuilder().id()
            .firstName("James")
            .lastName("Madison")
            .email("jmad@example.com")
            .city("Orange")
            .state("VA")
            .birthday("1751-03-16")
            .build()
        );
    
        cList.add(
            new Customer.CustomerBuilder().id()
            .firstName("James")
            .lastName("Monroe")
            .email("jmo@example.com")
            .city("New York")
            .state("NY")
            .birthday("1758-04-28")
            .build()
        );
    
      }
      
      private MockCustomerList(){}
      
      public static CopyOnWriteArrayList<Customer> getInstance(){
        return cList;
      }
      
    }                                
Download MockCustomerList.java

Reading from a REST Web Service

In this section, you learn how to create a Rest Service that implements the resource method get using the annotations introduced in Java SE 5 (@GET, @Path, @PathParam, @Produces).

  1. Create a new class called CustomerService in the com.example.rest package.

  2. Annotate the class with @Path ("customers").

    The @Path annotation provides a value attribute that indicates the path at which the resource is available to receive HTTP requests. The value attribute may be literal characters, variables, or variables plus a customized regular expression.It can be placed upon a class or on one or more Java methods. Java classes annotated with @Path are called JAX-RS root resources.

     @Path("/customers")
     public class CustomerService {                                  
  3. Create a CopyOnWriteArrayList of Customer using MockCustomerList class. This array will used to apply the REST operations (get, put, post and delete).

     private final CopyOnWriteArrayList<Customer> cList = MockCustomerList.getInstance();                               
  4. Create a GET resource method called getAllCustomers that returns an array with all the Customers in JSON format.

    The @GET annotation enables the method to process HTTP GET requests. HTTP GET methods are used to retrieve (or read) a representation of a resource, in this case the list of Customers.

    The @Produces annotation is used to specify the MIME media types a resource can produce and send back to the client. In this example, the Java method will produce representations identified by the MIME media type "JSON".

    @GET
    @Path("/all")
    @Produces(MediaType.APPLICATION_JSON)
    public Customer[] getAllCustomers() {
    return cList.toArray(new Customer[0]);
    }                                     
  5. Create a GET resource method called getCustomer that receives an id and returns the Customer.

    This method gets the id from the URI and using a Lambda expression looks for the Customer that matches, if there is none an exception is thrown and a message in json format is send to the client. NotFoundException and JsonError classes are covered in the next sections.

    URI path templates are URIs with variables embedded within the URI syntax. These variables are substituted at runtime in order for a resource to respond to a request based on the substituted URI. Variables are denoted by braces ({ }).

    The @PathParam annotation is used to extract parameters from the URI. The @Path expression "{id}" must matches with the value of the @PathParam "id".

    This method returns 200 (OK) and in this case a single Customer or 404 (Not found) if the id is not found or is invalid.

      @GET
      @Path("{id}")
      @Produces(MediaType.APPLICATION_JSON)
      public Customer getCustomer(@PathParam("id") long id){
        Optional<Customer> match
            = cList.stream()
            .filter(c -> c.getId() == id)
            .findFirst();
        if (match.isPresent()) {
          return match.get();
        } else {
          throw new NotFoundException(new JsonError("Error", "Customer " + id + " not found"));
        }
      }                                  
  6. Add the missing imports.
    import java.util.Optional;
    import java.util.concurrent.CopyOnWriteArrayList;
    import javax.ws.rs.Consumes;
    import javax.ws.rs.GET;
    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;                                                   

Download CustomerService.java

Creating JsonError class

In this section, you create a JsonError class to send error messages to the client if something is wrong. This class is used to give more information to the client about the error.

  1. Create a new class called JsonError in the com.example.rest package.
  2. Add two private String fields: type and message.
      private String type;
      private String message;                   
  3. Create a constructor with the parameters type and message.
      public JsonError(String type, String message){
        this.type = type;
        this.message = message;                
      }                               
  4. Add the getters methods.
      public String getType(){
        return this.type;
      }
      
      public String getMessage(){
        return this.message;
      }                                
Download JsonError.java

Creating NotFoundException class

WebApplicationException is a runtime exception used by resource methods to send a message error and a HTTP status to the client when something is wrong. The NotFoundException class wraps WebApplicationException to provide a message error in Json format.

  1. Create a new class called NotFoundException in com.example.rest package that extends from WebApplicationException.
  2. Add the following constructors:

        public NotFoundException() {
            super(Response.status(Response.Status.NOT_FOUND).type(MediaType.TEXT_PLAIN).build());
        }
    
        public NotFoundException(String message) {
          super(Response.status(Response.Status.NOT_FOUND).entity(message).type(MediaType.TEXT_PLAIN).build());
        }
    
        public NotFoundException(JsonError jse) {
          super(Response.status(Response.Status.NOT_FOUND).entity(jse).type(MediaType.APPLICATION_JSON).build());
        }                                   
  3. Add the missing imports.

        import javax.ws.rs.WebApplicationException;
        import javax.ws.rs.core.MediaType;
        import javax.ws.rs.core.Response;                               
Download NotFoundException.java

Running the Web Service

This section shows how to run the web service.
  1. Open a command line window (or Terminal in Linux).
  2. Navigate to the root directory of the project (jersey-service), where the pom.xml resides.
  3. Execute the following Maven command to compile the code.

    mvn clean compile

    Note: If you get a compile error, review your source code for errors, then save it and run the command again.

    c:\examples\jersey-service>mvn clean compile
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building jersey-service 1.0-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ jersey-service ---
    [INFO] Deleting c:\examples\jersey-service\target
    [INFO]
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ jersey-service ---
    [INFO] Using 'UTF-8' encoding to copy filtered resources.
    [INFO] skip non existing resourceDirectory c:\examples\jersey-service\src\main\resources
    [INFO]
    [INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ jersey-service ---
    [INFO] Compiling 7 source files to c:\examples\jersey-service\target\classes
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 4.284 s
    [INFO] Finished at: 2015-07-29T16:07:34-05:00
    [INFO] Final Memory: 14M/135M
    [INFO] ------------------------------------------------------------------------ 
  4. Execute the following Maven command to run the main method in the Main class.

    mvn exec:java
    c:\examples\jersey-service>mvn exec:java
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building jersey-service 1.0-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] >>> exec-maven-plugin:1.2.1:java (default-cli) > validate @ jersey-service >>>
    [INFO]
    [INFO] <<< exec-maven-plugin:1.2.1:java (default-cli) < validate @ jersey-service <<<
    [INFO]
    [INFO] --- exec-maven-plugin:1.2.1:java (default-cli) @ jersey-service ---
    jul 29, 2015 4:09:45 PM org.glassfish.grizzly.http.server.NetworkListener start
    INFO: Started listener bound to [localhost:8080]
    jul 29, 2015 4:09:45 PM org.glassfish.grizzly.http.server.HttpServer start
    INFO: [HttpServer] Started.
    Jersey app started with WADL available at http://localhost:8080/myapp/application.wadl
    Hit enter to stop it... 

Testing the Customer Service

This section shows how to test the rest service using cURL.

cURL is a command line tool and library for transferring data with URL syntax.

Testing the resource method getAllCustomers

  1. Open a command line window (or Terminal in Linux).
  2. Execute the following command:
curl -X GET http://localhost:8080/myapp/customers/all 

-X is used to specify the type of method request.

http://localhost:8080/myapp/ is the URI where the service is hosted.

/customers is the path of the root class and /all is the path of the resource method.

C:\Program Files\curl>curl -X GET -i http://localhost:8080/myapp/customers/all
HTTP/1.1 200 OK
Content-Type: application/json
Date: Wed, 29 Jul 2015 21:49:42 GMT
Content-Length: 684

[{"firstName":"George","lastName":"Washington","email":"gwash@example.com","city":"Mt Vernon","state":"VA","id":100,"
birthday":"1732-02-23"},{"firstName":"John","lastName":"Adams","email":"jadams@example.com","city":"Braintree","state
":"MA","id":101,"birthday":"1735-10-30"},{"firstName":"Thomas","lastName":"Jefferson","email":"tjeff@example.com","ci
ty":"CharlottesVille","state":"VA","id":102,"birthday":"1743-04-13"},{"firstName":"James","lastName":"Madison","email
":"jmad@example.com","city":"Orange","state":"VA","id":103,"birthday":"1751-03-16"},{"firstName":"James","lastName":"
Monroe","email":"jmo@example.com","city":"New York","state":"NY","id":104,"birthday":"1758-04-28"}]

Testing the resource method getCustomer

  1. Execute the following command:
curl -X GET -i http://localhost:8080/myapp/customers/101

-i is used to display the headers, normally they are hidden.

101 is the Customer id. Initially in the MockCustomerList class where added five customers (id from 100 to 104).

C:\Program Files\curl>curl -X GET -i http://localhost:8080/myapp/customers/101
HTTP/1.1 200 OK
Content-Type: application/json
Date: Wed, 29 Jul 2015 21:25:49 GMT
Content-Length: 133

{"firstName":"John","lastName":"Adams","email":"jadams@example.com","city":"Braintree","state":"MA","id":101,"birthday":
"1735-10-30"}

200 (OK) status and the customer's data are received.

You can try with one Customer id that doesn't exist.

curl -X GET -i http://localhost:8080/myapp/customers/110 
C:\Program Files\curl>curl -X GET -i http://localhost:8080/myapp/customers/110
HTTP/1.1 404 Not Found
Content-Type: application/json
Date: Wed, 29 Jul 2015 21:27:36 GMT
Content-Length: 51

{"type":"Error","message":"Customer 110 not found"}

404 (Not found) status and a message error in json format are received.

Modifying REST Web Service Data

This section shows how to implement the methods post, put and delete using the annotations @POST, @PUT and @DELETE.

  1. Create a POST method called addCustomer that receives a Customer and returns a status response.

    The @POST annotation enables the method to process HTTP POST requests. The HTTP POST method is most-often utilized for creation of new resources.On successful creation, HTTP returns status 201. The javax.ws.rs.core.Response class is used to send the status response to the client.

        @POST
        @Path("/add")
        @Produces(MediaType.APPLICATION_JSON)
        public Response addCustomer(Customer customer){
          cList.add(customer);
          return Response.status(201).build();
        }                                  
  2. Create a PUT resource method called updateCustomer that receives a Customer object and returns the response status.

    The @PUT annotation indicates that the annotated method responds to HTTP PUT requests. HTTP PUT methods are used to update an existing resource base on the Request-URI. The URI in a PUT request identifies the resource that will handle the enclosed entity. On a successful update, the method returns status 200. A status code of 204 is returned if the id is not found or is invalid.

        @PUT
        @Path("{id}/update")
        @Produces(MediaType.APPLICATION_JSON)
        public Response updateCustomer(Customer customer){
          int matchIdx = 0;
          Optional<Customer> match = cList.stream()
              .filter(c -> c.getId() == customer.getId())
              .findFirst();
          if (match.isPresent()) {
            matchIdx = cList.indexOf(match.get());
            cList.set(matchIdx, customer);
            return Response.status(Response.Status.OK).build();
          } else {
            return Response.status(Response.Status.NOT_FOUND).build();      
          }
        }                                  
  3. Create a DELETE resource method called deleteCustomer that receives an id and removes the Customer of the list.

    The @DELETE annotated indicates that the annotated method responds to HTTP DELETE requests. The DELETE method should identify resources to be deleted by Resource-URI.

        @DELETE
        @Path("/remove/{id}")
        public void deleteCustomer(@PathParam("id") long id){
          Predicate <Customer> customer = c -> c.getId() == id;
          if (!cList.removeIf(customer)) {
           throw new NotFoundException(new JsonError("Error", "Customer " + id + " not found"));
          }
        }                                 
  4. Add the missing imports.
        import java.util.function.Predicate;
        import javax.ws.rs.DELETE;
        import javax.ws.rs.POST;
        import javax.ws.rs.PUT;                                

Download CustomerService.java updated.

Testing Web Service Updates

This section shows how to test the resources PUT, POST and DELETE implemented in the previous section using cURL tool.

Testing the resource method updateCustomer

  1. Stop the app (if it's running).
  2. Execute again the steps of the section Running the Web Service.
  3. Open a command line or a Terminal for Linux.
  4. Search the Customer id 102 executing the following command:
    curl -X GET -i http://localhost:8080/myapp/customers/102
    C:\Program Files\curl>curl -X GET -i http://localhost:8080/myapp/customers/102
    HTTP/1.1 200 OK
    Content-Type: application/json
    Date: Wed, 29 Jul 2015 21:30:01 GMT
    Content-Length: 144
    
    {"firstName":"Thomas","lastName":"Jefferson","email":"tjeff@example.com","city":"CharlottesVille","state":"VA","id":102,
    "birthday":"1743-04-13"}
  5. Execute the following command to update the Customer with the id 102:

    For Linux:

    curl -X PUT -i -H "Content-Type: application/json" -d '{"id":102, "firstName":"Abigail","lastName":"Adams","email":"aadams@example.com","city":"Braintree","state":"MA","birthday":"1744-11-22"}' http://localhost:8080/myapp/customers/102/update
                                        

    For windows, the syntax changes a little, you need to escape the double-quotes.

    curl -X PUT -i -H "Content-Type:application/json" -d "{\"id\":102,\"firstName\":\"Abigail\",\"lastName\":\"Adams\",\"email\":\"aadams@example.com\",\"city\":\"Braintree\",\"state\":\"MA\",\"birthday\":\"1744-11-22\"}" http://localhost:8080/myapp/customers/102/update                                    

    -d is used to send data.

    -H is used to pass custom header LINE to server

    C:\Program Files\curl>curl -X PUT -i -H "Content-Type:application/json" -d "{\"id\":102,\"firstName\":\"Abigail\",\"l
    astName\":\"Adams\",\"email\":\"aadams@example.com\",\"city\":\"Braintree\",\"state\":\"MA\",\"birthday\":
    \"1744-11-22\"}" http://localhost:8080/myapp/customers/102/update
    HTTP/1.1 200 OK
    Date: Wed, 29 Jul 2015 21:32:04 GMT
    Content-Length: 0 

    200 (OK) status is received which means the Customer (id 102) was successfully updated.

  6. Verify that the Customer's data have changed executing the command in the step 4 again.

    C:\Program Files\curl>curl -X GET -i http://localhost:8080/myapp/customers/102
    HTTP/1.1 200 OK
    Content-Type: application/json
    Date: Wed, 29 Jul 2015 21:34:02 GMT
    Content-Length: 136
    
    {"firstName":"Abigail","lastName":"Adams","email":"aadams@example.com","city":"Braintree","state":"MA","id":102,"birthday":"1744-11-22"} 
  7. Try to update a Customer (id) that doesn't exist executing the following command:

    For Linux:

    curl -X PUT -i -H "Content-Type: application/json" -d '{"id":118, "firstName":"Abigail","lastName":"Adams","email":"aadams@example.com","city":"Braintree","state":"MA","birthday":"1744-11-22"}' http://localhost:8080/myapp/customers/118/update
                                        

    For windows:

    curl -X PUT -i -H "Content-Type:application/json" -d "{\"id\":118,\"firstName\":\"Abigail\",\"lastName\":\"Adams\",\"email\":\"aadams@example.com\",\"city\":\"Braintree\",\"state\":\"MA\",\"birthday\":\"1744-11-22\"}" http://localhost:8080/myapp/customers/118/update                                    
    C:\Program Files\curl>curl -X PUT -i -H "Content-Type:application/json" -d "{\"id\":118,\"firstName\":\"Abigail\",\"l
    astName\":\"Adams\",\"email\":\"aadams@example.com\",\"city\":\"Braintree\",\"state\":\"MA\",\"birthday\":\"1744-11-2
    2\"}" http://localhost:8080/myapp/customers/118/update
    HTTP/1.1 404 Not Found
    Date: Wed, 29 Jul 2015 21:35:32 GMT
    Content-Length: 0

    A 404 (Not Found) status is received because the Customer Id 118 doesn't exist.

Testing the resource method addCustomer

  1. Execute the following command to add a new Customer:

    For Linux:

    curl -X POST -i -H "Content-Type: application/json" -d '{"firstName":"Laura","lastName":"Stuart","email":"lstuart@example.com","city":"Braintree","state":"MA", "birthday":"1744-11-22"}' http://localhost:8080/myapp/customers/add

    For Windows:

    curl -X POST -i -H "Content-Type: application/json" -d "{\"firstName\":\"Laura\",\"lastName\":\"Stuart\",\"email\":\"lstuart@example.com\",\"city\":\"Braintree\",\"state\":\"MA\",\"birthday\":\"1744-11-22\"}" http://localhost:8080/myapp/customers/add
    C:\Program Files\curl>curl -X POST -i -H "Content-Type: application/json" -d "{\"firstName\":\"Laura\",\"lastName\":\
    "Stuart\",\"email\":\"lstuart@example.com\",\"city\":\"Braintree\",\"state\":\"MA\",\"birthday\":\"1744-11-22\"}" htt
    p://localhost:8080/myapp/customers/add
    HTTP/1.1 201 Created
    Date: Wed, 29 Jul 2015 21:45:09 GMT
    Content-Length: 0

    201 (Created) status is received which means the new customer was successfully created.

  2. Verify that the new Customer was created.

    C:\Program Files\curl>curl -X GET -i http://localhost:8080/myapp/customers/105
    HTTP/1.1 200 OK
    Content-Type: application/json
    Date: Thu, 30 Jul 2015 14:10:58 GMT
    Content-Length: 136
    
    {"firstName":"Laura","lastName":"Stuart","email":"lstuart@example.com","city":"Braintree","state":"MA","id":105,"birt
    hday":"1744-11-22"}

Testing the resource method deleteCustomer

  1. Execute the following command to delete the Customer with the id 101:

    curl -X DELETE -i http://localhost:8080/myapp/customers/remove/101
    C:\Program Files\curl>curl -X DELETE -i http://localhost:8080/myapp/customers/remove/101
    HTTP/1.1 200 OK
    Date: Wed, 29 Jul 2015 22:01:01 GMT
    Content-Length: 0 

    200 (OK) status is received which means the customer id 101 was removed successfully.

  2. Execute the same command again.

    C:\Program Files\curl>curl -X DELETE -i http://localhost:8080/myapp/customers/remove/101
    HTTP/1.1 404 Not Found
    Date: Wed, 29 Jul 2015 22:03:36 GMT
    Content-Length: 0 

    A 404 (Not Found) status is received because the customer id 101 is already removed.

  3. Check all the customers again.

    C:\Program Files\curl>curl -X GET -i http://localhost:8080/myapp/customers/all
    HTTP/1.1 200 OK
    Content-Type: application/json
    Date: Thu, 30 Jul 2015 14:00:36 GMT
    Content-Length: 679
    
    [{"firstName":"George","lastName":"Washington","email":"gwash@example.com","city":"Mt Vernon","state":"VA","id":100,
    birthday":"1732-02-23"},{"firstName":"Abigail","lastName":"Adams","email":"aadams@example.com","city":"Braintree","s
    ate":"MA","id":102,"birthday":"1744-11-22"},{"firstName":"James","lastName":"Madison","email":"jmad@example.com","ci
    y":"Orange","state":"VA","id":103,"birthday":"1751-03-16"},{"firstName":"James","lastName":"Monroe","email":"jmo@exa
    ple.com","city":"New York","state":"NY","id":104,"birthday":"1758-04-28"},{"firstName":"Laura","lastName":"Stuart","
    mail":"lstuart@example.com","city":"Braintree","state":"MA","id":107,"birthday":"1744-11-22"}]
    C:\Program Files\curl>

    There is not a Customer id 101.

Changing the JSON format to XML

This section shows how to change the format produce from JSON to XML.
  1. Define the root element for the XML to be produced adding the @XmlRootElement (name="customer") JAXB annotation on the top of the class Customer.

    @XmlRootElement (name="customer")
    public class Customer {

    If the attibute name is not specified the name of the root XML element is derived from the class name.

  2. Annotate all fields with @XMLElement to be included in XML output.

    @XmlElement annotation can be place on the fields or getters methods. Add @XmlAccessorType(XmlAccessType.FIELD) at the class level if you want to annotate private fields instead of getter methods. By default, public fields will be serialized to XML elements.

      @XmlElement
      public long getId(){
        return this.id;
      }
      @XmlElement
      public String getFirstName() {
        return this.firstName;
      }
      @XmlElement
      public String getLastName() {
        return this.lastName;
      }
      @XmlElement
      public String getEmail(){
        return this.email;
      }
      @XmlElement
      public String getCity() {
        return this.city;
      }
      @XmlElement
      public String getState() {
        return this.state;
      } 
      @XmlElement
      public String getBirthday(){
        return this.birthday;
      }
  3. Add the missing imports.

    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlElement;
  4. Change the @Produces media type in the resource method getAllCustomers of the CustomerService class to APPLICATION_XML.
      @GET
      @Path("/all")
      @Produces(MediaType.APPLICATION_XML)
      public Customer[] getAllCustomers() {
        return cList.toArray(new Customer[0]);
      }

Testing Web Service with XML updates

  1. Stop the app (if it's running).
  2. Execute again the steps of the section Running the Web Service.
  3. Open a command line or a Terminal for Linux.
  4. Execute the following command to get all customer's list:

    curl -X GET http://localhost:8080/myapp/customers/all
    C:\Program Files\curl>curl -X GET http://localhost:8080/myapp/customers/all
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><customers><customer><id>100</id><firstName>George</firstName>
    <lastName>Washington</lastName><email>gwash@example.com</email><city>Mt Vernon</city><state>VA</state><birthday>1732-
    02-23</birthday></customer><customer><id>101</id><firstName>John</firstName><lastName>Adams</lastName><email>jadams@e
    xample.com</email><city>Braintree</city><state>MA</state><birthday>1735-10-30</birthday></customer><customer><id>102
    </id><firstName>Thomas</firstName><lastName>Jefferson</lastName><email>tjeff@example.com</email><city>CharlottesVille
    </city><state>VA</state><birthday>1743-04-13</birthday></customer><customer><id>103</id><firstName>James</firstName>
    <lastName>Madison</lastName><email>jmad@example.com</email><city>Orange</city><state>VA</state><birthday>1751-03-16
    </birthday></customer><customer><id>104</id><firstName>James</firstName><lastName>Monroe</lastName><email>jmo@example.com
    </email><city>New York</city><state>NY</state><birthday>1758-04-28</birthday></customer></customers> 

Resources

The Maven project with source code is in the following zip file.

jersey-service.zip

Want to Learn More?

Credits

  • Curriculum Developer: Luz Elena Peralta Ayala
  • QA: Veerabhadra Rao Putrevu