"Hai teman!"

"Hei, Diego."

"Saya lihat di sini Anda telah mempelajari dasar-dasar serialisasi JSON?"

"Apa maksudmu 'dasar'? Aku tahu banyak!"

"Sangat naif. Kamu tidak tahu setengahnya. Paling banter sepuluh persen."

"Kamu bercanda. Ada apa lagi?"

"Deserialisasi hierarki objek (deserialisasi polimorfik), deserialisasi koleksi, dan banyak lagi! Kerangka kerja Jackson besar dan kuat. Sejujurnya, Anda baru mulai menggores permukaannya."

"Oke, kalau begitu ceritakan tentang itu - aku mendengarkan."

"Saya benar-benar menikmati menjadi lebih pintar dengan setiap pelajaran!"

"Yah, dengan senang hati membantu, teman robotku!"

"Apakah kamu siap? Lalu dengarkan."

"Seperti yang telah Anda pelajari, anotasi digunakan untuk serialisasi dan deserialisasi. Dalam praktiknya, serialisasi memerlukan informasi yang jauh lebih sedikit daripada deserialisasi. Misalnya:"

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

"Instance Array, ArrayList, LinkedList, dan kelas lainnya diubah menjadi array JSON."

"Tetapi ketika Anda melakukan deserialisasi array JSON, objek apa yang harus Anda buat: ArrayList atau LinkedList?"

"Benar. Jika anggota kelas adalah sebuah antarmuka (misalnya public List<Cat> cats ), objek apa yang harus dikaitkan dengannya?"

"Kita dapat menambahkan anotasi tambahan ke bidang atau secara eksplisit menunjukkan kelas target selama deserialisasi. Lihat contoh ini:"

Mengonversi objek dari 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));
}
Kelas yang objeknya dideserialisasi dari JSON
@JsonAutoDetect
class Cat {
 public String name;
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"Dengan kata lain, kita bisa menggunakan parameter kedua dari metode mapper .readValue untuk meneruskan daftar kelas yang akan digunakan selama deserialisasi. "

"Saya menyukainya. Nyaman. Jadi, Anda dapat melakukan deserialisasi array JSON menjadi apa pun yang Anda butuhkan, ArrayList atau LinkedList.

"Kamu juga menyebutkan menggunakan anotasi. Bagaimana kamu melakukannya?"

"Gampang. Misalnya:"

Mengonversi objek dari 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);
}
Kelas yang objeknya dideserialisasi dari JSON
@JsonAutoDetect
class Cat
{
 public String name;
 @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"Kami cukup menambahkan anotasi @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class) ke baris 5 untuk menunjukkan implementasi mana dari antarmuka Daftar yang akan digunakan."

"Ah. Begitu. Itu sangat sederhana."

"Tapi masih ada lagi. Misalkan tipe data dalam Daftar juga merupakan antarmuka! Apa yang akan Anda lakukan?"

"Apakah kita menggunakan anotasi di sini juga?"

"Ya, sama. Anda juga bisa menggunakannya untuk menunjukkan tipe parameter. Seperti ini:"

Jenis koleksi Cara mengatur tipe data
Daftar @JsonDeserialize(contentAs = ValueTypeImpl.class)
Peta @JsonDeserialize(keyAs = KeyTypeImpl.class)

"Keren! Memang ada banyak anotasi yang dibutuhkan untuk berbagai situasi yang tidak bisa kami antisipasi."

"Bukan itu saja. Dan itu membawa kita ke kursus utama: dalam proyek nyata, kelas cukup sering mewarisi kelas dasar atau antarmuka yang sama, yang digunakan hampir di mana saja. Dan sekarang bayangkan Anda perlu melakukan deserialisasi struktur data yang berisi kelas semacam itu. Misalnya:"

Mengkonversi objek ke 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());
}
Kelas yang objeknya diubah menjadi 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;
}
Hasil serialisasi dan output layar:
[
 { "name" : "Missy", "age" : 5},
 { "name" : "Killer", "age" : 8 , "owner" : "Bill Jeferson"}
]

"Perhatikan hasil serialisasi."

"Kami tidak dapat membatalkan serialisasi data ini ke dalam objek Java, karena pada dasarnya tidak dapat dibedakan dari data untuk kelas lain."

"Ada beberapa fitur yang membedakan: Anjing memiliki bidang pemilik."

"Ya, tapi kolom ini bisa kosong atau bisa dilewati seluruhnya selama serialisasi."

"Yah, tidak bisakah kita menentukan tipe data menggunakan anotasi yang kita ketahui?"

"Tidak. Setelah deserialisasi, satu koleksi harus memiliki berbagai objek Kucing dan Anjing, serta selusin kelas lain yang dapat diwarisi dari Pet."

"Apa yang bisa kamu lakukan di sini?"

"Dua hal digunakan di sini."

"Pertama, bidang tertentu dipilih untuk membedakan satu jenis dari yang lain. Jika tidak ada, maka dibuat."

"Kedua, ada anotasi khusus yang memungkinkan Anda mengontrol proses «deserialisasi polimorfik». Inilah yang dapat Anda lakukan:"

Mengkonversi objek ke 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());
}
Kelas yang objeknya diubah menjadi 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<>();
}
Hasil serialisasi dan output layar:
{
 "pets" : [
 {"type" : "dog", "name" : "Killer", "age" : 8, "owner" : "Bill Jeferson"},
 {"type" : "cat", "name" : "Missy", "age" : 5}
]
}

Menggunakan anotasi, kami menunjukkan bahwa representasi JSON akan berisi bidang khusus yang disebut tipe yang akan menampung nilai kucing untuk kelas Kucing , dan nilai anjing untuk kelas Anjing . Informasi ini cukup untuk melakukan deserialisasi objek dengan benar: selama deserialisasi, tipe objek yang akan dibuat akan ditentukan oleh nilai bidang tipe.

"Kadang-kadang nama kelas digunakan sebagai nilai bidang jenis (misalnya «com.example.entity.Cat.class»), tetapi ini bukan praktik yang baik. Bagaimana aplikasi eksternal yang menerima JSON kami mengetahui nama-nama kelas kita? Lebih buruk lagi, kelas terkadang diganti namanya. Lebih baik menggunakan beberapa nama unik untuk mengidentifikasi kelas tertentu."

"Keren! Huh. Aku tidak menyadari deserialization begitu rumit. Dan ada begitu banyak yang bisa kamu sesuaikan."

"Ya. Ini adalah konsep baru untukmu, tapi ini adalah jenis pengetahuan praktis yang akan membuatmu menjadi programmer yang jenius."

"Amigo adalah programmer yang keren. Keren!"

"Oke. Pergi dan istirahatlah."