JavaCreating RESTful Web Services with JAX-RS

Creating RESTful Web Services with JAX-RS

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Creating RESTful Web Services with JAX-RS

RESTful (Representational State Transfer) Web Services are not protocol specific. The orchestra of intermingling technologies working together in SOAP is absent here. Plain and simple, REST is built over HTTP for a distributed, collaborative, document based system. Information is regarded as ‘resources’ addressed through URI (Uniform Resource Identifier). Obviously, a one line explanation would be a ludicrous definition of such a robust and extensible architecture. Refer to Fielding’s PhD dissertation for an in depth understanding. Here we focus on ‘creating JAX-RS’, the RESTful implementation of Java. Readers may also refer – Creating SOAP Web Service with JAX-WS to appreciate the differences and similarities in creating ‘Web Services’ in SOAP (JAX-WS) and REST (JAX-RS).

 

JAX-RS RESTful communication between Client and Server
Fig 1: JAX-RS RESTful communication between Client and Server

Note: The examples given below are implemented in JDK-jdk7, App Server-Glassfish4.0, IDE-Netbeans (Eclipse is also great, but you may be boggled by configuration issues…). There is a wizard for creating a RESTful resource server as well as its client counterpart in Netbeans. This may be the easy way to build one but not the very best, especially for a newbie. However, people make their own choices. I believe, if one is to learn programming there is only one way – the hard way 🙂

Writing JAX-RS Web Service from Scratch

In the example we will have a library database in MySQL. EJB and JAX-RS will perform data operations with the help of EclipseLink, JPA provider. The Java annotation provided by JAX-RS helps to bind specific URI patterns and HTTP operations to specific methods of Java classes. The parameter injection annotation such as @GET, @PUT, @POST, etc. helps in pulling information from the HTTP request. Here we will define a JAX-RS service that allows us to perform read and create operations on the database. In fact, we will have two projects:

  • Project 1: Producing HTTP operation through Web Service as a server (JAX-RS Server)
  • Project 2: A remote client consuming HTTP responses as a client (JAX-RS Client).

Project 1: (JAX-RS Server)

Let’s implement the server or resource producer first. Here, we will have four classes, namely, Book.java, Books.java, BookService.java and ApplicationConfig.java.

Entity Class

This simple Java class represents the Book entity and maps the BOOK_LIB table into the database. The JPA annotation @Entity makes any simple POJO a persistence class. Persistence provider, EclipseLink, which comes bundled with Glassfish, recognizes it and transforms it into an entity from simple POJO. @Id defines the unique identifier or primary key of the relation. @GeneratedValue represents that the unique identifier is auto generated by the database. @NamedQuery defines a static query, which in our case is used to retrieve a list of books from the database. Since we will be using XML transformation for data communication, it is a good idea to use @XmlRooElement, a JAXB annotation that allow us to map the Java class directly to XML.

Listing 1: Book.java

package org.mano.dto;
 
//... import statements
 
@Entity
@Table(name="BOOK_LIB")
@NamedQuery(name="Book.findAll", query="SELECT b FROM Book b ORDER BY b.id")
@XmlRootElement
public class Book implements Serializable {
       private static final long serialVersionUID = 1L;
       
       @Id @GeneratedValue 
       private String id;
       private String isbn;
       private String title;
       private String author;
       private String publisher;
       private String edition;
       private Float price;
       private String description;
 
       //...constructors, getters and setters
}

JAXB Class

We will use this utility class more for convenience sake than necessity. This class helps in JAXB marshalling, since we will be retrieving all the books from the database through a RESTful function, this class will help in representing the fetched list to XML data.

Listing 2: Books.java

package org.mano.jaxb;
 
//...import statements
 
@XmlRootElement
@XmlSeeAlso(Book.class)
public class Books extends ArrayList<Book> {
       private static final long serialVersionUID = 1L;
       public Books() {
        super();
    }
    public Books(Collection<? extends Book> c) {
        super(c);
    }
    @XmlElement(name = "book")
    public List<Book> getBooks() {
        return this;
    }
    public void setBooks(List<Book> books) {
        this.addAll(books);
    }
}

JAX-RS Class

This is our main JAX-RS class. Any POJO can be transformed into RESTful Web Service with the annotation @Path. The “/book” represents the URI path in the sense that if http://xyzwebsite.com is a URI then http://xyzwebsite.com/book will be the URI to access this particular RESTful web service. Annotation @Produces and @Consumes define the default content type that this resource produces and consumes. In our case this class can handle both XML and JSON types of content, though we will be using only XML here. The @Stateless annotation informs the Application Server container to treat it as an EJB as well. In this class a reference to EntityManager is made with the help of @PersistenceContext and UriInfo injected into it with the annotation @Inject. EntityManager acts as the JPA interface of EclipseLink and UriInfo retrieves the URI path. @POST, @GET, etc. defines HTTP POST, GET methods through Java annotation to create a new resource in XML or JSON.

