Jersey JSON support comes as a set of JAX-RS MessageBodyReader<T> and MessageBodyWriter<T> providers distributed with jersey-json module. These providers enable using three basic approaches when working with JSON format:

  • POJO support
  • JAXB based JSON support
  • Low-level, JSONObject/JSONArray based JSON support

The first method is pretty generic and allows you to map any Java Object to JSON and vice versa. The other two approaches limit you in Java types your resource methods could produce and/or consume. JAXB based approach could be taken if you want to utilize certain JAXB features. The last, low-level, approach gives you the best fine-grained control over the outcoming JSON data format.

POJO support

POJO suppport represents the easiest way to convert your Java Objects to JSON and back. It is based on the Jackson library.

To use this approach, you will need to turn the JSONConfiguration.FEATURE_POJO_MAPPING feature on. This could be done in web.xml using the following servlet init parameter:

<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>

The following snippet shows how to use the POJO mapping feature on the client side:

ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
Client client = Client.create(clientConfig);

Jackson JSON processor could be futher controlled via providing custom Jackson ObjectMapper instance. This could be handy if you need to redefine the default Jackson behaviour and to fine-tune how your JSON data structures look like. Detailed description of all Jackson features is out of scope of this guide. The example bellow gives you a hint on how to wire your ObjectMapper instance into your Jersey application.

Download jacksonjsonprovider-1.19.1-project.zip to get a complete example using POJO based JSON support.

JAXB based JSON support

Taking this approach will save you a lot of time, if you want to easily produce/consume both JSON and XML data format. Because even then you will still be able to use a unified Java model. Another advantage is simplicity of working with such a model, as JAXB leverages annotated POJOs and these could be handled as simple Java beans.

A disadvantage of JAXB based approach could be if you need to work with a very specific JSON format. Then it could be difficult to find a proper way to get such a format produced and consumed. This is a reason why a lot of configuration options are provided, so that you can control how things get serialized out and deserialized back.

Following is a very simple example of how a JAXB bean could look like.

@XmlRootElement
public class MyJaxbBean {
public String name;
public int age; public MyJaxbBean() {} // JAXB needs this public MyJaxbBean(String name, int age) {
this.name = name;
this.age = age;
}
}

Using the above JAXB bean for producing JSON data format from you resource method, is then as simple as:

@GET @Produces("application/json")
public MyJaxbBean getMyBean() {
return new MyJaxbBean("Agamemnon", 32);
}

Notice, that JSON specific mime type is specified in @Produces annotation, and the method returns an instance of MyJaxbBean, which JAXB is able to process. Resulting JSON in this case would look like:

{"name":"Agamemnon", "age":"32"}

Configuration Options

JAXB itself enables you to control output JSON format to certain extent. Specifically renaming and ommiting items is easy to do directly using JAXB annotations. E.g. the following example depicts changes in the above mentioned MyJaxbBean that will result in {"king":"Agamemnon"} JSON output.

@XmlRootElement
public class MyJaxbBean { @XmlElement(name="king")
public String name; @XmlTransient
public int age; // several lines removed
}

To achieve more important JSON format changes, you will need to configure Jersey JSON procesor itself. Various configuration options could be set on an JSONConfiguration instance. The instance could be then further used to create a JSONConfigurated JSONJAXBContext, which serves as a main configuration point in this area. To pass your specialized JSONJAXBContext to Jersey, you will finally need to implement a JAXBContext ContextResolver<T>:

@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> { private JAXBContext context;
private Class[] types = {MyJaxbBean.class}; public JAXBContextResolver() throws Exception {
this.context =
new JSONJAXBContext(                  // Creation of our specialized JAXBContext
JSONConfiguration.natural().build(), types); // Final JSON format is given by this JSONConfiguration instance
} public JAXBContext getContext(Class<?> objectType) {
for (Class type : types) {
if (type == objectType) {
return context;
}
}
return null;
}
}

JSON Notations

JSONConfiguration allows you to use four various JSON notations. Each of these notations serializes JSON in a different way. Following is a list of supported notations:

  • MAPPED (default notation)
  • NATURAL
  • JETTISON_MAPPED
  • BADGERFISH

Individual notations and their further configuration options are described bellow. Rather then explaining rules for mapping XML constructs into JSON, the notations will be described using a simple example. Following are JAXB beans, which will be used.

