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 |
|
{"alice":{"$":"bob"}} |
@javax.xml.bind.annotation.XmlRootElement |
<alice> |
{"alice":{"bob":{"$":"charlie"},"david":{"$":"edgar"}}} |
@javax.xml.bind.annotation.XmlRootElement |
<alice charlie="david"> |
{"alice":{"@charlie":"david","$":"bob"}}
|
@javax.xml.bind.annotation.XmlRootElement(namespace="http://some-namespace") |
<alice xmlns="http://some |
{"alice":{"@xmlns":{"$":"http:\/\/some-namespace"},"$":"bob"}} |
@javax.xml.bind.annotation.XmlRootElement |
<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
Related posts:- TOTD #10: Consuming JSON and XML representations generated by a Jersey endpoint in a jMaki Table widget
- TOTD #56: Simple RESTful Web service using Jersey and Embeddable GlassFish – Text and JSON output
- TOTD #57: Jersey Client API – simple and easy to use
- TOTD #91: Retrieve JSON libraries using Maven dependency: json-lib
- TOTD #58: Jersey and GlassFish – how to process POST requests ?
[Trackback] Jersey is the open source, production quality, JAX-RS (JSR 311) Reference Implementation for building RESTful Web services in the GlassFish community. It also provides an API that allows developers to extend Jersey to suite their requirements. This Ti…
Comment by Arun Gupta's Blog — November 25, 2008 @ 6:39 am
I haven been struggling fixing this import statement
import javax.ws.rs.ProduceMime;
Do you know what jar files I need for that?
Thanks
David
Comment by David — January 8, 2009 @ 11:44 am
Multiple ways:
- In NetBeans, include JAX-RS 1.0 library using Library Manager
- In GlassFish, use Update Center and pull the jars (http://blogs.sun.com/japod/entry/jersey_0_2_1_available)
- Download JARs from jersey.dev.java.net and include explicitly
Comment by Arun Gupta — January 8, 2009 @ 4:07 pm
Hi!
Does your first JAXB example really work?!
I cannot use XmlElement AND XmlValue at the same time…
com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
If a class has @XmlElement property, it cannot have @XmlValue property.
Comment by Christoph — September 18, 2009 @ 4:19 am
Christoph,
The first example uses XmlRootElement and XmlValue, the 2nd example is XmlElement. Does that clarify ?
Comment by Arun Gupta — September 18, 2009 @ 6:08 am
Does it deal with multiple arrays in an object correctly? Say that you have
@XmlRootElement
class Foo {
@Element
Collection<Bar> bars;
@Element
Collection<Qux> quxen;
}
If each of those collections contain two elements, such that the XML would be
<foo>
<bar>Tango Bar</bar>
<bar>Limbo Bar</bar>
<qux>Quxote</qux>
<qux>Of the matter</qux>
</foo>
will the resulting JSON be
{
foo: {
bar: [{"$": "Tango Bar"}, {"$": "Limbo Bar"}],
qux: [{"$": "Quxote"}, {"$": "Of the matter"}]
}
}
Not in my experience. Since the arrays are flattened in XML, it becomes
{
foo: {
bar: [{"$": "Tango Bar"}, {"$": "Limbo Bar"}, {"qux": {"$": "Quxote"}}, {"qux": {"$": "Of the matter"}}]
}
}
The elements from the second collection get included in the first collection. Bug, or simple consequence of going to XML first? You be the judge.
Comment by Lars Clausen — February 23, 2010 @ 2:11 am