Робимо сериализацію в JSON і назад c Jackson

Робимо сериализацію в JSON і назад c Jackson

  • 29 липня, 2021
  • читати 7 хв
Алі Жагпаров
Алі Жагпаров Java Software Engineer у Devexperts

JSON — це текстовий формат даних, заснований на JavaScript. Такий формат даних часто використовується для інтеграцій з зовнішніми сервісами або використовується для спілкування різних модулів програми. Тому кожному програмісту важливо знати, як працювати з таким форматом даних.

Робота з JSON складається з процесів:

Сериалізація — коли ми конвертуємо наші дані в JSON.

Десериалізація — коли з JSON рядки отримуємо POJO об'єкт.

Для зручної, швидкої та комфортної роботи існує безліч бібліотек, таких як Gson, Jackson і т.д. В даному уроці ми розглянемо роботу з Jackson.

Для цього нам необхідно додати наступну залежність в наш pom.xml файл.

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

Сериалізація

Для кращого розуміння розглянемо приклад простої програми:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

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

public class SerializationExample {

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();

        Certificate certificateOracle = new Certificate();
        certificateOracle.name = "ORACLE";
        certificateOracle.year = 2000;
        Certificate certificateSun = new Certificate();
        certificateSun.name = "SUN";
        certificateSun.year = 2015;

        Department department = new Department();
        department.setName("Computer Science");

        Student student = new Student();
        student.id = 2;
        student.department = department;
        student.name = "Ali Z";
        student.certificates = Arrays.asList(certificateOracle, certificateSun);

        String json = objectMapper.writeValueAsString(student);
        System.out.println(json);
    }
   
 static class Student {
        private int id;
        private String name;

        @JsonProperty("dep")
        private Department department;

        private List<Certificate> certificates;

        public List<Certificate> getCertificates() {
            return certificates;
        }

        public void setCertificates(List<Certificate> certificates) {
            this.certificates = certificates;
        }

        public String getName() {
            return name;
        }

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

        public int getId() {
            return id;
        }

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

        public Department getDepartment() {
            return department;
        }

        public void setDepartment(Department department) {
            this.department = department;
        }

        @Override
        public String toString() {
            return "Student{"
                    + "name='" + name + '\'' + ", id='" + id + '\''
                    + '}';
        }
    }

    static class Department {
        private String name;

        public String getName() {
            return name;
        }

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

    static class Certificate {

        private String name;
        private int year;

        public int getYear() {
            return year;
        }

        public void setYear(int year) {
            this.year = year;
        }

        public String getName() {
            return name;
        }

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

Результатом цієї програми буде наступний рядок:

{
  "id" : 2,
  "name" : "Ali Z",
  "certificates" : [ {
    "name" : "ORACLE",
    "year" : 2000
  }, {
    "name" : "SUN",
    "year" : 2015
  } ],
  "dep" : {
    "name" : "Computer Science"
  }
}

У цьому прикладі ми маємо такі сутності (POJO об'єкти):

Student — клас, який описує студента.

id — унікальний номер кожного студента.

name — ім'я нашого студента.

Department — описує факультет, на якому навчається наш студент.

Certificate — грамоти і нагороди, які отримав наш студент.

  1. За замовчуванням якщо ми ніяк не анотуємо клас, то Jackson дасть JSON поле назви змінної. Для того, щоб наше JSON поле мало іншу назву, необхідно використовувати анотацію @JsonProperty, де в якості параметра передати назву.
  2. Jackson також може сериалізувати List об'єктів в масиву JSON.

Десериалізація в Jackson

Спробуємо десериалізувати наступний JSON рядок:

{"id":2,"name":"Ali Z","certificates":[{"name":"ORACLE","year":2000},{"name":"SUN","year":2015}]}
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.List;

public class DeserializationExample {

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        String json = "{\"id\":2,
\"name\":\"Ali Z\"," +
                        "\"certificates\":[" +
                            "{\"name\":\"ORACLE\",\"year\":2000}," +
                            "{\"name\":\"SUN\",\"year\":2015}" +
                        "]" +
                	     "}";
        Student student = objectMapper.readValue(json, Student.class);
        System.out.println(student);
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    static class Student {
        private int id;
        private String name;

        @JsonProperty("dep")
        private Department department;

        private List<Certificate> certificates;

        public List<Certificate> getCertificates() {
            return certificates;
        }

        public void setCertificates(List<Certificate> certificates) {
            this.certificates = certificates;
        }

        public String getName() {
            return name;
        }

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

        public int getId() {
            return id;
        }

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

        public Department getDepartment() {
            return department;
        }

        public void setDepartment(Department department) {
            this.department = department;
        }

        @Override
        public String toString() {
            return "Student{"
                    + "name='" + name + '\'' + ", id='" + id + '\''
                    + '}';
        }
    }

    static class Department {
        private String name;

        public String getName() {
            return name;
        }

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

    static class Certificate {
        private String name;
        private int year;

        public int getYear() {
            return year;
        }

        public void setYear(int year) {
            this.year = year;
        }

        public String getName() {
            return name;
        }

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

Як ви помітили, наш JSON не містить інформації щодо відділення студента, для того, щоб Jackson не видавав помилку при десериалізації JSON, необхідно позначити клас анотацією @JsonIgnoreProperties (ignoreUnknown = true), або ж задати глобальну конфігурацію наступним чином:

ObjectMapper objectMapper = new ObjectMapper()
                .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);