[Java JSON] Xử lý dữ liệu JSON với Jackson

Chào các bạn, trong bài viết này, chúng ta sẽ cùng tìm hiểu về cách xử lý dữ liệu JSON với Jackson trong Java

Jackson cung cấp phương thức writeValue() và readValue() để chuyển đổi qua lại giữa đối tượng Java và JSON.

mapper.writeValue – Từ Java Objects sang JSON

Java:
    ObjectMapper mapper = new ObjectMapper();

    // Java object to JSON file
    mapper.writeValue(new File("c:\\test\\staff.json"), new Staff());

    // Java object to JSON string, default compact-print
    String jsonString = mapper.writeValueAsString(new Staff());

    // pretty-print
    String jsonString2 = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(new Staff());

mapper.readValue – JSON thành Java Objects

Java:
    ObjectMapper mapper = new ObjectMapper();

    //JSON file to Java object
    Staff obj = mapper.readValue(new File("c:\\test\\staff.json"), Staff.class);

    //JSON URL to Java object
    Staff obj = mapper.readValue(new URL("http://some-domains/api/staff.json"), Staff.class);

    //JSON string to Java Object
    Staff obj = mapper.readValue("{'name' : 'mkyong'}", Staff.class);
P.S Đã test với Jackson 2.9.8

1. Download Jackson
Khai báo jackson-databind, nó sẽ download về jackson-annotations và jackson-core

pom.xml
XML:
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.8</version>
    </dependency>
Terminal
Code:
$ mvn dependency:tree

\- com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile
[INFO]    +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO]    \- com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile

2. POJO
Một đối tượng Java đơn giản, POJO, để kiểm tra về sau.

Staff.java
Java:
public class Staff {

    private String name;
    private int age;
    private String[] position;              //  Array
    private List<String> skills;            //  List
    private Map<String, BigDecimal> salary; //  Map

    // getters , setters, some boring stuff
}

3. Chuyển đổi Java Objects thành JSON