@XmlRootElement
public class Address {
public String street;
public String town; public Address() {
} public Address(String street, String town) {
this.street = street;
this.town = town;
}
} @XmlRootElement
public class Contact { public int id;
public String name;
public List<Address> addresses; public Contact() {
}; public Contact(int id, String name, List<Address> addresses) {
this.name = name;
this.id = id;
this.addresses = (addresses != null) ? new LinkedList<Address>(addresses) : null;
}
}

Following text will be mainly working with a contact bean initialized with:

final Address[] addresses = {new Address("Long Street 1", "Short Village")};
Contact contact = new Contact(2, "Bob", Arrays.asList(addresses));

I.e. contact bean with id=2name="Bob" containing a single address (street="Long Street 1"town="Short Village").

All bellow described configuration options are documented also in apidocs at JSONConfiguration Java Doc.

Mapped notation

JSONConfiguration based on mapped notation could be build with

JSONConfiguration.mapped().build()

for usage in a JAXBContext resolver above. Then a contact bean initialized that will be serialized as

{
"id": "2",
"name": "Bob",
"addresses": {"street": "Long Street 1", "town": "Short Village"}
}

The JSON representation seems fine, and will be working flawlessly with Java based Jersey client API.

However, at least one issue might appear once you start using it with a JavaScript based client. The information, that addresses item represents an array, is being lost for every single element array. If you added another address bean to the contact,

contact.addresses.add(new Address("Short Street 1000", "Long Village"));

, you would get

{
"id": "2",
"name": "Bob",
"addresses": [
{"street": "Long Street 1", "town": "Short Village"},
{"street": "Short Street 1000", "town": "Long Village"}
]
}

Both representations are correct, but you will not be able to consume them using a single JavaScript client, because to access "Short Village" value, you will write addresses.town in one case and addresses[0].town in the other. To fix this issue, you need to instruct the JSON processor, what items need to be treated as arrays by setting an optional property, arrays, on your JSONConfiguration object. For our case, you would do it with

JSONConfiguration.mapped().arrays("addresses").build()

You can use multiple string values in the arrays method call, in case you are dealing with more than one array item in your beans. Similar mechanism (one or more argument values) applies also for all below desribed options.

Another issue might be, that number value, 2, for id item gets written as a string, "2". To avoid this, you can use another optional property on JSONConfiguration called nonStrings.

JSONConfiguration.mapped().arrays("addresses").nonStrings("id").build()

It might happen you use XML attributes in your JAXB beans. In mapped JSON notation, these attribute names are prefixed with @ character. If id was an attribute, it's definition would look like:

...
@XmlAttribute
public int id;
...

and then you would get

