"Chào anh bạn!"

"Này, Diego."

"Tôi thấy ở đây bạn đã học những kiến ​​thức cơ bản về tuần tự hóa JSON?"

"Ý bạn 'cơ bản' là gì? Tôi biết rất nhiều!"

"Thật ngây thơ. Anh không biết một nửa của nó. Mười phần trăm là nhiều nhất."

"Đùa đấy. Còn gì nữa không?"

"Khử tuần tự hóa một hệ thống phân cấp đối tượng (khử lưu huỳnh hóa đa hình), khử lưu huỳnh hóa các bộ sưu tập, v.v. Khung Jackson rất lớn và mạnh mẽ. Thành thật mà nói, bạn mới chỉ bắt đầu làm xước bề mặt."

"Được rồi, vậy thì hãy nói cho tôi biết về nó - tôi nghe rõ đây."

"Tôi thực sự thích trở nên thông minh hơn với mỗi bài học!"

"Chà, tôi rất vui được giúp đỡ, người bạn robot của tôi!"

"Sẵn sàng chưa? Vậy thì nghe đây."

"Như bạn đã biết, các chú thích được sử dụng cho cả tuần tự hóa và giải tuần tự hóa. Trong thực tế, quá trình tuần tự hóa yêu cầu ít thông tin hơn nhiều so với quá trình giải tuần tự hóa. Ví dụ:"

lớp Java JSON
class Cat
{
 public String name = "missy";
 public Cat[] cats = new Cat[0];
}
{
 "name": "missy",
 "cats": []
}
class Cat
{
 public String name = "missy";
 public List cats = new ArrayList<Cat>();
}
{
 "name": "missy",
 "cats": []
}
class Cat
{
 public String name = "missy";
 public List cats = new LinkedList<Cat>();
}
{
 "name": "missy",
 "cats": []
}

"Các thể hiện của Array, ArrayList, LinkedList và các lớp khác được chuyển thành các mảng JSON."

"Nhưng khi bạn deserialize một mảng JSON, bạn nên tạo đối tượng nào: ArrayList hay LinkedList?"

"Phải. Nếu một thành viên lớp là một giao diện (ví dụ: public List<Cat> cats ), đối tượng nào sẽ được gán cho nó?"

"Chúng tôi có thể thêm các chú thích bổ sung vào trường hoặc chỉ ra rõ ràng các lớp mục tiêu trong quá trình khử lưu huỳnh. Hãy xem ví dụ sau:"