Listing 3: BookService.java

package org.mano.rest.service;
 
//...import statements
 
@Path("/book")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Stateless
public class BookService {
       
       @PersistenceContext(unitName="LibraryServer_JAXRS")
       EntityManager entityManager;
       @Context
       private UriInfo uriInfo;
 
       @POST
       public Response createBook(Book book) {        
             entityManager.persist(book);
             URI uri = uriInfo.getAbsolutePathBuilder().path(book.getId().toString()).build();
             return Response.created(uri).build();
       }
 
       @DELETE
       @Path("{id}")
       public Response deleteBook(@PathParam("id") String id) {
             entityManager.remove(entityManager.find(Book.class, id));
             return Response.noContent().build();
       }
 
       @GET
       @Path("{id}")
       public Response getBook(@PathParam("id") String id) {
             Book book = entityManager.find(Book.class, id);
             if (book == null) {
                    throw new NotFoundException();
             }
             return Response.ok(book).build();
       }
 
       @GET
       public Books getBooks() {               
             TypedQuery<Book> query = entityManager.createNamedQuery("Book.findAll",Book.class);
             Books books=new Books(query.getResultList());
             return books;
             //return Response.ok(books).build();
       }
}

JAX-RS Registration Class

This class is used to register a URL pattern in Jersey to intercept HTTP calls to the service. The marshaller, Jersey intercepts the path given in @ApplicationPath annotation such as – @ApplicationPath(“rest”). So our URI for calling GET service of the resource ‘book’ will be http://xyzwebsite.com/rest/book or if you are using a local host server then: http://localhost:8080/your_JAX-RS_project_name/rest/book. This class extends javax.ws.rs.core.Application. All the RESTful web services and extensions needed are registered here, such as the JAX-RS class is added with c.add(BookService.class) and extension with c.add(jsonProvicer).

Listing 4:ApplicationConfig.java

package org.mano.rest.service;
 
//..import statements
 
@ApplicationPath("rest")
public class ApplicationConfig extends Application {
 
    private final Set<Class<?>> classes;
 
    public ApplicationConfig() {
        HashSet<Class<?>> c = new HashSet<>();
        try {
            Class jsonProvider = Class.forName("org.glassfish
                    .jersey.jackson.JacksonFeature");
            c.add(jsonProvider);
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(
                    getClass().getName())
                    .log(java.util.logging.Level.SEVERE, null, ex);
        }
        c.add(BookService.class);        
        classes = Collections.unmodifiableSet(c);
    }
 
    @Override
    public Set<Class<?>> getClasses() {
        return classes;
    }
}

Writing REST Web Service Client from Scratch

Though any programming language that has support for HTTP is good enough to create a RESTful web service consumer, Client API provided in JAX-RS 2.0 is a welcome addition. JAX-RS is no longer just a server side framework, it now provides a client side framework for writing Web Services as well.

Project 2: (JAX-RS Client)

Our client project will have three classes: Book.java, BookRestClient.java, BookController.java and two Facelet XHTML files: layout.xhtml and index.xhtml.

Backing Bean Class

Book class represents our backing bean class; nothing extraordinary here.

Listing 5: Book.java

package org.mano.mbean;
 
//...import statements
 
@XmlRootElement
public class Book {
 
    private String id;
    private String isbn;
    private String title;
    private String author;
    private String publisher;
    private String edition;
    private Float price;
    private String description;
 
//... constructors, getters and setters
    
}

JAX-RS Client Class

This class uses the JAX-RS 2.0 client API framework and our main RESTful client class. Here, observe that method invocations are chained together to configure and submit requests to the REST resource. The simplest way to configure a client is through ClientBuilder, and URI through UriBuilder class provided by the JAX-RS Client API framework. Once the connection has been established, adding a new book or deleting one is simply a matter of calling the right GET, DELETE HTTP methods.

Listing 6: BookRestClient.java

package org.jaxrs.client;
 
//...import statements
 
@Stateless
public class BookRestClient {
       private URI uri;
       private Client client;
       public BookRestClient() {
             uri = UriBuilder
             .fromUri("http://localhost:8080/LibraryServer_JAXRS/rs/book")
             .port(8080).build();              
             client = ClientBuilder.newClient();
       }
       
       public String addNewBook(Book book){
             Response response = client.target(uri)
             .request()
             .post(Entity.entity(book,MediaType.APPLICATION_XML));
             return response.getStatusInfo().getReasonPhrase();
       }
       
       public List<Book> getBooks(){
             List<Book> books = client.target(uri)
             .request()
             .get(new GenericType<List<Book>>(){});
             return books;
       }
       