{"@id":"2" ...

at the JSON output. In case, you want to get rid of the @ prefix, you can take advantage of another configuration option of JSONConfiguration, called attributeAsElement. Usage is similar to previous options.

JSONConfiguration.mapped().attributeAsElement("id").build()

Mapped JSON notation was designed to produce the simplest possible JSON expression out of JAXB beans. While in XML, you must always have a root tag to start a XML document with, there is no such a constraint in JSON. If you wanted to be strict, you might have wanted to keep a XML root tag equivalent generated in your JSON. If that is the case, another configuration option is available for you, which is called rootUnwrapping. You can use it as follows:

JSONConfiguration.mapped().rootUnwrapping(false).build()

and get the following JSON for our Contact bean:

{
"contact": {
"id": "2",
"name": "Bob",
"addresses": {"street": "Long Street 1", "town": "Short Village"}
}
}

rootUnwrapping option is set to true by default. You should switch it to false if you use inheritance at your JAXB beans. Then JAXB might try to encode type information into root element names, and by stripping these elements off, you could break unmarshalling.

In version 1.1.1-ea, XML namespace support was added to the MAPPED JSON notation. There is of course no such thing as XML namespaces in JSON, but when working from JAXB, XML infoset is used as an intermediary format. And then when various XML namespaces are used, ceratin information related to the concrete namespaces is needed even in JSON data, so that the JSON procesor could correctly unmarshal JSON to XML and JAXB. To make it short, the XML namespace support means, you should be able to use the very same JAXB beans for XML and JSON even if XML namespaces are involved.

Map<String, String> ns2json = new HashMap<String, String>();
ns2json.put("http://example.com", "example");
context = new JSONJAXBContext(JSONConfiguration.mapped().xml2JsonNs(ns2json).build(), types);

Dot character (.) will be used by default as a namespace separator in the JSON identifiers. E.g. for the above mentioned example namespace and tag T"example.T" JSON identifier will be generated. To change this default behaviour, you can use the nsSeparator method on the mapped JSONConfiguration builder: JSONConfiguration.mapped().xml2JsonNs(ns2json).nsSeparator(':').build(). Then you will get "example:T" instead of "example.T" generated. This option should be used carefully, as the Jersey framework does not even try to check conflicts between the user selected separator character and the tag and/or namespace names.

Natural notation

After using mapped JSON notation for a while, it was apparent, that a need to configure all the various things manually could be a bit problematic. To avoid the manual work, a new, natural, JSON notation was introduced in Jersey version 1.0.2. With natural notation, Jersey will automatically figure out how individual items need to be processed, so that you do not need to do any kind of manual configuration. Java arrays and lists are mapped into JSON arrays, even for single-element cases. Java numbers and booleans are correctly mapped into JSON numbers and booleans, and you do not need to bother with XML attributes, as in JSON, they keep the original names. So without any additional configuration, just using

JSONConfiguration.natural().build()

for configuring your JAXBContext, you will get the following JSON for the bean initialized above:

{
"id": 2,
"name": "Bob",
"addresses": [
{"street": "Long Street 1", "town": "Short Village"}
]
}

You might notice, that the single element array addresses remains an array, and also the non-string id value is not limited with double quotes, as natural notation automatically detects these things.

To support cases, when you use inheritance for your JAXB beans, an option was introduced to the natural JSON configuration builder to forbid XML root element stripping. The option looks pretty same as at the default mapped notation case

JSONConfiguration.natural().rootUnwrapping(false).build()

Jettison mapped notation

Next two notations are based on project Jettison. You might want to use one of these notations, when working with more complex XML documents. Namely when you deal with multiple XML namespaces in your JAXB beans.

Jettison based mapped notation could be configured using:

JSONConfiguration.mappedJettison().build()

If nothing else is configured, you will get similar JSON output as for the default, mapped, notation:

{
"contact": {
"id": 2,
"name": "Bob",
"addresses": {"street": "Long Street 1", "town": "Short Village"}
}
}

The only difference is, your numbers and booleans will not be converted into strings, but you have no option for forcing arrays remain arrays in single-element case. Also the JSON object, representing XML root tag is being produced.

If you need to deal with various XML namespaces, however, you will find Jettison mapped notation pretty useful. Lets define a particular namespace for id item:

...
@XmlElement(namespace="http://example.com")
public int id;
...

Then you simply confgure a mapping from XML namespace into JSON prefix as follows:

Map<String, String> ns2json = new HashMap<String, String>();
ns2json.put("http://example.com", "example");
context = new JSONJAXBContext(JSONConfiguration.mappedJettison().xml2JsonNs(ns2json).build(), types);

Resulting JSON will look like in the example bellow.

{
"contact": {
"example.id": 2,
"name": "Bob",
"addresses": {"street": "LongStreet1", "town": "ShortVillage"}
}
}

Please note, that id item became example.id based on the XML namespace mapping. If you have more XML namespaces in your XML, you will need to configure appropriate mapping for all of them.

Badgerfish notation

Badgerfish notation is the other notation based on Jettison. From JSON and JavaScript perspective, this notation is definitely the worst readable one. You will probably not want to use it, unless you need to make sure your JAXB beans could be flawlessly written and read back to and from JSON, without bothering with any formatting configuration, namespaces, etc.

JSONConfiguration instance using badgerfish notation could be built with

JSONConfiguration.badgerFish().build()

and the output JSON will be as follows.

{
"contact": {
"id": {"$": "2"},
"name": {"$": "Bob"},
"addresses": {
"street": {"$": "Long Street 1"},
"town": {"$": "Short Village"}
}
}
}

Examples

Download json-from-jaxb-1.19.1-project.zip to get a more complex example using JAXB based JSON support.

Low-level, JSONObject/JSONArray based JSON support

Using this approach means you will be using JSONObject and/or JSONArray classes for your data representations. These classes are actually taken from Jettison project, but conform to the description provided at http://www.json.org/java/index.html.

The biggest advantage here is, that you will gain full control over the JSON format produced and consumed. On the other hand, dealing with your data model objects will probably be a bit more complex, than when taking the JAXB based approach. Differencies are depicted at the following code snipets.

MyJaxbBean myBean = new MyJaxbBean("Agamemnon", 32);

Above you construct a simple JAXB bean, which could be written in JSON as {"name":"Agamemnon", "age":32}

Now to build an equivalent JSONObject (in terms of resulting JSON expression), you would need several more lines of code.

JSONObject myObject = new JSONObject();
myObject.JSONObject myObject = new JSONObject();
try {
myObject.put("name", "Agamemnon");
myObject.put("age", 32);
} catch (JSONException ex) {
LOGGER.log(Level.SEVERE, "Error ...", ex);
}

Examples

Download bookmark-1.19.1-project.zip to get a more complex example using low-level JSON support.

Jersey(1.19.1) - JSON Support的更多相关文章

  1. Jersey(1.19.1) - XML Support

    As you probably already know, Jersey uses MessageBodyWriters and MessageBodyReaders to parse incomin ...

  2. Jersey(1.19.1) - Client API, Ease of use and reusing JAX-RS artifacts

    Since a resource is represented as a Java type it makes it easy to configure, pass around and inject ...

  3. Qt浅译:JSON Support in Qt(JSON只有六种数据类型)

    JSON Support in Qt   Qt5之后开始提供对处理JSON数据的支持,JSON是一种Interter数据交换的数据格式.   JSON 用于存储结构化的数据,JSON有6种基本数据类型 ...

  4. 输入docker ps 报错信息处理Get http:///var/run/docker.sock/v1.19/containers/json: dial unix /var/run/docker.sock: permission denied.

    完整错误信息 Get http:///var/run/docker.sock/v1.19/containers/json: dial unix /var/run/docker.sock: permis ...

  5. Jersey(1.19.1) - Hello World, Get started with a Web application

    1. Maven Dependency <properties> <jersey.version>1.19.1</jersey.version> </prop ...

  6. Jersey(1.19.1) - Root Resource Classes

    Root resource classes are POJOs (Plain Old Java Objects) that are annotated with @Path have at least ...

  7. Jersey(1.19.1) - Hello World, Get started with Jersey using the embedded Grizzly server

    Maven Dependencies The following Maven dependencies need to be added to the pom: <dependency> ...

  8. Jersey(1.19.1) - Sub-resources

    @Path may be used on classes and such classes are referred to as root resource classes. @Path may al ...

  9. Jersey(1.19.1) - Client API, Overview of the API

    To utilize the client API it is first necessary to create an instance of a Client, for example: Clie ...

随机推荐

  1. Global.asax.cs介绍

    转载  http://www.cnblogs.com/tech-bird/p/3629585.html ASP.NET的配置文件 Global.asax--全局应用程序文件 Web.config--基 ...

  2. HDU2066一个人的旅行(dijkstra)

    一开始拿到这个题感觉floyd可能会超,还是写了写,果然1WA+1TLE,之后觉得用dijkstra试试看看S和D会不会比较小,还是1WA+1TLE,最后还是借鉴了别人的做法. 把他的家作为起点,与他 ...

  3. hibernate[版本四]知识总结

    1.hibernate是orm对象关系映射,是对jdbc的封装 2.hibernate版helloworld 2.1导入jar <dependencies> <dependency& ...

  4. JS 命名空间 实现方式 收集

    一. 对象注册式 // 声明一个全局对象Namespace,用来注册命名空间Namespace = new Object(); // 全局对象仅仅存在register函数,参数为名称空间全路径,如&q ...

  5. jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究

    终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...

  6. Linux下升级python版本

    转载自:http://lovebeyond.iteye.com/blog/1770476 CentOS下的Python版本一般都比较低,很多应用都需要升级python来完成.我装的centOS的默认的 ...

  7. Android Studio安装及主题字体配置

    在2013 Google I/O 大会上,谷歌推出了自家全新的安卓软件集成开发工具 Android Studio,这是 Google 基于 IntelliJ IDEA 改动而来. 谷歌称 Androi ...

  8. 我总结的18个非常好用的vim指令

    在Linux下最有名的程序编辑器非vim莫属了. 在一般模式下, 1.dd——删除光标所在行 2./word ——全文搜索指定单词 3.G ——将光标移动到文件的最后一行,移动到第99行,就是99G ...

  9. [Redux + Webpack] Hot reloading Redux Reducers with Webpack

    Webpack will hot reload the component, but the reducer we need hard refresh. To sovle the problem, g ...

  10. [React] Styling React Components With Aphrodite

    Aphrodite is a library styling React components. You get all the benefits of inline styles (encapsul ...