Jackson JSON Processing: A Comprehensive Guide
Converting JSON to a Plain Old Java Object (POJO)
The ObjectMapper class is the primary entry point for Jackson. It can be used to convert JSON strings into Java objects and vice versa. Below is an example of deserializing a JSON string into a Person object and then serializing that object back to a formatted JSON string.
public class JsonPojoExample {
public static void main(String[] args) {
// ObjectMapper is thread-safe and should be reused
ObjectMapper objectMapper = new ObjectMapper();
String jsonInput = "{"firstName":"Alice", "age":28}";
try {
// Deserialize JSON string to a Person object
Person person = objectMapper.readValue(jsonInput, Person.class);
System.out.println("Deserialized Person: " + person);
// Enable pretty-printing for the output
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
// Serialize the Person object back to a JSON string
String jsonOutput = objectMapper.writeValueAsString(person);
System.out.println("Serialized JSON:
" + jsonOutput);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person {
private String firstName;
private int age;
// Getters and setters are required for serialization/deserialization
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override
public String toString() {
return "Person{firstName='" + firstName + "', age=" + age + "}";
}
}
Serialization and Deserialization to Files
Jackson can also work directly with files. The following example demonstrates writing a Person object to a JSON file and then reading it back.
public class JsonFileHandler {
public static void main(String[] args) {
JsonFileHandler handler = new JsonFileHandler();
try {
Person person = new Person();
person.setFirstName("Bob");
person.setAge(35);
// Serialize the object to a JSON file
handler.serializeToFile(person, "./data/person.json");
// Deserialize the object from the JSON file
Person personFromFile = handler.deserializeFromFile("./data/person.json");
System.out.println("Person from file: " + personFromFile);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Serializes a Java object to a JSON file.
* @param object The object to serialize.
* @param filePath The path to the output file.
* @throws Exception if an error occurs during serialization.
*/
public void serializeToFile(Object object, String filePath) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(new File(filePath), object);
}
/**
* Deserializes a JSON file into a Java object.
* @param filePath The path to the input file.
* @param clazz The class of the object to deserialize into.
* @return The deserialized object.
* @throws Exception if an error occurs during deserialization.
*/
public <t> T deserializeFromFile(String filePath, Class<t> clazz) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(new File(filePath), clazz);
}
}
</t></t>
Binding to a Map
Jackson can bind complex JSON structures directly to a Map. This is useful when you don't have a predefined POJO or when the structure is highly dynamic.
public class JsonMapBinding {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
// Create a complex data structure to serialize
Map<string object=""> dataMap = new HashMap<>();
Person person = new Person();
person.setFirstName("Charlie");
person.setAge(42);
dataMap.put("user", person);
dataMap.put("title", "System Administrator");
dataMap.put("isActive", true);
int[] scores = {98, 95, 92};
dataMap.put("performanceScores", scores);
// Serialize the map to a JSON file
// objectMapper.writeValue(new File("./data/user_data.json"), dataMap);
// Deserialize the JSON file back into a map
Map<string object=""> loadedMap = objectMapper.readValue(new File("./data/user_data.json"), Map.class);
// Access the data from the map
System.out.println("User: " + loadedMap.get("user"));
System.out.println("Title: " + loadedMap.get("title"));
System.out.println("Is Active: " + loadedMap.get("isActive"));
// Access the array from the map
List<integer> scoreList = (List<integer>) loadedMap.get("performanceScores");
System.out.println("Scores: " + scoreList);
}
}
</integer></integer></string></string>
Handling Generic Types
Deserializing generic types like List<User> or custom classes like PageResult<T> requires special handling to inform Jackson about the generic type information.
public class JsonGenericBinding {
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
User user = new User(1, "david@example.com");
List<user> userList = new ArrayList<>();
userList.add(user);
PageResult<user> pageResult = new PageResult<>();
pageResult.setItems(userList);
String json = objectMapper.writeValueAsString(pageResult);
// Method 1: Using TypeReference
PageResult<user> pageResult1 = objectMapper.readValue(json, new TypeReference<pageresult>>() {});
// Method 2: Using JavaType
JavaType javaType = objectMapper.getTypeFactory().constructParametrizedType(PageResult.class, PageResult.class, User.class);
PageResult<user> pageResult2 = objectMapper.readValue(json, javaType);
// Handling a List of Users
String listJson = objectMapper.writeValueAsString(userList);
JavaType listType = objectMapper.getTypeFactory().constructParametricType(List.class, User.class);
List<user> deserializedUsers = objectMapper.readValue(listJson, listType);
// Handling a Map of String to User
Map<string user=""> userMap = new HashMap<>();
userMap.put("admin", user);
String mapJson = objectMapper.writeValueAsString(userMap);
JavaType mapType = objectMapper.getTypeFactory().constructParametricType(HashMap.class, String.class, User.class);
Map<string user=""> deserializedMap = objectMapper.readValue(mapJson, mapType);
}
}
class User {
private int id;
private String email;
// Constructor, getters, setters...
public User(int id, String email) { this.id = id; this.email = email; }
// ... other methods
}
class PageResult<t> {
private List<t> items;
// Constructor, getters, setters...
public void setItems(List<t> items) { this.items = items; }
// ... other methods
}
</t></t></t></string></string></user></user></pageresult></user></user></user>
Using the Jackson Tree Model
The Tree Model alllows you to parse JSON into a tree of JsonNode objects, which you can then navigate manually. This is useful for dynamic or complex JSON structures.
public class JsonTreeModel {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = "{"firstName":"Eve", "lastName":"Adams", "age":30, "isEmployed":true, "skills":["Java", "Spring", "SQL"]}";
// Parse JSON string into a JsonNode tree
JsonNode rootNode = objectMapper.readTree(jsonString);
// Navigate the tree using path()
JsonNode nameNode = rootNode.path("firstName");
System.out.println("First Name: " + nameNode.asText());
JsonNode ageNode = rootNode.path("age");
System.out.println("Age: " + ageNode.asInt());
JsonNode skillsNode = rootNode.path("skills");
System.out.println("Skills:");
for (JsonNode skill : skillsNode) {
System.out.println(" - " + skill.asText());
}
// Reading from a file and converting to a POJO
JsonNode fileNode = objectMapper.readTree(new File("./data/user_info.json"));
UserInfo userInfo = objectMapper.treeToValue(fileNode, UserInfo.class);
System.out.println("User Info from file: " + userInfo.getFullName());
}
}
class UserInfo {
private String fullName;
// Constructor, getters, setters...
public String getFullName() { return fullName; }
// ... other methods
}
Streaming API for Large JSON
For very large JSON documents, the streaming API (JsonParser and JsonGenerator) is more memory-efficient as it processes the data token by token without loading the entire document into memory.
public class JsonStreamingApi {
public static void main(String[] args) throws Exception {
//writeJsonStream();
readJsonStream();
}
/**
* Writes JSON using JsonGenerator.
*/
public static void writeJsonStream() throws Exception {
JsonFactory jsonFactory = new JsonFactory();
JsonGenerator jsonGenerator = jsonFactory.createGenerator(new File("./data/employee.json"), JsonEncoding.UTF8);
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name", "Frank Miller");
jsonGenerator.writeNumberField("id", 101);
jsonGenerator.writeBooleanField("isManager", true);
jsonGenerator.writeFieldName("projects");
jsonGenerator.writeStartArray();
jsonGenerator.writeString("Project Alpha");
jsonGenerator.writeString("Project Beta");
jsonGenerator.writeEndArray();
jsonGenerator.writeEndObject();
jsonGenerator.close();
}
/**
* Reads JSON using JsonParser.
*/
public static void readJsonStream() throws Exception {
JsonFactory jsonFactory = new JsonFactory();
JsonParser jsonParser = jsonFactory.createParser(new File("./data/employee.json"));
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String fieldName = jsonParser.getCurrentName();
if ("name".equals(fieldName)) {
jsonParser.nextToken();
System.out.println("Name: " + jsonParser.getText());
}
if ("id".equals(fieldName)) {
jsonParser.nextToken();
System.out.println("ID: " + jsonParser.getIntValue());
}
if ("isManager".equals(fieldName)) {
jsonParser.nextToken();
System.out.println("Is Manager: " + jsonParser.getBooleanValue());
}
if ("projects".equals(fieldName)) {
jsonParser.nextToken(); // Move to the start of the array
System.out.println("Projects:");
while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
System.out.println(" - " + jsonParser.getText());
}
}
}
jsonParser.close();
}
}