Friday, October 4, 2013

REST Service on JBoss 7 (using RESTEasy) - Part 3

In the last post we learnt how to output JSON from a REST service. Here is the sample JSON output that we got in the last post.

[
    {
        "name": "Java The Complete Reference, 8th Edition",
        "author": "Herbert Schildt",
        "price": 479
    },
    {
        "name": "Jboss As 7 Configuration, Deployment, And Administration",
        "author": "Francesco Marchioni",
        "price": 450
    },
    {
        "name": "RESTful Java with JAX-RS 2.0 2ed",
        "author": "Bill Burke",
        "price": 2018
    }
]

RESTEasy (default JAX-RS provider for JBoss AS 7) uses Jackson as the JSON provider. What if your clients are using Jettison for parsing the response from your REST service?

Hold on. What is the difference between Jackson and Jettison? Here are a few differences.
  • Jettison relies on JAXB annotation (such as @XmlRootElememt); doesnt need any JSON specific annotation. Jackson uses its own annotations (such as @JsonIgnore, etc). What this means is, by simply using JAXB annotation you will be able to generate same response in XML and JSON format if you use Jettison. You need additional annotations to achieve this if you use Jackson.
  • Jettison produces XML compliant JSON content; Jackson does not. If you look at the above JSON, there is no root element (remember a valid XML document requires one root element)
Output produced by one of them, can't be consumed by the other.

Many times you may not have the control over what your clients use. Let's see how we can use Jettison as our JSON provider.

1. Since we needed a root element, let add a class to wrap the list of books. Let's call it as BookResponse. Copy paste the following contents into it.
package org.jbosstest.jbosstest;

import java.io.Serializable;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "bookResponse")
public class BookResponse implements Serializable {

    private List<Book> books;

    public BookResponse() {
    }

    public BookResponse(List<Book> books) {
        this.books = books;
    }

    @XmlElementWrapper(name = "books")
    @XmlElement(name = "book")
    public List<Book> getBooks() {
        return books;
    }

    public void setBooks(List<Book> books) {
        this.books = books;
    }
}

2. Modify the Book class as below
package org.jbosstest.jbosstest;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "book")
public class Book implements Serializable {

    private String name;
    private String author;
    private float price;

    public Book() {
    }

    public Book(String name, String author, float price) {
        this.name = name;
        this.author = author;
        this.price = price;

    }

    // getter-setter methods
}

3. Modify the LibraryService class as follows.
package org.jbosstest.jbosstest;

import java.util.ArrayList;
import java.util.List;
import javax.ejb.LocalBean;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@LocalBean
@Path("/library")
public class LibraryService {

    @GET
    @Path("available-books")
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public BookResponse getAvailableBooks() {
        List<Book> books = new ArrayList<Book>();
        books.add(new Book("Java The Complete Reference, 8th Edition", "Herbert Schildt", 479));
        books.add(new Book("Jboss As 7 Configuration, Deployment, And Administration", "Francesco Marchioni", 450));
        books.add(new Book("RESTful Java with JAX-RS 2.0 2ed", "Bill Burke", 2018));
        return new BookResponse(books);
    }
}

4. Now we need to include Jettison and exclude Jackson from the list of providers. Create a file called jboss-deployment-structure.xml under WEB-INF folder and paste the following contents into it.
<?xml version="1.0" encoding="UTF-8"?>

<jboss-deployment-structure  xmlns="urn:jboss:deployment-structure:1.2">
    <deployment>
        <exclusions>
            <module name="org.jboss.resteasy.resteasy-jackson-provider"/>
        </exclusions>
        <dependencies>
            <module name="org.jboss.resteasy.resteasy-jaxb-provider" services="import"/>
            <module name="org.jboss.resteasy.resteasy-jettison-provider" services="import"/>
            <module name="org.codehaus.jettison"/>
        </dependencies>
    </deployment>
</jboss-deployment-structure>


5. Build and run the project.
6. This time let's use postman, a chrome/chromium plugin, to test both JSON and XML output. So let's open chromium postman as follows and specify accept-header value as application/xml and the URL as http://localhost:8080/JbossTest/webresources/library/available-books and hit Send.



 7. Change the accept-header value to application/json and hit Send again.