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?
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?
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?
- Java Development Kit 8 (JDK8)
- Maven 3.0+
- cURL
7.0+
cURL
is installed by default on most Unix and Linux distributions. For the steps to install cURL on a Windows 64-bit machine, click here. - A favorite text editor or IDE.
Creating a new Maven project
In this section, you create a Jersey Maven project from an archetype project.
- Open a command line window (or Terminal in Linux).
- Navigate to the directory where the new project should reside.
-
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.
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:
- Project sources: Located under
src/main/java
. Contains 2 classes in thecom.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. - Project test sources: Located under
src/test/java. Contains a unit test class
MyResourceTest
in thecom.example.rest
package responsible for testing myresource. - A
pom.xml
located in the project root directory. Contains all dependencies needed for a Jersey project that runs on a Grizzly container. In thepom.xml
also is specified the class that contains the main method, in this case is theMain
class, that is called whenmvn 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.
-
Open the
pom.xml
. -
Add the
jersey-media-json-jackson
dependency for JSON support.<dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-jackson</artifactId> </dependency>
-
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.
-
Create a new class called
Customer
in thecom.example.rest
package. - 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); } } }
Creating a mock Customer list.
In this section, you create a helper class to create a list of customers for testing purposes.
-
Create a new class called
MockCustomerList
in thecom.example.rest
package. - 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; } }
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
).
-
Create a new class called
CustomerService
in thecom.example.rest
package. - 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 {
-
Create a
CopyOnWriteArrayList
of Customer usingMockCustomerList
class. This array will used to apply the REST operations (get, put, post and delete).private final CopyOnWriteArrayList<Customer> cList = MockCustomerList.getInstance();
- 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]); }
-
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
andJsonError
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")); } }
- 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.
- Create a new class called
JsonError
in thecom.example.rest
package. - Add two private String fields: type
and message.
private String type; private String message;
- Create a constructor with the parameters
type and message.
public JsonError(String type, String message){ this.type = type; this.message = message; }
- Add the getters methods.
public String getType(){ return this.type; } public String getMessage(){ return this.message; }
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.
- Create a new class called
NotFoundException
incom.example.rest
package that extends fromWebApplicationException
. -
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()); }
-
Add the missing imports.
import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response;
Running the Web Service
- Open a command line window (or Terminal in Linux).
- Navigate to the root directory of the project (jersey-service), where the pom.xml resides.
-
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] ------------------------------------------------------------------------
-
Execute the following Maven command to run the
main
method in theMain
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
cURL is a command line tool and library for transferring data with URL syntax.
Testing the resource method getAllCustomers
- Open a command line window (or Terminal in Linux).
- 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
- 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
.
-
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. Thejavax.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(); }
-
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(); } }
-
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")); } }
- 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
- Stop the app (if it's running).
- Execute again the steps of the section Running the Web Service.
- Open a command line or a Terminal for Linux.
- 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"}
- 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.
-
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"}
- 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
- 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.
-
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
-
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.
-
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.
-
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
-
Define the root element for the XML to be produced adding the
@XmlRootElement (name="customer")
JAXB annotation on the top of the classCustomer
.@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.
-
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; }
-
Add the missing imports.
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlElement;
- Change the
@Produces
media type in the resource methodgetAllCustomers
of theCustomerService
class toAPPLICATION_XML
.@GET @Path("/all") @Produces(MediaType.APPLICATION_XML) public Customer[] getAllCustomers() { return cList.toArray(new Customer[0]); }
Testing Web Service with XML updates
- Stop the app (if it's running).
- Execute again the steps of the section Running the Web Service.
- Open a command line or a Terminal for Linux.
-
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.zipWant to Learn More?
-
To learn more about Java and related topics check out the Oracle Learning Library
Credits
- Curriculum Developer: Luz Elena Peralta Ayala
- QA: Veerabhadra Rao Putrevu