TOTD #8: Generating JSON using JAXB annotations in Jersey
Posted by arungupta on September 10, 2007 at 06:11 AM | Comments (4)
Jersey provides a
pluggable
type system for the encoding/decoding of a Java type to/from an entity of an
HTTP response/request.
JSON
support was added in Jersey using the
BadgerFish convention for encoding/decoding
JAXB beans to/from JSON. A new
sample was also added in the
recently released
0.2.1 that demonstrates this concept.
This TOTD provides provides a trivial sample (using the snippets shown on
BadgerFish) that will allow you to
experiment with this feature in Jersey. This sample consists of a Resource,
Server and "build.xml" to build, deploy, run the server and invoke
the endpoint.
Here is the code for the REST resource:
import javax.ws.rs.HttpMethod;
import javax.ws.rs.ProduceMime;
import javax.ws.rs.UriTemplate;
@UriTemplate("/helloworld")
public class HelloWorldResource {
@HttpMethod
@ProduceMime("application/xml")
@UriTemplate("/xml")
public States getXML() {
return new alice();
}
@HttpMethod
@ProduceMime("application/json")
@UriTemplate("/json")
public States getJSON() {
return new alice();
}
}
This resource is published on two URIs - one using XML (/xml)
and the other using JSON (/json) representation. Here is the code
to start the server:
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.ws.rest.api.container.ContainerFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
public class HelloWorld {
public static void main(String[] args) throws IOException {
HttpHandler handler = ContainerFactory.createContainer(
HttpHandler.class,
HelloWorldResource.class);
HttpServer server = HttpServer.create(new
InetSocketAddress(9998), 0);
server.createContext("/", handler);
server.setExecutor(null);
server.start();
System.out.println("Server running");
System.out.println("Visit: http://localhost:9998/helloworld");
System.out.println("Hit return to stop...");
System.in.read();
System.out.println("Stopping server");
server.stop(0);
System.out.println("Server stopped");
}
}
This is a very standard code that is available in all the bundled samples.
And here is the "build.xml":
<project name="json" default="default" basedir=".">
<property name="jersey.home" value="c:\jersey-0.2.1-ea"/>
<path id="jersey.classpath">
<fileset dir="${jersey.home}\lib" includes="*.jar"/>
</path>
<property name="build.dir" value="build"/>
<property name="src.dir" value="src"/>
<target name="init">
<mkdir dir="${build.dir}"/>
</target>
<target name="build" depends="init">
<javac srcdir="${src.dir}" destdir="${build.dir}"
includes="**/*.java">
<classpath refid="jersey.classpath"/>
</javac>
</target>
<target name="run" depends="build">
<java classname="samples.HelloWorld" fork="true">
<classpath>
<path refid="jersey.classpath"/>
<pathelement location="${build.dir}"/>
</classpath>
</java>
</target>
<target name="get-json">
<get src="http://localhost:9998/helloworld/json" dest="out.json"/>
</target>
<target name="get-xml">
<get src="http://localhost:9998/helloworld/xml" dest="out.xml"/>
</target>
<target name="clean">
<delete quiet="true" dir="${build.dir}"/>
</target>
</project>
Make sure to set the value of "jersey.home" property correctly
in this file. And now the JAXB bean and corresponding XML and JSON
representation:
| JAXB Bean |
XML representation |
JSON representation |
@javax.xml.bind.annotation.XmlRootElement
public class alice {
@javax.xml.bind.annotation.XmlValue
protected String value;
public alice() { this.value = "bob"
}
public String getValue() {
return value;
}
} |
<alice>bob</alice>
|
{"alice":{"$":"bob"}} |
@javax.xml.bind.annotation.XmlRootElement
public class alice {
@javax.xml.bind.annotation.XmlElement
protected String bob;
@javax.xml.bind.annotation.XmlElement
protected String david;
public alice() {
bob = "charlie";
david = "edgar";
}
public String getBob() { return bob; }
public String getDavid() { return david; }
} |
<alice>
<bob>charlie</bob>
<david>edgar</david>
</alice> |
{"alice":{"bob":{"$":"charlie"},"david":{"$":"edgar"}}} |
@javax.xml.bind.annotation.XmlRootElement
public class alice {
@javax.xml.bind.annotation.XmlValue
protected String value;
@javax.xml.bind.annotation.XmlAttribute
protected String charlie;
public alice() {
value = "bob";
charlie = "david";
}
public String getValue() { return value; }
public String getCharlie() { return charlie; }
} |
<alice charlie="david">
bob
</alice> |
{"alice":{"@charlie":"david","$":"bob"}} |
@javax.xml.bind.annotation.XmlRootElement(namespace="http://some-namespace")
public class alice {
@javax.xml.bind.annotation.XmlValue
protected String value;
public alice() { value = "bob"; }
public String getValue() { return value; }
} |
<alice xmlns="http://some
-namespace">
bob
</alice> |
{"alice":{"@xmlns":{"$":"http:\/\/some-namespace"},"$":"bob"}} |
@javax.xml.bind.annotation.XmlRootElement
public class alice {
@javax.xml.bind.annotation.XmlElement
protected java.util.List<String> bob;
public alice() {
bob = new java.util.ArrayList<String>();
bob.add("charlie");
bob.add("david");
}
public java.util.List<String> getBob() { return bob; }
} |
<alice>
<bob>charlie</bob>
<bob>david</bob>
</alice> |
{"alice":{"bob":[{"$":"charlie"},{"$":"david"}]}} |
JSON representation can always be constructed using the JSON APIs as shown
below and by adding the method to "HelloWorldResource":
import org.codehaus.jettison.json.*;
@HttpMethod("GET")
@ProduceMime("application/json")
@UriTemplate("/json2")
public JSONObject getJSONMessage() throws JSONException {
JSONObject object = new JSONObject();
JSONObject content = new JSONObject();
content.put("$", "bob");
object.put("alice", content);
return object;
}
JAX-WS also supports JSON as a
pluggable encoding.
Please leave suggestions on other TOTD that you'd like to see. A complete
archive is available here.
Technorati:
totd
jersey
json
jax-ws
REST
pluggableencoding
restful
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
There is a mistake I believe here in alice..
public States() { this.value = "bob" }
Otherwise, a great tutorial and a great technology.
Posted by: ivan_memruk on September 10, 2007 at 10:46 PM
-
Glad you liked it. It seems you are talking about 4th alice. "this" is implicit so wondering which of these you think is a mistake.
Posted by: arungupta on September 10, 2007 at 11:14 PM
-
talking about the first alice. the constructor name should be alice() not States(), or I am missing something.
Posted by: ivan_memruk on September 11, 2007 at 03:41 AM
-
ah I see, now fixed, thanks!
Posted by: arungupta on September 11, 2007 at 05:56 AM
|