"สวัสดีเพื่อน!"

"เฮ้ ดิเอโก้"

"ฉันเห็นว่าคุณได้เรียนรู้พื้นฐานของการทำให้เป็นอนุกรม JSON แล้ว"

"คุณหมายถึงอะไร 'พื้นฐาน' ฉันรู้มาก!"

“ไร้เดียงสามาก คุณไม่รู้ครึ่งหนึ่งของมัน ดีที่สุดสิบเปอร์เซ็นต์”

“ล้อเล่นนะ มีอะไรอีก”

"การดีซีเรียลไลเซชันของลำดับชั้นของออบเจ็กต์ (การดีซีเรียลไลเซชันแบบโพลีมอร์ฟิก) การดีซีเรียลไลเซชันของคอลเล็กชัน และอื่นๆ อีกมากมาย! กรอบงานของ Jackson นั้นใหญ่และทรงพลัง พูดตามตรง คุณเพิ่งเริ่มเกาพื้นผิวเท่านั้น"

“โอเค งั้นก็เล่ามาสิ ฉันหูฝาด”

"ฉันสนุกกับการฉลาดขึ้นในแต่ละบทเรียน!"

"ดี ฉันยินดีช่วย เพื่อนหุ่นยนต์ของฉัน!"

“คุณพร้อมหรือยัง?

"ตามที่คุณได้เรียนรู้แล้ว คำอธิบายประกอบจะใช้สำหรับทั้งการทำให้เป็นอนุกรมและการแยกซีเรียล ในทางปฏิบัติ การทำให้เป็นอนุกรมต้องการข้อมูลน้อยกว่าการแยกซีเรียลอย่างมาก ตัวอย่างเช่น:"

คลาสจาวา เจสัน
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"

"แต่เมื่อคุณ deserialize อาร์เรย์ JSON คุณควรสร้างวัตถุใด: ArrayList หรือ LinkedList"

"ถูกต้อง หากสมาชิกคลาสเป็นอินเทอร์เฟซ (เช่นสาธารณะ 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));
}
คลาสที่มีอ็อบเจ็กต์ถูก deserialized จาก JSON
@JsonAutoDetect
class Cat {
 public String name;
 public List<Cat> cats = new ArrayList<>();
 Cat() {
 }
}

"กล่าวอีกนัยหนึ่ง เราสามารถใช้พารามิเตอร์ตัวที่สองของเมธอดmapper .readValueเพื่อส่งรายการคลาสที่จะใช้ในระหว่างการดีซีเรียลไลเซชัน"

"ฉันชอบมัน สะดวกดี คุณจึงสามารถ deserialize อาร์เรย์ 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);
}
คลาสที่มีอ็อบเจ็กต์ถูก deserialized จาก JSON
@JsonAutoDetect
class Cat
{
 public String name;
 @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)
 public List<Cat> cats = new ArrayList<>();
 Cat() {
 }
}

"เราเพียงเพิ่มคำอธิบายประกอบ@JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)ในบรรทัดที่ 5 เพื่อระบุว่าจะใช้อินเทอร์เฟซรายการใด"

"อา ฉันเข้าใจแล้ว มันค่อนข้างง่ายจริงๆ"

"แต่ยังมีมากกว่านั้น สมมติว่าชนิดข้อมูลในรายการเป็นอินเทอร์เฟซด้วย! คุณจะทำอย่างไร"

"เราใช้คำอธิบายประกอบที่นี่ด้วยหรือไม่"

"ใช่อันเดียวกัน คุณยังสามารถใช้เพื่อระบุประเภทพารามิเตอร์ แบบนี้:"

ประเภทคอลเลกชัน วิธีกำหนดประเภทข้อมูล
รายการ @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"}
]

"ให้ความสนใจกับผลลัพธ์ของการทำให้เป็นอนุกรม"

"เราไม่สามารถ deserialize ข้อมูลนี้เป็นอ็อบเจกต์ Java ได้ เนื่องจากโดยพื้นฐานแล้วมันแยกไม่ออกจากข้อมูลสำหรับคลาสอื่น"

"มีคุณสมบัติที่แตกต่าง: สุนัขมีเขตข้อมูลเจ้าของ"

"ใช่ แต่ฟิลด์นี้อาจเป็นโมฆะหรืออาจถูกข้ามไปทั้งหมดระหว่างการทำให้เป็นอันดับ"

"เราไม่สามารถระบุประเภทข้อมูลโดยใช้คำอธิบายประกอบที่เรารู้จักได้หรือไม่"

"ไม่ หลังจากการดีซีเรียลไลเซชัน คอลเลกชันเดียวควรมีออบเจกต์แมวและสุนัขหลายรายการ รวมถึงคลาสอื่นๆ อีกหลายสิบคลาสที่สามารถสืบทอดจากเพ็ตได้"

"มาทำอะไรที่นี่"

"ใช้สองอย่างที่นี่"

"อย่างแรกฟิลด์บางฟิลด์ถูกเลือกเพื่อแยกประเภทหนึ่งออกจากอีกประเภทหนึ่งหากไม่มีฟิลด์ใดฟิลด์หนึ่ง ฟิลด์นั้นจะถูกสร้าง"

"ประการที่สอง มีคำอธิบายประกอบพิเศษที่ให้คุณควบคุมกระบวนการของ «การแยกซีเรียลไลเซชันแบบโพลีมอร์ฟิค» นี่คือสิ่งที่คุณสามารถทำได้:"

แปลงวัตถุเป็น 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<Pet> 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 ของเราจะทราบชื่อของ ชั้นเรียนของเราหรือที่แย่กว่านั้นคือบางครั้งมีการเปลี่ยนชื่อชั้นเรียน ดังนั้น ควรใช้ชื่อเฉพาะเพื่อระบุชั้นเรียนที่เฉพาะเจาะจงจะดีกว่า"

"เจ๋ง! เฮ้อ ฉันไม่นึกเลยว่าการดีซีเรียลไลเซชันจะซับซ้อนขนาดนี้ และมีอะไรอีกมากที่คุณสามารถปรับแต่งได้"

"ใช่แล้ว นี่เป็นแนวคิดใหม่สำหรับคุณ แต่นี่เป็นความรู้เชิงปฏิบัติที่จะทำให้คุณเป็นโปรแกรมเมอร์อัจฉริยะ"

"Amigo เป็นโปรแกรมเมอร์ที่ยอดเยี่ยม เจ๋ง!"

"ตกลง ไปพักเถอะ"