Friday Feb 13, 2009

Configuring JSON for RESTful Web Services in Jersey 1.0.2

This is an update for a tech tip on configuring JSON in Jersey, which i wrote in October 2008. The way of JSON configuration, suggested in the tech tip, is now deprecated (but still functioning). Here i would like to describe the new API, which will hopefully last (and be supported) a way longer.

Notice: you will need to bundle jaxb-impl-2.1.10.jar with your application in order to take advantage of the recently added JSON NATURAL convention

Deprecated Configuration

Configuring JSON format, as described in the tech tip, meant to implement a JAXBContext resolver class returning an instance of JSONJAXBContext. This principle have not changed. What changed is a way, how the JSONJAXBContext itself is being configured. Lets look at the sample code below (using the deprecated API):

   @Provider
   public class MyJAXBContextResolver implements ContextResolver<JAXBContext> {

       private JAXBContext context;
       private Class[] types = {StatusInfoBean.class, JobInfoBean.class};

       public MyJAXBContextResolver() throws Exception {
           Map props = new HashMap<String, Object>();
           props.put(JSONJAXBContext.JSON_NOTATION, JSONJAXBContext.JSONNotation.MAPPED);
           props.put(JSONJAXBContext.JSON_ROOT_UNWRAPPING, Boolean.TRUE);
           props.put(JSONJAXBContext.JSON_ARRAYS, new HashSet<String>(1){{add("jobs");}});
           props.put(JSONJAXBContext.JSON_NON_STRINGS, new HashSet<String>(1){{add("pages"); add("tonerRemaining");}});
           this.context = new JSONJAXBContext(types, props);
       }

       public JAXBContext getContext(Class<?> objectType) {
           return (types[0].equals(objectType)) ? context : null;
       }
   }

There you needed to create a property bag, put appropriate configuration options into it, and then pass it to the JSONJAXBContext constructor.

Jersey 1.0.2 JSON Configuration

In the currently available 1.0.2 Jersey version, a new JSONConfiguration class was introduced to became a central point for JSON configuration options. For creating a new JSONConfiguration instance, a builder pattern is employed. It is not only more user friendly, but also ensures only meaningful JSON options could be combined together. You can compare the following code, with the deprecated example above:

   @Provider
   public class MyJAXBContextResolver implements ContextResolver<JAXBContext> {

       private JAXBContext context;
       private Class[] types = {StatusInfoBean.class, JobInfoBean.class};

       public MyJAXBContextResolver() throws Exception {
           this.context = new JSONJAXBContext(
                   JSONConfiguration.mapped()
                                      .rootUnwrapping(true)
                                      .arrays("jobs")
                                      .nonStrings("pages", "tonerRemaining")
                                      .build(),
                   types);
       }

       public JAXBContext getContext(Class<?> objectType) {
           return (types[0].equals(objectType)) ? context : null;
       }
   }

You can look at JSONConfiguration javadoc for detailed information on various configuration options.

Further Simplification

If you go a bit further, you can ask if the configuration could be simplified even more. Imagine you have much bigger number of JAXB beans in your model, and they are more complex. It could easily become unmanageable to maintain a reasonable JSON configuration as described so far. Then if you happen to have conflicting non-string/string values and/or arrays/non-arrays elements in your set, you could easily run out of options there.

A natural way to overcome above mentioned issues, is to simply use recently introduced Jersey NATURAL JSON notation. Then you need only to:

   @Provider
   public class MyJAXBContextResolver implements ContextResolver<JAXBContext> {

       private JAXBContext context;
       private Class[] types = {StatusInfoBean.class, JobInfoBean.class};

       public MyJAXBContextResolver() throws Exception {
           this.context = new JSONJAXBContext(
                   JSONConfiguration.natural().build(),
                   types);
       }

       public JAXBContext getContext(Class<?> objectType) {
           return (types[0].equals(objectType)) ? context : null;
       }
   }

Such configuration is simple from user point of view, but yet very powerful. You do not need to keep various configuration options in sync with your actual JAXB beans, and be worried what options to actually use (what exact names, etc.). Jersey will automatically take care about serializing Java collections/arrays as JSON arrays, Java booleans as JSON booleans, Java ints as JSON integers,and so on.

Monday May 26, 2008

Workarounding Cross-domain Restriction With Jersey

Having a JSON generating REST resource, you can consume provided
data in your web page using JavaScript pretty easily. To access data
at your own site you can obviously make a HttpRequest from JavaScript code.
To access data from another site, you will need to workaround
a cross-domain restriction somehow. Two possible approaches are described
at Dan Theurer's blog entries here and here.

In this entry i will show how to add the JavaScript representation option to your Jersey based REST resource, so that besides


{ some JSON data}

when your client asks for http://.../myResource.json,
you will be able to return also something like

myFunc({ some JSON data})

when it asks for http://.../myResource.js?callback=myFunc...

[Read More]

Friday Feb 22, 2008

Better JSON Available In Jersey

Since today a better support for JSON data generated out of JAXB beans is available in Jersey.

The main improvement is a simpler default JSON data format.
Badgerfish convention was replaced by a new one, a slightly simplified so called mapped convention from Jettison. JSON convention used for particular beans is now also fully configurable by the end user.
I will show how the configuration could be done below.

The main differences between available formats could be described using the following example.
Lets start with a very simple JAXB bean. You can see the source code, XML output and then
all formats you can get from Jersey resource:


@XmlRootElement
public static class SimpleJaxbBean {
public String name = "Franz";
public String surname = "Kafka";
}

XML output:


<simpleJaxbBean>
<name>Franz</name>
<surname>Kafka</surname>
</simpleJaxbBean>

Badgerfish format:


{"simpleJaxbBean":{"name":{"$":"Franz"},"surname":{"$":"Kafka"}}}

Mapped format (Jettison):


{"simpleJaxbBean":{"name":"Franz","surname":"Kafka"}}

and finally Jersey default format:


{"name":"Franz","surname":"Kafka"}

If you want to control, which format is actually used for which JAXB bean,
you can do it by providing Jersey runtime with your own custom JAXBContext classes
via implementing custom ContextResolver.

You can get inspired by following example:


@Path("/jsonFormats")
public class SimpleJsonResource {
@Provider
public static class JAXBContextResolver implements ContextResolver<JAXBContext> {

private JAXBContext context;
private Class[] types = {SimpleJaxbBean.class};

public JAXBContextResolver() throws Exception {
Map<String, Object> props = new HashMap<String, Object>();
props.put(JSONJAXBContext.JSON_NOTATION, "MAPPED_JETTISON");
props.put(JSONJAXBContext.JSON_ROOT_UNWRAPPING, Boolean.FALSE);
this.context = new JSONJAXBContext(types, props);
}

public JAXBContext getContext(Class<?> objectType) {
return (types[0].equals(objectType)) ? context : null;
}
}

@XmlRootElement
public static class SimpleJaxbBean {
public String name = "Franz";
public String surname = "Kafka";
}

@GET
@ProduceMime({"application/json", "application/xml"})
public SimpleJaxbBean getJson() {
return new SimpleJaxbBean();
}
}

The following options are available for the JSONJAXBContext.JSON_NOTATION
property, where the first one is the default value:


  • MAPPED
  • MAPPED_JETTISON
  • BADGERFISH

In the future i plan to add more properties so that the JSON serialization and deserialization
is highly configurable.

Friday Aug 31, 2007

JSON Representation of JAXB Object Sample

To help people understand how things work it is useful to provide examples.
The blog entry contains a link to an example providing JSON data out from a JAXB object. It is build upon Jersey of course...

[Read More]
About

Jakub Podlesak

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today