JSON is a alternative to XML for interchanging messages between the 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). Jackson databind depends on core and annotations libraries. Therefore, just adding jackson-databind to your 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 Jackson parser to convert JSON to object or vice versa, the library is included in Spring Boot project dependencies list by default. Therefore, you do not need to explicitly include it. Otherwise, you may get version conflict errors.

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 ObjectMapper class for mapping JSON data to Java objects (POJOs). It also supports JSON data conversion to Map and other generic data types.

In order to thoroughly understand how the mapping works, let's create the following JSON file that includes a 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. By looking 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 Address class representing inner address object along with 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 by 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 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 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 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

ObjectMapper class also provides methods to transform Java object to JSON file or string. One such overloaded method is writeValue() that works with byte arrays, files and output streams etc.

Let's update our JacksonApplication class with an example of Customer object conversion to 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 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 Customer object and then creates a new Customer object and stores it in 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 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. 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());
}

Important thing to notice in above code snippet is overloaded readValue() method where we used FileInputStream to read our 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

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 which provides different methods to work with specific keys.

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

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

//read customer.json file into 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 readTree() method from ObjectMapper class to read our customer.json file in a JSON Tree Model. JsonNode class provides 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 nested node (like city value in above code). asText() method returns the value of the node as a string.

Another key thing to note in above code snippet is the use of 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 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 ease-of-use and a lot of options available for processing JSON.

What is your preferred choice for processing JSON data in Java? Tweet me anytime to let me know.

Further Reading

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

✌️ Like this article? Follow @attacomsian on Twitter. You can also follow me on LinkedIn and DEV. Buy me a coffee (cost $3)

Need help to start a new Spring Boot or MEAN stack project? I am available for contract work. Hire me to accomplish your business goals with engineering and design. Let’s talk about your project: hi@attacomsian.com.