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 marshalled 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 marshalling or unmarshalling, 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 unmarshalling.
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 marshalled 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) {...}