JacksonExample1.java
Java:
package com.mkyong;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class JacksonExample1 {

    public static void main(String[] args) {

        ObjectMapper mapper = new ObjectMapper();

        Staff staff = createStaff();

        try {

            // Java objects to JSON file
            mapper.writeValue(new File("c:\\test\\staff.json"), staff);

            // Java objects to JSON string - compact-print
            String jsonString = mapper.writeValueAsString(staff);

            System.out.println(jsonString);

            // Java objects to JSON string - pretty-print
            String jsonInString2 = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(staff);

            System.out.println(jsonInString2);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static Staff createStaff() {

        Staff staff = new Staff();

        staff.setName("mkyong");
        staff.setAge(38);
        staff.setPosition(new String[]{"Founder", "CTO", "Writer"});
        Map<String, BigDecimal> salary = new HashMap() {{
            put("2010", new BigDecimal(10000));
            put("2012", new BigDecimal(12000));
            put("2018", new BigDecimal(14000));
        }};
        staff.setSalary(salary);
        staff.setSkills(Arrays.asList("java", "python", "node", "kotlin"));

        return staff;

    }

}

Kết quả

c:\\test\\staff.json
JSON:
{"name":"mkyong","age":38,"position":["Founder","CTO","Writer"],"skills":["java","python","node","kotlin"],"salary":{"2018":14000,"2012":12000,"2010":10000}}

Terminal
Code:
{"name":"mkyong","age":38,"position":["Founder","CTO","Writer"],"skills":["java","python","node","kotlin"],"salary":{"2018":14000,"2012":12000,"2010":10000}}

{
  "name" : "mkyong",
  "age" : 38,
  "position" : [ "Founder", "CTO", "Writer" ],
  "skills" : [ "java", "python", "node", "kotlin" ],
  "salary" : {
    "2018" : 14000,
    "2012" : 12000,
    "2010" : 10000
  }
}

4. JSON sang Java Object

JacksonExample2.java
Java:
package com.mkyong;

import com.fasterxml.jackson.databind.ObjectMapper;

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

public class JacksonExample2 {

    public static void main(String[] args) {

        ObjectMapper mapper = new ObjectMapper();

        try {

            // JSON file to Java object
            Staff staff = mapper.readValue(new File("c:\\test\\staff.json"), Staff.class);

            // JSON string to Java object
            String jsonInString = "{\"name\":\"mkyong\",\"age\":37,\"skills\":[\"java\",\"python\"]}";
            Staff staff2 = mapper.readValue(jsonInString, Staff.class);

            // compact print
            System.out.println(staff2);

            // pretty print
            String prettyStaff1 = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(staff2);

            System.out.println(prettyStaff1);


        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

Kết quả

Code:
Staff{name='mkyong', age=37, position=null, skills=[java, python], salary=null}

{
  "name" : "mkyong",
  "age" : 37,
  "position" : null,
  "skills" : [ "java", "python" ],
  "salary" : null
}

5. @JsonProperty – Đặt tên cho JSON Field

5.1 Mặc định

Java:
public class Staff {

    private String name;
    private int age;

Kết quả

JSON:
{"name":"abc", "age":38}

5.2 Thay đổi tên property với @JsonProperty

Java:
public class Staff {

    @JsonProperty("custom_name")
    private String name;
    private int age;

Kết quả

JSON:
{"custom_name":"abc", "age":38}

6. @JsonInclude – Bỏ qua giá trị null
Mặc định, Jackson sẽ xuất ra cả những field có giá trị null

JSON:
{
  "name" : "mkyong",
  "age" : 38,
  "position" : null,
  "skills" : null,
  "salary" : null
}

6.1 @JsonInclude ở tên class (class level)

Staff.java
Java:
import com.fasterxml.jackson.annotation.JsonInclude;

                                            //    ignore null fields , class level
@JsonInclude(JsonInclude.Include.NON_NULL)     //  ignore all null fields
public class Staff {

    private String name;
    private int age;
    private String[] position; 
    private List<String> skills;
    private Map<String, BigDecimal> salary;
    //...

6.2 @JsonInclude ở tên field (fields level).

Staff.java
Java:
import com.fasterxml.jackson.annotation.JsonInclude;

public class Staff {

    private String name;
    private int age;

    @JsonInclude(JsonInclude.Include.NON_NULL) //ignore null field on this property only
    private String[] position; 

    private List<String> skills;

    private Map<String, BigDecimal> salary;

Kết quả

JSON:
{
  "name" : "mkyong",
  "age" : 38,
  "skill" : null,
  "salary" : null
}

6.3 Cấu hình toàn cục

Java:
    ObjectMapper mapper = new ObjectMapper();

    // ignore all null fields globally
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

Ghi chú
Nhiều ví dụ hơn ở bài viết Cách bỏ qua giá trị null với Jackson

7. @JsonView
7.1 @JsonView được sử dụng để giới hạn các field hiển thị cho những người dùng khác nhau. Ví dụ:

CompanyViews.java
Java:
package com.mkyong;

public class CompanyViews {

    public static class Normal{};

    public static class Manager extends Normal{};

}

Thông thường chỉ hiển thị tên và tuổi, Quản lí có thể xem được tất cả.

Staff.java
Java:
import com.fasterxml.jackson.annotation.JsonView;

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

public class Staff {

    @JsonView(CompanyViews.Normal.class)
    private String name;

    @JsonView(CompanyViews.Normal.class)
    private int age;

    @JsonView(CompanyViews.Manager.class)
    private String[] position;

    @JsonView(CompanyViews.Manager.class)
    private List<String> skills;

    @JsonView(CompanyViews.Manager.class)
    private Map<String, BigDecimal> salary;

JacksonExample.java
Java:
package com.mkyong;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class JacksonExample {

    public static void main(String[] args) {

        ObjectMapper mapper = new ObjectMapper();

        Staff staff = createStaff();

        try {

            // to enable pretty print
            mapper.enable(SerializationFeature.INDENT_OUTPUT);

            // normal
            String normalView = mapper
                .writerWithView(CompanyViews.Normal.class)
                .writeValueAsString(staff);

            System.out.format("Normal views\n%s\n", normalView);

            // manager
            String managerView = mapper
                .writerWithView(CompanyViews.Manager.class)
                .writeValueAsString(staff);

            System.out.format("Manager views\n%s\n", managerView);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static Staff createStaff() {

        Staff staff = new Staff();

        staff.setName("mkyong");
        staff.setAge(38);
        staff.setPosition(new String[]{"Founder", "CTO", "Writer"});
        Map<String, BigDecimal> salary = new HashMap() {{
            put("2010", new BigDecimal(10000));
            put("2012", new BigDecimal(12000));
            put("2018", new BigDecimal(14000));
        }};
        staff.setSalary(salary);
        staff.setSkills(Arrays.asList("java", "python", "node", "kotlin"));

        return staff;

    }

}

Kết quả

Code:
Normal views
{
  "name" : "mkyong",
  "age" : 38
}

Manager views
{
  "name" : "mkyong",
  "age" : 38,
  "position" : [ "Founder", "CTO", "Writer" ],
  "skills" : [ "java", "python", "node", "kotlin" ],
  "salary" : {
    "2018" : 14000,
    "2012" : 12000,
    "2010" : 10000
  }
}

Ghi chú
Đọc thêm Jackson @JsonView

8. @JsonIgnore và @JsonIgnoreProperties
Mặc định, Jackson sẽ xuất ra tất cả các field, bao gồm cả các field static hoặc transient.

8.1 @JsonIgnore dùng để bỏ qua những field không muốn xuất ra JSON (dùng ở field level).

Java:
import com.fasterxml.jackson.annotation.JsonIgnore;

public class Staff {

    private String name;
    private int age;
    private String[] position;

    @JsonIgnore
    private List<String> skills;

    @JsonIgnore
    private Map<String, BigDecimal> salary;

Kết quả

JSON:
{
  "name" : "mkyong",
  "age" : 38,
  "position" : [ "Founder", "CTO", "Writer" ]
}

8.2 @JsonIgnoreProperties tương tự như @JsonIgnore nhưng dùng ở class level

Java:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties({"salary", "position"})
public class Staff {

    private String name;
    private int age;
    private String[] position;
    private List<String> skills;
    private Map<String, BigDecimal> salary;

Kết quả

JSON:
{
  "name" : "mkyong",
  "age" : 38,
  "skills" : [ "java", "python", "node", "kotlin" ]
}

9. FAQs
9.1 Chuyển đổi chuỗi JSON dạng mảng thành List

Java:
    String json = "[{\"name\":\"mkyong\", \"age\":38}, {\"name\":\"laplap\", \"age\":5}]";

    List<Staff> list = Arrays.asList(mapper.readValue(json, Staff[].class));

    // or like this:
    // List<Staff> list = mapper.readValue(json, new TypeReference<List<Staff>>(){});

9.2 Chuyển đổi JSON thành Map

Java:
    String json = "{\"name\":\"mkyong\", \"age\":\"33\"}";

    Map<String, String> map = mapper.readValue(json, Map.class);

    // or like this:
    //Map<String, String> map = mapper.readValue(json, new TypeReference<Map<String, String>>(){});

    map.forEach((k, v) -> System.out.format("[key]:%s \t[value]:%s\n", k, v));

Kết quả

Code:
[key]:name     [value]:mkyong
[key]:age     [value]:33

9.3 Điều gì xảy ra nếu xử lý cấu trúc JSON phức tạp không dễ dàng ánh xạ tới lớp Java?
Trả lời: Thử với Jackson TreeModel để chuyển đổi dữ liệu JSON sang JsonNode, sau đó, có thể thêm, cập nhật hoặc xóa các node JSON dễ dàng.


Cám ơn các bạn đã theo dõi. Hẹn gặp lại các bạn trong các bài viết sau :)

Bài viết tham khảo tại: https://mkyong.com/java/jackson-how-to-parse-json
 
Sửa lần cuối:

Bình luận