Chuyển đổi một đối tượng từ JSON
public static void main(String[] args) throws IOException
{
 String jsonString = ""{\"name\":\"Missy\",\"cats\":[{\"name\":\"Timmy\"},{\"name\":\"Killer\"}]}"";
 StringReader reader = new StringReader(jsonString);
 ObjectMapper mapper = new ObjectMapper();
 Cat cat = mapper.readValue(reader, TypeFactory.collectionType(ArrayList.class, Cat.class));
}
Một lớp có các đối tượng được giải tuần tự hóa từ JSON
@JsonAutoDetect
class Cat {
 public String name;
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"Nói cách khác, chúng ta có thể sử dụng tham số thứ hai của phương thức . readValue của trình ánh xạ để chuyển danh sách các lớp sẽ sử dụng trong quá trình khử lưu huỳnh."

"Tôi thích nó. Điều đó thật tiện lợi. Vì vậy, bạn có thể giải tuần tự hóa một mảng JSON thành bất cứ thứ gì bạn cần, một ArrayList hoặc một LinkedList.

"Bạn cũng đã đề cập đến việc sử dụng chú thích. Làm thế nào để bạn làm điều đó?"

"Thật dễ dàng. Ví dụ:"

Chuyển đổi một đối tượng từ JSON
public static void main(String[] args) throws IOException
{
 String jsonString = ""{\"name\":\"Missy\",\"cats\":[{\"name\":\"Timmy\"},{\"name\":\"Killer\"}]}"";
 StringReader reader = new StringReader(jsonString);

 ObjectMapper mapper = new ObjectMapper();

 Cat cat = mapper.readValue(reader, Cat.class);
}
Một lớp có các đối tượng được giải tuần tự hóa từ JSON
@JsonAutoDetect
class Cat
{
 public String name;
 @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"Chúng tôi chỉ cần thêm chú thích @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class) vào dòng 5 để cho biết triển khai giao diện Danh sách nào sẽ sử dụng."

"À. Tôi hiểu rồi. Điều đó thực sự khá đơn giản."

"Nhưng còn nữa. Giả sử kiểu dữ liệu trong Danh sách cũng là một giao diện! Bạn sẽ làm gì?"

"Chúng ta có sử dụng chú thích ở đây không?"

"Vâng, giống nhau. Bạn cũng có thể sử dụng nó để biểu thị loại tham số. Như thế này:"

Loại bộ sưu tập Cách đặt kiểu dữ liệu
Danh sách @JsonDeserialize(contentAs = ValueTypeImpl.class)
Bản đồ @JsonDeserialize(keyAs = KeyTypeImpl.class)

"Tuyệt! Thực sự có rất nhiều chú thích cần thiết cho các tình huống khác nhau mà chúng tôi không thể lường trước được."

"Đó không phải là tất cả. Và điều đó đưa chúng ta đến khóa học chính: trong các dự án thực tế, các lớp thường kế thừa cùng một lớp cơ sở hoặc giao diện, được sử dụng hầu như ở mọi nơi. Và bây giờ hãy tưởng tượng rằng bạn cần giải tuần tự hóa một cấu trúc dữ liệu chứa các lớp như vậy. Ví dụ:"

Chuyển đổi một đối tượng thành JSON
public static void main(String[] args) throws IOException
{
 Cat cat = new Cat();
 cat.name = "Missy";
 cat.age = 5;

 Dog dog = new Dog();
 dog.name = "Killer";
 dog.age = 8;
 dog.owner = "Bill Jefferson";

 ArrayList<Pet> pets = new ArrayList<Pet>();
 pets.add(cat);
 pets.add(dog);

 StringWriter writer = new StringWriter();
 ObjectMapper mapper = new ObjectMapper();
 mapper.writeValue(writer, pets);
 System.out.println(writer.toString());
}
Một lớp có các đối tượng chuyển đổi thành JSON
@JsonAutoDetect
class Pet
{
 public String name;
}

@JsonAutoDetect
class Cat extends Pet
{
 public int age;
}

@JsonAutoDetect
class Dog extends Pet
{
 public int age;
 public String owner;
}
Kết quả tuần tự hóa và đầu ra màn hình:
[
 { "name" : "Missy", "age" : 5},
 { "name" : "Killer", "age" : 8 , "owner" : "Bill Jeferson"}
]

"Hãy chú ý đến kết quả của việc tuần tự hóa."

"Chúng tôi không thể giải tuần tự hóa dữ liệu này thành một đối tượng Java, vì về cơ bản nó không thể phân biệt được với dữ liệu của các lớp khác."

"Có một số tính năng phân biệt: Con chó có một lĩnh vực chủ sở hữu."

"Có, nhưng trường này có thể là null hoặc nó có thể bị bỏ qua hoàn toàn trong quá trình lập số sê-ri."

"Chà, chúng ta không thể chỉ định loại dữ liệu bằng cách sử dụng các chú thích mà chúng ta biết sao?"

"Không. Sau khi khử lưu huỳnh, một bộ sưu tập duy nhất sẽ có nhiều đối tượng Mèo và Chó khác nhau, cũng như hàng chục lớp khác có thể kế thừa từ Pet."

"Bạn có thể làm cái quái gì ở đây?"

"Hai thứ được sử dụng ở đây."

"Đầu tiên, một trường nhất định được chọn để phân biệt loại này với loại khác. Nếu không có trường nào, thì trường đó sẽ được tạo."

"Thứ hai, có các chú thích đặc biệt cho phép bạn kiểm soát quá trình «khử lưu huỳnh đa hình». Đây là những gì bạn có thể làm:"

Chuyển đổi một đối tượng thành JSON
public static void main(String[] args) throws IOException
{
 Cat cat = new Cat();
 cat.name = "Missy";
 cat.age = 5;

 Dog dog = new Dog();
 dog.name = "Killer";
 dog.age = 8;
 dog.owner = "Bill Jeferson";

 House house = new House();
 house.pets.add(dog);
 house.pets.add(cat);

 StringWriter writer = new StringWriter();
 ObjectMapper mapper = new ObjectMapper();
 mapper.writeValue(writer, house);
 System.out.println(writer.toString());
}
Một lớp có các đối tượng chuyển đổi thành JSON
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Cat.class, name = "cat"),
@JsonSubTypes.Type(value = Dog.class, name = "dog")
})
class Pet
{
 public String name;
}

class Cat extends Pet
{
 public int age;
}

class Dog extends Pet
{
 public int age;
 public String owner;
}

class House
{
 public List&ltPet> pets = new ArrayList<>();
}
Kết quả tuần tự hóa và đầu ra màn hình:
{
 "pets" : [
 {"type" : "dog", "name" : "Killer", "age" : 8, "owner" : "Bill Jeferson"},
 {"type" : "cat", "name" : "Missy", "age" : 5}
]
}

Sử dụng các chú thích, chúng tôi chỉ ra rằng biểu diễn JSON sẽ chứa một trường đặc biệt được gọi là loại sẽ giữ giá trị cat cho lớp Cat và giá trị dog cho lớp Dog . Thông tin này đủ để giải tuần tự hóa một đối tượng đúng cách: trong quá trình giải tuần tự hóa, loại đối tượng được tạo sẽ được xác định bởi giá trị của trường loại.

"Đôi khi tên lớp được sử dụng làm giá trị của trường loại (ví dụ: «com.example.entity.Cat.class»), nhưng đây không phải là một phương pháp hay. Làm cách nào để ứng dụng bên ngoài nhận JSON của chúng tôi biết tên của các lớp của chúng ta? Tệ hơn nữa, các lớp đôi khi được đổi tên. Tốt hơn là sử dụng một số tên duy nhất để xác định một lớp cụ thể."

"Tuyệt! Haizz. Tôi không nhận ra quá trình khử lưu huỳnh lại phức tạp đến vậy. Và bạn có thể tinh chỉnh rất nhiều thứ."

"Đúng. Đây là những khái niệm mới đối với bạn, nhưng đây là loại kiến ​​thức thực tế sẽ giúp bạn trở thành một lập trình viên thiên tài."

"Amigo là một lập trình viên tuyệt vời. Tuyệt vời!"

"Được. Đi nghỉ đi."