Jackson: Java Parsing Json Library

Jackson is a simple Java-based library to serialize Java objects to JSON and vice versa. It has some features like easy to use, no need mapping, good performance, clean JSON, no dependency, and opne source.

There are mainly 3 usages for Jackson library.

Tree Model

ObjectMapper object will provide a pointer to the root node of your JSON tree after reading the JSON string, and then we can use the root node to traverse the whole tree.
Here is the code to create ObjectMapper and get the root JSON node:

1
2
3
4
5
6
7
8
// Example of JSON String
String jsonString = "{\"name\":\"Peter\",\"age\":22,\"gender\":\"male\", \"modules\":[\"CS1010\",\"MA1100\",\"GEK1505\"]}";

// Create ObjectMapper instance
ObjectMapper mapper = new ObjectMapper();

// Get the root JSON node
JsonNode rootNode = mapper.readTree(jsonString);

And then you can use the the root node to traverse the whole tree like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
JsonNode nameNode = rootNode.path("name");
System.out.println("Name: "+ nameNode.getTextValue());

JsonNode ageNode = rootNode.path("age");
System.out.println("Age: " + ageNode.getIntValue());

JsonNode genderNode = rootNode.path("gender");
System.out.println("Gender: " + genderNode.getTextValue());

JsonNode modulesNode = rootNode.path("modules");
Iterator<JsonNode> iterator = modulesNode.getElements();
System.out.print("Modules: [ ");
while (iterator.hasNext()) {
JsonNode modules = iterator.next();
System.out.print(modules.getIntValue() + " ");
}
System.out.println("]");

And the printing result is:

1
2
3
4
Name: Peter
Age: 22
Gender: male
Modules: [ CS1010 MA1100 GEK1505 ]

If you want to modify value of some fields, you cannot directly change it in the JsonNode because it is immutable, which means read-only. However, we can cast JsonNode to ObjectNode first, and then we can modify the values:

1
2
3
4
JsonNode jsonNode = mapper.createObjectNode();

ObjectNode objectNode = (ObjectNode)jsonNode;
objectNode.put("key", "value");

put method will check if there is an old value; if yes, then overwrite it; else just put in the new value.

And if you want to put new value in an array, then cast it to ArrayNode and use add methdo to add new value:

1
2
3
4
JsonNode jsonNode = mapper.createArrayNode();

ArrayNode arrayNode = (ArrayNode)jsonNode;
arrayNode.add("value");

Using this tree model, you can easily cast a JSON String to a readable JSON Tree, and also you can cast a JSON Tree to a JSON String as well. However, there is a small different between getTextValue() and toString(); if using getTextValue(), there won’t be any double quotes in the result String; if using toString(), it will keep all the double quotes.

Data Binding

It converts JSON to and from Plain Old Java Object (POJO) using property accessor or using annotations. ObjectMapper reads or writes JSON for both types of data bindings. Data binding is analogous to JAXB parser for XML. Data binding is of two types:

  • Simple Data Binding
    It converts JSON to and from Java Maps, Lists, Strings, Numbers, Booleans, and null objects.
  • Full Data Binding
    It converts JSON to and from any Java type.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import java.io.IOException;

import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;

public class JacksonTester {
public static void main(String args[]){

ObjectMapper mapper = new ObjectMapper();
String jsonString = "{" +
"\"name\":\"Peter\"," +
"\"age\":22," +
"\"info\":{" +
"\"nationality\":\"Singaporean\"," +
"\"address\":\"NUS\"" +
"{" +
"}"

try{
Student student = mapper.readValue(jsonString, Student.class);

System.out.println(student);

mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
jsonString = mapper.writeValueAsString(student);

System.out.println(jsonString);
}
catch (JsonParseException e) { e.printStackTrace();}
catch (JsonMappingException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
}
}

public class Student {
public static class Info {
String nationality;
String address;

public Info() {}

public String getNationality() {
return nationality;
}

public String getAddress() {
return address;
}

public void setNationality(String nationality) {
this.nationality = nationality;
}

public void setAddress(String address) {
this.address = address;
}

@Override
public String toString() {
return "{" +
"\"nationality\":\"" + nationality + "\"," +
"\"address\":\"" + address + "\"" +
"}";
}
}

private String name;
private int age;
private Info info;

public Student() {}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Info getInfo() {
return info;
}

public void setInfo(Info info) {
this.info = info;
}

@Override
public String toString(){
return "{" +
"\"name\":\"" + name + "\"," +
"\"age\":" + age + "," +
"\"info\":" +
"}";
}
}

The code above is an example of creating a JSON string with Student details and then deserializing it to Student object and then serializing it back to a JSON string.

For the inner class, you must use static class for Jackson because non-static inner class will not have a default zero-argument constructor which is required for using Jackson data binding. For more details, check here.

If you want to ignore null value, using this:

1
2
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);

If you want to ignore non-matching field in the json, using this:

1
2
3
4
5
6
ObjectMapper mapper = new ObjectMapper();

// jackson 1.9 and before
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// or jackson 2.0
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Streaming API

Streaming API reads and writes JSON content as discrete events. JsonParser reads the data, and JsonGenerator writes the data.

Here is the usage of JsonParser:

1
2
3
4
5
JsonFactory jasonFactory = new JsonFactory();
JsonGenerator jsonGenerator = jasonFactory.createJsonGenerator(new File("student.json"), JsonEncoding.UTF8);

jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name", "Peter");

Here is the usage of JsonGenerator:

1
2
3
4
5
6
7
8
9
10
11
12
13
JsonFactory jasonFactory = new JsonFactory();
JsonParser jsonParser = jasonFactory.createJsonParser(new File("student.json"));

while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
//get the current token
String fieldname = jsonParser.getCurrentName();

if ("name".equals(fieldname)) {
//move to next token
jsonParser.nextToken();
System.out.println(jsonParser.getText());
}
}

For more details, check here.