In this tutorial I am going to explain how to develop restful web services in java using the opensource JAX-RS 2.0 APIs. Also explains how to write JAX-RS 2.0 client API for invoking the JAX-RS 2.0 web services.
In my previous post I wrote about using JAXB to marshall and unmarshal XML data and in that I used the example of simple Book management system. In this post I am expanding on that to create a RESTful Webservice using the refrence implementation of JAX-RS i.e Jersey and also using the new Client API introduced in JAX-RS 2.0 which comes with JavaEE 7. The RESTful Webservice to be developed will support the following:
- To add a details of new book.
- To get the details of a book given its ISBN.
- To get the details of all the books present in the database.
The database in my example is not the usual database but just a Java Collection object which contains list of Book objects.
If you are not familiar with REST and its concepts I would suggest you to search on the net for some basic information before proceeding further. I would recommend to read the book RESTful Web Services.
also read:
Now lets look at creating RESTful Web Service using JAX-RS reference implementation.
Creating a RESTful Web Service using JAX-RS 2.0
- Annotate the class representing some service with
@javax.ws.rs.Path
annotation and also pass the URL at which this service can be invoked. This service class should have a default public constructor and the class should not be final or abstract. - To support different HTTP methods define different methods within the service class and for each method annotation with
@javax.ws.rs.GET
or@javax.ws.rs.POST
or@javax.ws.rs.PUT
or@javax.ws.rs.DELETE
depending on which HTTP method you want to be handled by the methods. - One can annotate at the class level or at the method level the format of data accepted by the RESTful service and the format of data generated by the RESTful Service by using the
@javax.ws.rs.Produces
and@javax.ws.rs.Consumes
annotations.
Lets build a RESTful webservice which will support the following operations:
- To list all the books present in the database.
- To list the details of a particular book.
- To add details for new book.
Building the RESTful Webservice
Let us identify the Path which can be used to perform the above stated operations:
- To list all the books present in the database – The URL for this would be a GET request to /book/
- To list the details of a particular book – The URL for this would be a GET request to /book/{isbn}
- To add details for new book – The URL for this would be a POST request to /book/
All of the above services accept XML data and generate XML data as response. The implementation for the RESTful service which supports all of these operations is given below:
import db.BookDb; import java.net.URISyntaxException; import javax.ws.rs.BadRequestException; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import model.Book; import model.Books; /** * RESTful Service for operations on Book like adding new book, * viewing the data for a book given its ISBN, listing all the books. */ @Path("/book") @Produces(MediaType.APPLICATION_XML) @Consumes(MediaType.APPLICATION_XML) public class BookRestService { @Context UriInfo uriInfo; /** * Service method to return all the books present in the database in the form * of XML. The conversion from Java object to XML is handled by JAXB. */ @GET public Books getAllBooks(){ Books books = BookDb.bookDb.getAllBooks(); return books; } /** * Service method to return the details of the book represented by the ISBN * number. The conversion from Book java object to XML is handled by JAXB. */ @GET @Path("{isbn}") public Book getBook(@PathParam("isbn") String isbn){ Book book = BookDb.bookDb.getBookByIsbn(isbn); if ( book == null ){ throw new NotFoundException("No book found with the matching ISBN: "+ isbn); } return book; } /** * Service method to add the details of the new book. The data for the details * of the book is sent in the form of XML which is converted to Book object * by the JAXB. And return the the details page displaying the details * of the new Book added. */ @POST @Consumes(MediaType.APPLICATION_XML) public Response createBook(Book book) throws URISyntaxException{ if ( book == null){ throw new BadRequestException(); } BookDb.bookDb.addToBookDb(book); return Response.created(uriInfo.getAbsolutePathBuilder().path(book.isbn).build()).build(); } }
In the previous post I had shown how to create XML data given Book
object or Books
object and also how to create Book
object or Books
object given the XML data representing it using JAXB. This complete RESTful Webservice implementation shown above is based on top of this JAXB implementation. The RESTful API i.e JAX-RS does the conversion from Java object to XML and from XML to Java Object using the JAXB implementation there by making it easier for development of the RESTful Webservice.
Using JAX-RS Client API to access the RESTful Webservice
In JavaEE 7 a new Client API has been added to the JAX-RS API. I will make use of that API to access the RESTful Webservice developed above. These are the basic tasks to be performed to use the client API to access the RESTful Webservice:
- Obtain the instance of
javax.ws.rs.client.Client
class which is the basic and entry point to invoking RESTful Webservices. - To invoke a RESTful Webserivce at some location or URI create an instance of
javax.ws.rs.client.WebTarget
using the instance of Client class. - Once you have the target you will have to populate the target with the required data like query params, MIME Type, any post data and then create a request of appropriate HTTP method type which would be an instance of
javax.ws.rs.client.Invocation
. - Use the instance of
javax.ws.rs.client.Invocation
to obtain the response from the desired RESTful Webservice.
Lets apply the above steps to invoke the RESTful Webservice at “http:///rs/book”. In my case the Book RESTful Webserivce is available at: http://localhost:8080/RestfulDemo/rs/book.
Invoking the getAllBooks() RESTful Webservice
Lets look at the code which invokes the getAllBooks()
RESTful Webservice:
import java.util.List; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import model.Book; import model.Books; import model.Review; import rest.BookRestService; /** * Testing the Client API by invoking the Book RESTful Webservice. */ public class BookRestClient { public static void main(String[] args) { invokeAllBooksService(); } private static void invokeAllBooksService() { System.out.println("****Invoking the All Books Service****"); //Obtaining the instance of Client which will be entry point to invoking REST Services. Client client = ClientBuilder.newClient(); //Targeting the RESTful Webserivce we want to invoke by capturing it in WebTarget instance. WebTarget allBooksTarget = client.target("http://localhost:8080/RestfulDemo/rs/book"); //Building the request i.e a GET request to the RESTful Webservice defined //by the URI in the WebTarget instance. Invocation allBooksInvocation = allBooksTarget.request().buildGet(); //Invoking the request to the RESTful API and capturing the Response. Response response = allBooksInvocation.invoke(); //As we know that this RESTful Webserivce returns the XML data which can be unmarshalled //into the instance of Books by using JAXB. Books books = response.readEntity(Books.class); for (Book book : books.myBooks) { printBook(book); } } private static String joinList(List list) { StringBuilder builder = new StringBuilder(); for (String str : list) { builder.append(str).append(","); } return builder.toString().substring(0, builder.length() - 1); } private static void printBook(Book book) { System.out.println("Details for: " + book.title); System.out.println("Author: " + joinList(book.authors)); System.out.println("ISBN: " + book.isbn); System.out.println("Publisher: " + book.publisher); System.out.println("Cost: " + book.price); System.out.println("Publication year: " + book.year); System.out.println("Reviews: "); for (Review review : book.reviews) { System.out.println(review.content + " by " + review.author + " posted on " + review.getPostedOn()); } } }
Invoking the getBook() RESTful Webservice
In this we will invoke the Book RESTful Webservice by passing in an ISBN value which will be of the form “/book/9781259002465”.
private static void invokeGetBookService() { System.out.println("****Invoking the Get Book Service****"); String isbn = "9781259002465"; Client client = ClientBuilder.newClient(); WebTarget target = client.target("http://localhost:8080/RestfulDemo/rs/book/"+isbn); Response response = target.request().buildGet().invoke(); Book book = response.readEntity(Book.class); printBook(book); } private static void printBook(Book book) { System.out.println("Details for: " + book.title); System.out.println("Author: " + joinList(book.authors)); System.out.println("ISBN: " + book.isbn); System.out.println("Publisher: " + book.publisher); System.out.println("Cost: " + book.price); System.out.println("Publication year: " + book.year); System.out.println("Reviews: "); for (Review review : book.reviews) { System.out.println(review.content + " by " + review.author + " posted on " + review.getPostedOn()); } }
Invoking the createBook() RESTful Webservice
This RESTful Webservice is used to add the details of new book. And once added it gives the URL to the user to view details of the new book.
private static void invokeCreateBookService() { System.out.println("****Invoking the Create Book Service****"); Calendar calendar = Calendar.getInstance(); Date today = calendar.getTime(); calendar.add(Calendar.DATE, -4); Date olderDay1 = calendar.getTime(); Book book = new Book(); book.authors = Arrays.asList("Gayle Laakmann McDowell"); book.binding = Binding.PAPERBACK; book.isbn = "9788126538058"; book.numberOfPages = 280; book.price = 260.0; book.publisher = "Wiley/Goels Computer Hut"; book.title = "The Google Resume: How to Prepare for a Career and land a Job at Apple, Microsoft, Google, or Any Top Tech Company"; book.year = 2012; book.reviews = (Arrays.asList(new Review("Very Precise and handy", "Shameer", today, Rating.FOUR), new Review("Best guide for cover letters, resumes etc", "Harshith", olderDay1, Rating.FIVE))); Client client = ClientBuilder.newClient(); WebTarget target = client.target("http://localhost:8080/RestfulDemo/rs/book"); Response response = target.request().buildPost(Entity.entity(book, MediaType.APPLICATION_XML)).invoke(); System.out.println(response.getLocation().getPath()); }
JAX-RS RESTful Web Service Example Application
The complete code for invoking the Book RESTful Webservice using the new Client API in JAX-RS 2.0 is give below:
import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.List; 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 model.Binding; import model.Book; import model.Books; import model.Rating; import model.Review; /** * Testing the Client API by invoking the Book RESTful Webservice. */ public class BookRestClient { public static void main(String[] args) { invokeAllBooksService(); invokeGetBookService("9781259002465"); invokeCreateBookService(); //Trying to read the book details created by the above method. invokeGetBookService("9788126538058"); } private static void invokeAllBooksService() { System.out.println("****Invoking the All Books Service****"); //Obtaining the instance of Client which will be entry point to invoking REST Services. Client client = ClientBuilder.newClient(); //Targeting the RESTful Webserivce we want to invoke by capturing it in WebTarget instance. WebTarget allBooksTarget = client.target("http://localhost:8080/RestfulDemo/rs/book"); //Building the request i.e a GET request to the RESTful Webservice defined //by the URI in the WebTarget instance. Invocation allBooksInvocation = allBooksTarget.request().buildGet(); //Invoking the request to the RESTful API and capturing the Response. Response response = allBooksInvocation.invoke(); //As we know that this RESTful Webserivce returns the XML data which can be unmarshalled //into the instance of Books by using JAXB. Books books = response.readEntity(Books.class); for (Book book : books.myBooks) { printBook(book); } } private static void invokeGetBookService(String isbn) { System.out.println("****Invoking the Get Book Service****"); Client client = ClientBuilder.newClient(); WebTarget target = client.target("http://localhost:8080/RestfulDemo/rs/book/" + isbn); Response response = target.request().buildGet().invoke(); Book book = response.readEntity(Book.class); printBook(book); } private static void invokeCreateBookService() { System.out.println("****Invoking the Create Book Service****"); Calendar calendar = Calendar.getInstance(); Date today = calendar.getTime(); calendar.add(Calendar.DATE, -4); Date olderDay1 = calendar.getTime(); Book book = new Book(); book.authors = Arrays.asList("Gayle Laakmann McDowell"); book.binding = Binding.PAPERBACK; book.isbn = "9788126538058"; book.numberOfPages = 280; book.price = 260.0; book.publisher = "Wiley/Goels Computer Hut"; book.title = "The Google Resume: How to Prepare for a Career and land a Job at Apple, Microsoft, Google, or Any Top Tech Company"; book.year = 2012; book.reviews = (Arrays.asList(new Review("Very Precise and handy", "Shameer", today, Rating.FOUR), new Review("Best guide for cover letters, resumes etc", "Harshith", olderDay1, Rating.FIVE))); Client client = ClientBuilder.newClient(); WebTarget target = client.target("http://localhost:8080/RestfulDemo/rs/book"); Response response = target.request().buildPost(Entity.entity(book, MediaType.APPLICATION_XML)).invoke(); System.out.println(response.getLocation().getPath()); } private static String joinList(List list) { StringBuilder builder = new StringBuilder(); for (String str : list) { builder.append(str).append(","); } return builder.toString().substring(0, builder.length() - 1); } private static void printBook(Book book) { System.out.println("Details for: " + book.title); System.out.println("Author: " + joinList(book.authors)); System.out.println("ISBN: " + book.isbn); System.out.println("Publisher: " + book.publisher); System.out.println("Cost: " + book.price); System.out.println("Publication year: " + book.year); System.out.println("Reviews: "); for (Review review : book.reviews) { System.out.println(review.content + " by " + review.author + " posted on " + review.getPostedOn()); } } }
I am not printing the output here because the output contains the complete XML structure which will be huge. If you want to access this complete sample you can fork the Github repository at: https://github.com/javabeat/javaee7-restdemo and load the project in Netbeans 7.3+ with JavaEE 7 support.
Do let me know if you are unable to get the code working or understand something from the code. I hope you have learned about how to develop restful web services in java.
also read: