The json string at times have a lot of properties. It seems a waste creating a POJO with all those properties. Wouldnt it be great if there was a catch’all that could read all properties in a map? Jackson provides annotations to do just that. In the example below we have set two properties in the bean and the other properties are read into a map. These example also introduces some common annotations using in Jackson. Lets look at them briefly:
- @JsonProperty-This annotation is used to mark a method as a getter or setter for a property. In other words, it associates a json field with a java property. If a name is specified (@JsonProperty(“age”)) then the java property that is annotated with this annotation is mapped to the ‘age’ field of the json, If no name is specified the java property name is used.
- @JsonCreator-This annotation is used the define constructors that are used to create java objects from json string. It is used during data binding and specifies properties that will be used to create java objects during deserialization.
- @JsonAnyGetter and @JsonAnySetter - This annotations are used to mark methods that set or read fields that are not handled by any other java property. These act like catch-all and handle all fields that are not handled by any other java property. The fields are stored in a map as key value pairs.
In this tutorial we will see how to convert a java List to JSON. Serializing list is a little tricky since by default the type info is not stored while serializing and deserializing lists. In this tutorial we look at two examples. In the first example we serialize an Object that has a java List as one of its properties. In the second example we try and serialize the List directly. In both examples we use special configuration to preserve type info.
Example 1 : Serializing Object containing a list
The example converts a Zoo class to json. the zoo class contains the name of zoo, its city and a list of animals. The list is of type ‘Animal’, i.e. the list contains elements that are subclass of the Abstract class Animal. Lets see what happens when we try to serialize zoo. First we create the Zoo class. Notice how the constructor looks. When we try to get the Zoo Object back from the JSON, Jackson has to know that it should create the Zoo Object using the constructor that takes in the name and city properties.
class Zoo {
public String name;
public String city;
@JsonCreator
public Zoo(@JsonProperty("name") String name,@JsonProperty("city") String city) {
this.name = name;
this.city = city;
}
public List<Animal> animals = new ArrayList<Animal>();
public List<Animal> addAnimal(Animal animal) {
animals.add(animal);
return animals;
}
}
A thing that most java developers love to deal with is …. Java POJO. Wouldn’t you love a black box where you can see JSON string entering from one side and POJOs coming out from the other. That’s what Jackson data binding does. This can be best explained by an example. We use the json from free music archive. It has an API to get latest albums in the form of JSON. we would read that json string (Click on this link to see the json) into Albums object. The Albums object contains an array of Dataset.
Here’s how The JSON to Java conversion works
- The first step is to create the Java class that would hold the JSON data. Look at the json. we create an Albums object to hold the entire json. The json contains an array of ‘dataset’ elements. We create a Java Object of type DataSet and in the Albums object we create a dataset property that is an array of type DataSet.
- Create an instance of the com.fasterxml.jackson.databind.ObjectMapper class. This is the class that maps a JSON to a Java Object.
ObjectMapper mapper = new ObjectMapper();
- We use the readValue method of the ObjectMapper to read. There are multiple versions of this method and we use the method that takes in a URL. However, there are method that read from a file, inputstream, String or a ByteArray.
- The ObjectMapper caches serializers and deserializers so it would be a good idea to reuse an ObjectMapper instance for multiple conversions
Jackson provides a tree node called com.fasterxml.jackson.databind.JsonNode. The ObjectMapper provides a method to read the json into a tree with the root being a JsonNode. This can be thought of as being similar to DOM nodes in XML DOM trees. The example below demonstrates building a tree from the json string
Streaming Parser and Generator
Jackson provides a low level API to parse json string. The API provides token for each json object. For example, the start of json ‘{’ is the first object that the parser provides. The key value pair is another single object. The client code can use the tokens and get the json properties or build a java object out of it if required. This low level API is extremely powerful but needs a lot of coding. For most cases, Jackson’s tree traversing and data binding capability should be explored instead. We provide two examples below. The first example demonstrates json parsing and the second demonstrated json generation.
Creating JSON from Java
Jackson provides classes that can be used to convert a Java Object to JSON and back. In this example we look at how to build a JSON construct from a Java Object. We will start with a simple class and gradually start adding complexities to it. Lets say that we are a music company and we want to publish an api where users can query for Album. We first build an Album class with a single property title.
class Album {
private String title;
public Album(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
Overview of The Jackson API
Jackson Api contains a lot of functionalities to read and build json using java. It has very powerful data binding capabilities and provides a framework to serialize custom java objects to json string and deserialize json string back to java objects. Json written with jackson can contain embedded class information that helps in creating the complete object tree during deserialization.
Creating JSON from JAVA
There are three ways to create JSON from JAVA:
- From a Java Object (The Same object can also be then used to read the JSON)
- From a JsonNode Tree
- Building a Json Stream
In the first tutorial we look at all the three ways of creating JSON. Note that if you are new to Jackson this is probably the best place to begin even if you are looking at a way to parse JSON.
XStream provides a TraxSource (extends SAXSource) that can be used as an input to XSLT transformation. The TraxSource uses a java Object and the corresponding XStream Object. The java object can then be directly converted to XSLT target without actually converting to XML. Lets look at an example
package com.studytrails.xml.xstream;
import java.util.ArrayList;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.TraxSource;
public class XStreamTransformationExample {
public static void main(String[] args) throws TransformerFactoryConfigurationError, TransformerException {
XStreamTransformationExample transformationExample = new XStreamTransformationExample();
transformationExample.runTransformation();
}
private void runTransformation() throws TransformerFactoryConfigurationError, TransformerException {
XStream xstream = new XStream();
xstream.alias("rss", Rss2.class);
xstream.alias("item", Item2.class);
Rss2 rss = new Rss2();
Channel2 channel = new Channel2();
rss.channel = channel;
channel.title = "Title";
channel.link = "link";
channel.image = new Image2();
channel.image.link = "image link";
Item2 item1 = new Item2();
item1.link = "item link";
item1.title = "Item Title";
channel.items = new ArrayList<Item2>();
channel.items.add(item1);
System.out.println(xstream.toXML(rss));
Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource("bbc.xsl"));
TraxSource traxSource = new TraxSource(rss, xstream);
StreamResult result = new StreamResult(System.out);
transformer.transform(traxSource, result);
// prints the html on console
}
}
XStream can also be used with JSON. XStream provides two drivers : a JsonHierarchicalStreamDriver and a JettisonMappedXmlDriver. The JsonHierarchicalStreamDriver can be used to write a JSON string but cannot deserialize a JSON. JettisonMappedXmlDriver can be used to deserialize a JSON but it introduces an additional dependency. In this example we deserialize a json string into a java object.
Note: The mapping from Java to JSON (and back) is limited, since not anything can be expressed in JSON as with XML. It works quite well for simple objects, but one should not expect wonders. Additionally XStream supports only Jettison 1.0.1. Any other version will not work correctly (even newer ones).