Converting Jackson JsonNode to Complex Java Collections
- Published on
Converting Jackson JsonNode to Complex Java Collections
In the world of modern application development, handling JSON data has become a fundamental skill, especially when working with APIs. One of the most powerful libraries to facilitate JSON parsing in Java is Jackson. Given its robustness, it allows us to convert JSON objects effortlessly into Java collections—be it simple lists, maps, or more complex nested structures.
In this post, we will explore how to convert Jackson's JsonNode
to complex Java collections. We will cover scenarios such as converting to lists of objects, maps, and even collections within collections. Furthermore, we will also discuss the best practices to follow during this conversion process.
Understanding Jackson's JsonNode
Before we dive into the conversion process, it's essential to understand what a JsonNode
is. JsonNode
is a core component of the Jackson library used to represent a JSON structure.
You typically obtain a JsonNode
by using the ObjectMapper
class, as shown below:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonNodeExample {
public static void main(String[] args) throws Exception {
String json = "{ \"name\": \"John\", \"age\": 30 }";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(json);
System.out.println(node.get("name").asText()); // Prints: John
System.out.println(node.get("age").asInt()); // Prints: 30
}
}
This snippet highlights the ease of working with JsonNode
but doesn't dive into collections just yet. The exciting part is how we can extract complex Java structures from this representation.
Converting JsonNode to Collections
Let's say you have a JSON object resembling the following:
{
"employees": [
{
"name": "Alice",
"age": 28,
"projects": ["Project A", "Project B"]
},
{
"name": "Bob",
"age": 32,
"projects": ["Project C"]
}
]
}
Our objective is to extract this data into a list of custom objects. First, we will create a custom class that represents our employee.
Create a Custom Class
import java.util.List;
public class Employee {
private String name;
private int age;
private List<String> projects;
public Employee(String name, int age, List<String> projects) {
this.name = name;
this.age = age;
this.projects = projects;
}
// Getters and toString() method for easier output
public String getName() { return name; }
public int getAge() { return age; }
public List<String> getProjects() { return projects; }
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", projects=" + projects +
'}';
}
}
Converting JsonNode to List of Employees
Now, let's use Jackson to convert the JsonNode
to a list of our Employee
objects.
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
public class JsonNodeToCollection {
public static void main(String[] args) throws Exception {
String json = "{ \"employees\": [{ \"name\": \"Alice\", \"age\": 28, \"projects\": [\"Project A\", \"Project B\"] }, { \"name\": \"Bob\", \"age\": 32, \"projects\": [\"Project C\"] }] }";
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(json);
JsonNode employeesNode = rootNode.path("employees");
List<Employee> employees = new ArrayList<>();
for (JsonNode employeeNode : employeesNode) {
String name = employeeNode.path("name").asText();
int age = employeeNode.path("age").asInt();
List<String> projects = mapper.convertValue(employeeNode.path("projects"), List.class);
employees.add(new Employee(name, age, projects));
}
// Output the extracted employees
employees.forEach(System.out::println);
}
}
Commentary on This Code
-
Path Method: The
path
method is used to navigate through theJsonNode
. This approach avoids exceptions where the path does not exist by returning a “missing node.” -
convertValue: The
convertValue
method allows seamless conversion fromJsonNode
to a List of Strings directly. It efficiently handles the transformation without the need for manual iteration.
Handling Nested Collections
JSON structures can often get more complicated, with additional layers of nesting. For instance, consider the following JSON structure that includes another collection.
{
"departments": [
{
"name": "Development",
"employees": [
{ "name": "Alice", "age": 28, "projects": ["Project A", "Project B"] },
{ "name": "Bob", "age": 32, "projects": ["Project C"] }
]
},
{
"name": "Marketing",
"employees": []
}
]
}
To extract this information, we will need a new class that represents a department:
Create a Department Class
import java.util.List;
public class Department {
private String name;
private List<Employee> employees;
public Department(String name, List<Employee> employees) {
this.name = name;
this.employees = employees;
}
// Getters and toString() method for easier output
public String getName() { return name; }
public List<Employee> getEmployees() { return employees; }
@Override
public String toString() {
return "Department{" +
"name='" + name + '\'' +
", employees=" + employees +
'}';
}
}
Converting to List of Departments
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
public class JsonNodeNestedCollection {
public static void main(String[] args) throws Exception {
String json = "{ \"departments\": [{ \"name\": \"Development\", \"employees\": [{ \"name\": \"Alice\", \"age\": 28, \"projects\": [\"Project A\", \"Project B\"] }, { \"name\": \"Bob\", \"age\": 32, \"projects\": [\"Project C\"] }] }, { \"name\": \"Marketing\", \"employees\": [] }] }";
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(json);
JsonNode departmentsNode = rootNode.path("departments");
List<Department> departments = new ArrayList<>();
for (JsonNode departmentNode : departmentsNode) {
String name = departmentNode.path("name").asText();
List<Employee> employees = new ArrayList<>();
for (JsonNode employeeNode : departmentNode.path("employees")) {
String empName = employeeNode.path("name").asText();
int age = employeeNode.path("age").asInt();
List<String> projects = mapper.convertValue(employeeNode.path("projects"), List.class);
employees.add(new Employee(empName, age, projects));
}
departments.add(new Department(name, employees));
}
// Output the extracted departments
departments.forEach(System.out::println);
}
}
The Bottom Line
Handling JSON data and converting it to Java collections using Jackson allows developers to interact seamlessly with external APIs and define custom structures based on the received data. This guide has provided you with essential techniques to convert JsonNode
to complex Java collections effectively and efficiently.
For more detailed information about the features and benefits of Jackson, you can refer to the Jackson official documentation.
By mastering these skills, you will be well-equipped to tackle complex data transformations in Java, a crucial capability for any modern developer. Happy coding!
Checkout our other articles