       public void close(){
             client.close();
       }
}

JSF Controller Class

This is a usual JSF controller class written for Faces pages. The only different annotation used here is CDI @Inject. Observe that we have defined the BookRestClient class as an EJB with @Stateless annotation. The @Inject annotation informs the container that it has to inject a reference of the EJB class into BookController property so that we can call BookRestClient’s function as per our requirement in the controller class.

Listing 7: BookController.java

 
package org.mano.mbean;
 
//...import statements
 
@Named(value = "bk")
@RequestScoped
public class BookController {
    @Inject
    private BookRestClient rc;
    private Book book = new Book();
    List<Book> books = new ArrayList<>();
    FacesContext facesContext = FacesContext.getCurrentInstance();
 
    public BookController() {
    }
 
    public Book getBook() {
        return book;
    }
 
    public void setBook(Book book) {
        this.book = book;
    }
 
    public String addNewBook() {
        String status = "";
        try {
            if (validate()) {
                status = rc.addNewBook(book);
                facesContext
                    .addMessage(status, new FacesMessage(
                    FacesMessage.SEVERITY_INFO, 
                    "New Book added successfully", 
                    book.toString()));
            }
        } catch (Exception ex) {
            facesContext
             .addMessage(status, new FacesMessage(
             FacesMessage.SEVERITY_ERROR, 
             "New Book cannot be added", ex.getMessage()));
        }
        books = getAllBooks();
        return status;
    }
 
    public List<Book> getAllBooks() {        
        books = rc.getBooks();
        return books;
    }
    
    public void getBookById(){
        book = rc.getBook(book.getId());
    }
 
    private boolean validate() {
        if (book.getIsbn() == null || book.getIsbn().trim().isEmpty()) {
            facesContext.addMessage("form:isbn", 
             new FacesMessage(FacesMessage.SEVERITY_WARN, 
             "Invalid ISBN", "Please enter a valid ISBN number"));
        }
        if (book.getTitle() == null || book.getTitle().trim().isEmpty()) {
            facesContext.addMessage("form:title", 
             new FacesMessage(FacesMessage
             .SEVERITY_WARN, "Invalid Title", 
             "Please enter a valid title"));
        }
        if (!facesContext.getMessageList().isEmpty()) {
            return false;
        } else {
            return true;
        }
    }
}

JSF Template File

This is the layout template of the JSF page we will be using in index.xhtml. This page includes a CSS stylesheet, which has not been given here due to brevity. The line <link href=”./resources/css/mystyle.css” rel=”stylesheet” type=”text/css”/> has been commented out; as a result the functionality of the project remains same at the cost of looks becoming dull.

Listing 8: layout.xhtml

<xml?...>
    <h:head> <meta ... />
     <!-- <link href="./resources/css/mystyle.css" rel="stylesheet" type="text/css" /> -->
     <title><ui:insert name="title">Mini Library</ui:insert></title>
    </h:head>
    <h:body>
    <div id="top">
    <ui:insert name="top">Welcome to My MiniLibrary Application</ui:insert>
    </div>
    <div id="content" class="center_content">       
    <ui:insert name="content">Default content</ui:insert>            
    </div>
    <div id="bottom">
    <h:outputText value="A sample project to demonstrate JAX-RS Web Service client" style="font-style: italic"/>
    </div>
</h:body></html>

JSF file

This is the main client user interface of JAX-RS Client using Java Server Faces. The looks of the output file is given in Fig 2.

listing 9: index.xhtml

<xml?...><body> <center>
<ui:composition template="./layout.xhtml">
<ui:define name="content">                                
<h:form id="form">
<h:panelGrid columns="2">
<h:outputLabel value="Title : "/>
<h:inputText id="title" value="#{bk.book.title}"/>
                    [... ommitted for brevity]
<h:outputLabel value="Description : "/>
<h:inputTextarea id="description" value="#{bk.book.description}" cols="36" rows="3"/>                    
</h:panelGrid>
<h:commandButton value="Add New Book" action="#{bk.addNewBook()}">
<f:ajax execute="@form" render=":booklist :errors"/>
</h:commandButton>
</h:form>                          
<h:dataTable id="booklist" value="#{bk.allBooks}" var="b">
<h:column>
<f:facet name="header">
<h:outputText value="Title"/>
</f:facet>                 
<h:outputText value="#{b.title}"/>
</h:column>
                    [... ommitted for brevity]
<h:column>
<f:facet name="header">
<h:outputText value="Description"/>
</f:facet>
<h:outputText value="#{b.description}"/>
</h:column>
</h:dataTable>
</ui:define>
</ui:composition>
</center>
</body>
</html>

 

Book input form and data table display of all the books
Fig 2: Book input form and data table display of all the books

Conclusion

Creating RESTful Web Services in JAX-RS is pretty straightforward compared to SOAP. The article tries to give a simple but elaborate description in creating one. But in doing so, many concepts have been overlooked and unexplained to make it concise. Nonetheless, one can have a firsthand look at the intricacies of JAX-RS in creating one and appreciate its parallel technology JAX-WS as well.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories