JSON is an alternative to XML for interchanging messages between servers, communicating with RESTful web services, and more. It is a lightweight, language-independent, and human-readable data interchange format that is easy to read and write.

Jackson is a very popular choice for processing JSON data in Java. it consists of three libraries: Jackson Databind (jackson-databind), Core (jackson-core), and Annotations (jackson-annotations).

Since the databind library depends on core and annotations libraries, adding jackson-databind to the Gradle project dependencies section will also add the other two dependencies.

build.gradle

compile ('com.fasterxml.jackson.core:jackson-databind:2.9.8')

Or if you are using Maven, add the following dependency to your POM file:

pom.xml

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>

Since Spring Framework relies on the Jackson parser to convert JSON to object or vice versa, the library is already included in the Spring Boot project dependencies list. You do not need to explicitly include it. Otherwise, you may get version conflict errors.

Note: This tutorial is intended for processing JSON data stored in a file. If you are calling a RESTful web service for JSON data, check out Making HTTP Requests using RestTemplate guide.

JSON File to Object - Jackson Data Binding

Jackson has an ObjectMapper class for mapping JSON data to Java objects (POJOs). It also supports JSON data conversion to Map and other generic data types.

To thoroughly understand how the mapping works, let us create the following JSON file that includes customer data:

customer.json

{
  "id": 123,
  "name": "Jovan Lee",
  "email": "jovan@example.com",
  "phone": "+49 176 14890478",
  "age": 32,
  "projects": [
    "Remote Job Board",
    "Data Migration"
  ],
  "address": {
    "street": "Yorckstr. 75",
    "city": "Berlin",
    "zipcode": 10965,
    "country": "Germany"
  },
  "paymentMethods": [
    "PayPal",
    "Stripe"
  ],
  "profileInfo": {
    "gender": "Male",
    "married": "Yes",
    "source": "LinkedIn"
  }
}

The above JSON file contains several JSON objects with key-value pairs, including projects and paymentMethods arrays. When you look at the JSON data, it is cleared that we need to create two Java classes for mapping to work: Address & Customer.

The Customer class will contain the Address class representing the inner address object and other properties.

Address.java

package com.attacomsian.jackson;

public class Address {

    private String street;
    private String city;
    private int zipcode;
    private String country;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public int getZipcode() {
        return zipcode;
    }

    public void setZipcode(int zipcode) {
        this.zipcode = zipcode;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    @Override
    public String toString() {
        return "{" +
                "street='" + street + '\'' +
                ", city='" + city + '\'' +
                ", zipcode=" + zipcode +
                ", country='" + country + '\'' +
                '}';
    }
}

Customer.java

package com.attacomsian.jackson;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class Customer {

    private Long id;
    private String name;
    private String email;
    private String phone;
    private int age;
    private String[] projects;
    private Address address;
    private List<String> paymentMethods;
    private Map<String, Object> profileInfo;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public int getAge() {
        return age;
    }

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

    public String[] getProjects() {
        return projects;
    }

    public void setProjects(String[] projects) {
        this.projects = projects;
    }

    public Address getAddress() {
        return address;
    }

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

    public List<String> getPaymentMethods() {
        return paymentMethods;
    }

    public void setPaymentMethods(List<String> paymentMethods) {
        this.paymentMethods = paymentMethods;
    }

    public Map<String, Object> getProfileInfo() {
        return profileInfo;
    }

    public void setProfileInfo(Map<String, Object> profileInfo) {
        this.profileInfo = profileInfo;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", phone='" + phone + '\'' +
                ", age=" + age +
                ", projects=" + Arrays.toString(projects) +
                ", address=" + address +
                ", paymentMethods=" + paymentMethods +
                ", profileInfo=" + profileInfo +
                '}';
    }
}

Customer POJO represents the root JSON object. After creating POJO classes, now let's perform the data binding using Jackson's ObjectMapper classes.

JacksonApplication.java

package com.attacomsian.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.io.File;
import java.io.IOException;

@SpringBootApplication
public class JacksonApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(JacksonApplication.class, args);
    }

    @Override
    public void run(String[] args) throws IOException {

        //create ObjectMapper instance
        ObjectMapper objectMapper = new ObjectMapper();

        //read JSON file and convert to a customer object
        Customer customer = objectMapper.readValue(new File("customer.json"), Customer.class);

        //print customer details
        System.out.println(customer);
    }
}

In the above JacksonApplication class, we created an ObjectMapper instance and called its readValue() method with two parameters: a File object representing the JSON file as a source and Customer.class as the target to map the JSON values. In return, we get a Customer object populated with the data read from the customer.json file.

When we run the Spring Boot project, we will see the following output printed on the console:

Customer{id=123, name='Jovan Lee', email='jovan@example.com', phone='+49 176 14890478', age=32, projects=[Remote Job Board, Data Migration], address={street='Yorckstr. 75', city='Berlin', zipcode=10965, country='Germany'}, paymentMethods=[PayPal, Stripe], profileInfo={gender=Male, married=Yes, source=LinkedIn}}

Java Object to JSON File

The ObjectMapper class also provides methods to transform a Java object into a JSON file or string. For example, the writeValue() method converts byte arrays, files, and output streams into strings.

Let us update our JacksonApplication class with an example of Customer object conversion to the JSON file.

JacksonApplication.java

package com.attacomsian.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootApplication
public class JacksonApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(JacksonApplication.class, args);
    }

    @Override
    public void run(String[] args) throws IOException {

        //create ObjectMapper instance
        ObjectMapper objectMapper = new ObjectMapper();

        //read JSON file and convert to a customer object
        Customer customer = objectMapper.readValue(new File("customer.json"), Customer.class);

        //print customer details
        System.out.println(customer);

        //create a customer object
        Customer customerObj = new Customer();
        customerObj.setId(567L);
        customerObj.setName("Maria Kovosi");
        customerObj.setEmail("maria@example.com");
        customerObj.setPhone("+12 785 4895 321");
        customerObj.setAge(29);
        customerObj.setProjects(new String[]{"Path Finder App", "Push Notifications"});

        Address address = new Address();
        address.setStreet("Karchstr.");
        address.setCity("Hanover");
        address.setZipcode(66525);
        address.setCountry("Germany");
        customerObj.setAddress(address);

        List<String> paymentMethods = new ArrayList<>();
        paymentMethods.add("PayPal");
        paymentMethods.add("SOFORT");
        customerObj.setPaymentMethods(paymentMethods);

        Map<String, Object> info = new HashMap<>();
        info.put("gender", "female");
        info.put("married", "No");
        info.put("income", "120,000 EURO");
        info.put("source", "Google Search");
        customerObj.setProfileInfo(info);

        //configure objectMapper for pretty input
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);

        //write customerObj object to customer2.json file
        objectMapper.writeValue(new File("customer2.json"), customerObj);
    }
}

Our updated JacksonApplication class now maps the JSON file to the Customer object and then creates a new Customer object and stores it in the customer2.json file.

customer2.json

{
  "id" : 567,
  "name" : "Maria Kovosi",
  "email" : "maria@example.com",
  "phone" : "+12 785 4895 321",
  "age" : 29,
  "projects" : [ "Path Finder App", "Push Notifications" ],
  "address" : {
    "street" : "Karchstr.",
    "city" : "Hanover",
    "zipcode" : 66525,
    "country" : "Germany"
  },
  "paymentMethods" : [ "PayPal", "SOFORT" ],
  "profileInfo" : {
    "income" : "120,000 EURO",
    "gender" : "female",
    "source" : "Google Search",
    "married" : "No"
  }
}

JSON File to Map - Simple Data Binding

Sometimes we do not need full data binding - JSON data conversion to Java objects with the same properties and keys. Instead, we simply want to convert our JSON data into Map or List or any other built-in Java types, for example, Boolean, String, or even Double. The following is an example of simple data binding of our customer.json file to a generic Map:

//create ObjectMapper instance
ObjectMapper objectMapper = new ObjectMapper();

//convert JSON file to map
Map<?, ?> map = objectMapper.readValue(new FileInputStream("customer.json"), Map.class);

//iterate over map entries and print to console
for (Map.Entry<?, ?> entry : map.entrySet()) {
    System.out.println(entry.getKey() + "=" + entry.getValue());
}

Notice the overloaded readValue() method that accepts a FileInputStream object to read the customer.json file. This method has even more variants to support String, Reader, URL, and byte array. When we execute the above code snippet, we get the following output:

id=123
name=Jovan Lee
email=jovan@example.com
phone=+49 176 14890478
age=32
projects=[Remote Job Board, Data Migration]
address={street=Yorckstr. 75, city=Berlin, zipcode=10965, country=Germany}
paymentMethods=[PayPal, Stripe]
profileInfo={gender=Male, married=Yes, source=LinkedIn}

JSON File into a Tree Model

The ObjectMapperclass can also be used to construct a hierarchical tree of nodes from JSON data. In the JSON Tree Model, you can access a specific node and read its value.

In the Tree Model, each node is of type JsonNode that provides different methods to work with specific keys.

This method is useful when you are interested in only a few key values. In this scenario, it does not make sense to convert the complete JSON file into a Java object. The following code snippet converts the customer.json file into a Tree Model and then reads the name and phone nodes values.

//create ObjectMapper instance
ObjectMapper objectMapper = new ObjectMapper();

//read customer.json file into a tree model
JsonNode rootNode = objectMapper.readTree(new File("customer.json"));

//read name and phone nodes
System.out.println("Customer Name: " + rootNode.path("name").asText());
System.out.println("Customer Phone: " + rootNode.path("phone").asText());
System.out.println("Customer Age: " + rootNode.path("age").asInt());
System.out.println("Customer City: " + rootNode.path("address").path("city").asText());
System.out.println("Customer Project: " + rootNode.path("projects").get(0).asText());

In the code above, we used the readTree() method from the ObjectMapper class to read our customer.json file in a JSON Tree Model. The JsonNode class provides a path() method that can be used to specify the node name we are interested in to read the value. Since path() returns another JsonNode object, it can be chained to get a nested node (like the city value in the above code). The asText() method returns the value of the node as a string.

Another key thing to note in the above code snippet is the use of the get() method instead of path() to read the first project value. It works similar to path() method - returns the specific node as JsonNode. However, it returns a null value when the node is not present or is empty, instead of the missing node object as returned by the path() method. The get() method is also used to access the unknown keys and array indexes.

Source code: Download the complete source code from GitHub available under MIT license.

Conclusion

That is all for parsing JSON data using Jackson in a Spring Boot project. It is not the only JSON processor library available for Java. There are few more options available like Google Gson, Boon and core Java API. However, Jackson is very popular due to its ease of use and a lot of options available for processing JSON.

Further Reading

Want to learn more about Spring Boot? Check out the below tutorials:

✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.