“嗨兄弟!”

“嘿,迭戈。”

“我看到這裡你已經學習了 JSON 序列化的基礎知識?”

“‘基礎’是什麼意思?我知道很多!”

“太天真了。你連一半都不知道。最多只有百分之十。”

“開什麼玩笑,還有什麼?”

“對象層次結構的反序列化(多態反序列化)、集合的反序列化,以及更多!Jackson 框架龐大而強大。老實說,您才剛剛開始觸及皮毛。”

“好吧,那就告訴我吧——我洗耳恭聽。”

“我真的很享受每節課變得更聰明!”

“嗯,很高興能幫上忙,我的機器人朋友!”

“準備好了嗎?那就听好了。”

“正如您已經了解到的,註釋用於序列化和反序列化。實際上,序列化需要的信息遠少於反序列化。例如:”

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": []
}

“Array、ArrayList、LinkedList 和其他類的實例被轉換為 JSON 數組。”

“但是當你反序列化一個 JSON 數組時,你應該創建什麼對象:ArrayList 還是 LinkedList?”

“對。如果一個類成員是一個接口(例如public List<Cat> cats),應該將什麼對象歸於它?”

“我們可以在字段中添加額外的註釋,或者在反序列化過程中明確指出目標類。看這個例子:”

從 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));
}
其對像從 JSON 反序列化的類
@JsonAutoDetect
class Cat {
 public String name;
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

“換句話說,我們可以使用映射器的第二個參數.readValue方法來傳遞要在反序列期間使用的類列表。”

“我喜歡它。這很方便。因此您可以將 JSON 數組反序列化為您需要的任何內容,ArrayList 或 LinkedList。

“你還提到了使用註解。你是怎麼做到的?”

“這很簡單。例如:”

從 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);
}
其對像從 JSON 反序列化的類
@JsonAutoDetect
class Cat
{
 public String name;
 @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

“我們只需將註釋@JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)添加到第 5 行,以指示使用 List 接口的哪個實現。”

“啊,原來如此。那還真是很簡單呢。”

“但還有更多。假設List中的數據類型也是接口!你會怎麼做?”

“我們在這裡也使用註釋嗎?”

“是的,同一個。你也可以用它來表示參數類型。像這樣:”

集合類型 如何設置數據類型
列表 @JsonDeserialize(contentAs = ValueTypeImpl.class)
地圖 @JsonDeserialize(keyAs = KeyTypeImpl.class)

“酷!對於我們無法預料的各種情況,確實需要很多註釋。”

“這還不是全部。這讓我們進入了主要課程:在實際項目中,類經常繼承相同的基類或接口,幾乎無處不在。現在想像一下,您需要反序列化包含此類的數據結構。例如:”

將對象轉換為 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());
}
對象轉換為 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;
}
序列化結果和屏幕輸出:
[
 { "name" : "Missy", "age" : 5},
 { "name" : "Killer", "age" : 8 , "owner" : "Bill Jeferson"}
]

“注意連載結果。”

“我們無法將這些數據反序列化為 Java 對象,因為它與其他類的數據本質上沒有區別。”

“有一些顯著特徵: Dog 有一個 owner 字段。”

“是的,但這個字段可以為空,也可以在序列化期間完全跳過。”

“嗯,我們不能使用我們知道的註釋來指定數據類型嗎?”

“不。反序列化後,單個集合應該有各種 Cat 和 Dog 對象,以及十幾個可以從 Pet 繼承的其他類。”

“你到底能在這裡做什麼?”

“這裡用到了兩個東西。”

“首先,選擇某個字段來區分一種類型。如果沒有,則創建它。”

“其次,有一些特殊的註釋可以讓你控制 «多態反序列化» 的過程。這是你可以做的:”

將對象轉換為 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());
}
對象轉換為 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<>();
}
序列化結果和屏幕輸出:
{
 "pets" : [
 {"type" : "dog", "name" : "Killer", "age" : 8, "owner" : "Bill Jeferson"},
 {"type" : "cat", "name" : "Missy", "age" : 5}
]
}

使用註釋,我們指出 JSON 表示將包含一個名為type 的特殊字段,它將保存Cat類的值cat和Dog類的值dog。此信息足以正確反序列化對象:在反序列化過程中,要創建的對象的類型將由類型字段的值確定。

“有時類名用作類型字段的值(例如 «com.example.entity.Cat.class»),但這不是一個好的做法。接收我們的 JSON 的外部應用程序如何知道名稱我們的班級?更糟糕的是,班級有時會被重命名。最好使用一些唯一的名稱來標識特定的班級。”

“太棒了!嘆息。我沒有意識到反序列化如此復雜。而且您可以微調的地方如此之多。”

“是的。這些對你來說是新概念,但這是一種能讓你成為天才程序員的實用知識。”

“阿米戈是個很酷的程序員。酷!”

“行了,你去休息吧。”