17.4. JAXB and JSON provider

RESTEasy lets you marshal JAXB annotated POJOs to and from JSON with the Jettison JSON library. You can find more information about Jettison at http://jettison.codehaus.org/.
Jettison has two mapping formats: the default Jettison Mapped Convention format, and BadgerFish.
For example, consider this JAXB class:
@XmlRootElement(name = "book")
public class Book {

   private String author;
   private String ISBN;
   private String title;

   public Book() {
   }

   public Book(String author, String ISBN, String title) {
      this.author = author;
      this.ISBN = ISBN;
      this.title = title;
   }

   @XmlElement
   public String getAuthor() {
      return author;
   }

   public void setAuthor(String author) {
      this.author = author;
   }

   @XmlElement
   public String getISBN() {
      return ISBN;
   }

   public void setISBN(String ISBN) {
      this.ISBN = ISBN;
   }

   @XmlAttribute
   public String getTitle() {
      return title;
   }

   public void setTitle(String title) {
      this.title = title;
   }
}


The JAXB Book class would be marshaled to JSON using the BadgerFish Convention:
 {"book":
    {
       "@title":"EJB 3.0",
       "author":{"$":"Bill Burke"},
       "ISBN":{"$":"596529260"}
    }
 }
Element values are associated with a map. To find the value of the element, you must access the $ variable. You could access the book like this, in JavaScript:
 var data = eval("(" + xhr.responseText + ")");
 document.getElementById("zone").innerHTML = data.book.@title;
 document.getElementById("zone").innerHTML += data.book.author.$;
To use the BadgerFish Convention you must use the @org.jboss.resteasy.annotations.providers.jaxb.json.BadgerFish annotation either on the JAXB class you are marshaling or unmarshaling, or on the JAX-RS resource method or parameter:
 @BadgerFish
 @XmlRootElement(name = "book")
 public class Book {...}
To return a book on the JAX-RS method without polluting your JAXB classes with RESTEasy annotations, you can add the annotation to the JAX-RS method instead:
 @BadgerFish
 @GET
 public Book getBook(...) {...}
If your input is a Book, place it on the parameter:
 @POST
 public void newBook(@BadgerFish Book book) {...}
The default Jettison Mapped Convention returns the following JSON:
 { "book" :
      {
         "@title":"EJB 3.0",
         "author":"Bill Burke",
         "ISBN":596529260
       }
 }
Note that title is prefixed with the @ character. Unlike the BadgerFish convention, this does not represent the value of element text, which makes it simpler (and a sensible default). To access this in JavaScript:
 var data = eval("(" + xhr.responseText + ")");
 document.getElementById("zone").innerHTML = data.book.@title;
 document.getElementById("zone").innerHTML += data.book.author;
The Mapped Convention lets you adjust the JAXB mapping with the @org.jboss.resteasy.annotations.providers.jaxb.json.Mapped annotation. With this, you can provide an XML namespace to JSON namespace mapping. For example, if you define your JAXB namespace within your package-info.java class like so:
 @javax.xml.bind.annotation.XmlSchema(namespace="http://jboss.org/books")
 package org.jboss.resteasy.test.books;
You must define a JSON-to-XML namespace mapping, or you will receive an exception:
java.lang.IllegalStateException: Invalid JSON namespace:
  http://jboss.org/books
at org.codehaus.jettison.mapped.MappedNamespaceConvention
  .getJSONNamespace(MappedNamespaceConvention.java:151)
at org.codehaus.jettison.mapped.MappedNamespaceConvention
  .createKey(MappedNamespaceConvention.java:158)
at org.codehaus.jettison.mapped.MappedXMLStreamWriter
  .writeStartElement(MappedXMLStreamWriter.java:241)
The @Mapped annotation fixes this problem. Place the @Mapped annotation on your JAXB classes, your JAX-RS resource method, or on the parameter that you are unmarshaling.
 import org.jboss.resteasy.annotations.providers.jaxb.json.Mapped;
 import org.jboss.resteasy.annotations.providers.jaxb.json.XmlNsMap;

 ...

@GET
@Produces("application/json")
@Mapped(namespaceMap = {
        @XmlNsMap(namespace = "http://jboss.org/books", jsonName = "books")
})
public Book get() {...}

You can also force @XmlAttributes to be marshaled as XMLElements.
            @Mapped(attributeAsElements={"title"})
            @XmlRootElement(name = "book")
            public class Book {...}
To return a book on the JAX-RS method without polluting your JAXB classes with RESTEasy annotations, add the annotation to the JAX-RS method:
            @Mapped(attributeAsElements={"title"})
            @GET
            public Book getBook(...) {...}
If your input is a Book, place it on the parameter:
 @POST
 public void newBook(@Mapped(attributeAsElements={"title"}) Book book) {...}