"Hej makker!"

"Hej, Diego."

"Jeg kan se, at du har lært det grundlæggende i JSON-serialisering?"

"Hvad mener du med 'basics'? Jeg ved en masse!"

"Så naivt. Du kender ikke halvdelen af ​​det. I bedste fald ti procent."

"Du laver sjov. Hvad er der ellers?"

"Deserialisering af et objekthierarki (polymorf deserialisering), deserialisering af samlinger og en hel masse mere! Jackson-rammen er stor og kraftfuld. Helt ærligt, du er kun begyndt at ridse overfladen."

"Okay, så fortæl mig om det - jeg er alle ører."

"Jeg nyder virkelig at blive klogere for hver lektion!"

"Nå, det er mig en fornøjelse at hjælpe, min robotven!"

"Er du klar? Så hør efter."

"Som du allerede har lært, bruges annoteringer til både serialisering og deserialisering. I praksis kræver serialisering langt mindre information end deserialisering. For eksempel:"

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

"Forekomster af Array, ArrayList, LinkedList og andre klasser omdannes til JSON-arrays."

"Men når du deserialiserer et JSON-array, hvilket objekt skal du så oprette: en ArrayList eller en LinkedList?"

"Right. Hvis et klassemedlem er en grænseflade (f.eks. offentlig List<Cat> cats ), hvilket objekt skal tilskrives det?"

"Vi kan tilføje yderligere anmærkninger til feltet eller eksplicit angive målklasserne under deserialisering. Se på dette eksempel:"

Konverter et objekt fra 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));
}
En klasse, hvis objekter er deserialiseret fra JSON
@JsonAutoDetect
class Cat {
 public String name;
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"Med andre ord kan vi bruge den anden parameter i mapper . readValue- metoden til at videregive listen over klasser, der skal bruges under deserialisering."

"Jeg kan godt lide det. Det er praktisk. Så du kan deserialisere et JSON-array til hvad du har brug for, en ArrayList eller en LinkedList.

"Du nævnte også at bruge anmærkninger. Hvordan gør du det?"

"Det er nemt. For eksempel:"

Konverter et objekt fra 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);
}
En klasse, hvis objekter er deserialiseret fra JSON
@JsonAutoDetect
class Cat
{
 public String name;
 @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"Vi tilføjer simpelthen annotationen @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class) til linje 5 for at angive, hvilken implementering af List-grænsefladen, der skal bruges."

"Ah. Jeg forstår det. Det er virkelig ret simpelt."

"Men der er mere. Antag, at datatypen i en liste også er en grænseflade! Hvad ville du gøre?"

"Bruger vi også en anmærkning her?"

"Ja, den samme. Du kan også bruge den til at angive parametertypen. Sådan:"

Samlingstype Sådan indstilles datatypen
Liste @JsonDeserialize(contentAs = ValueTypeImpl.class)
Kort @JsonDeserialize(keyAs = KeyTypeImpl.class)

"Fedt! Der er virkelig brug for mange annoteringer til forskellige situationer, vi ikke kan forudse."

"Det er ikke alt. Og det bringer os til hovedforløbet: I rigtige projekter arver klasser ret ofte den samme basisklasse eller grænseflade, som bruges stort set overalt. Og forestil dig nu, at du skal deserialisere en datastruktur, der indeholder sådanne klasser. For eksempel:"

Konverter et objekt til 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());
}
En klasse, hvis objekter konverteres til 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;
}
Serialiseringsresultat og skærmoutput:
[
 { "name" : "Missy", "age" : 5},
 { "name" : "Killer", "age" : 8 , "owner" : "Bill Jeferson"}
]

"Vær opmærksom på resultatet af serialisering."

"Vi kan ikke deserialisere disse data til et Java-objekt, da det i det væsentlige ikke kan skelnes fra data for andre klasser."

"Der er nogle kendetegn: Hund har et ejerfelt."

"Ja, men dette felt kan være nul, eller det kan springes helt over under serialisering."

"Nå, kan vi ikke specificere datatypen ved hjælp af annoteringer, som vi kender?"

"Nej. Efter deserialisering skulle en enkelt samling have forskellige katte- og hundegenstande, samt et dusin andre klasser, der kunne arve fra Pet."

"Hvad i alverden kan du gøre her?"

"Her bruges to ting."

"For det første vælges et bestemt felt for at skelne en type fra en anden. Hvis der ikke er en, så oprettes den."

"For det andet er der specielle annotationer, der lader dig styre processen med «polymorf deserialisering». Her er, hvad du kan gøre:"

Konverter et objekt til 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());
}
En klasse, hvis objekter konverteres til 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<>();
}
Serialiseringsresultat og skærmoutput:
{
 "pets" : [
 {"type" : "dog", "name" : "Killer", "age" : 8, "owner" : "Bill Jeferson"},
 {"type" : "cat", "name" : "Missy", "age" : 5}
]
}

Ved hjælp af annoteringer angiver vi, at JSON-repræsentationen vil indeholde et særligt felt kaldet type , der vil indeholde værdien kat for Cat -klassen og værdien hund for Hund- klassen. Disse oplysninger er nok til at deserialisere et objekt korrekt: under deserialiseringen vil typen af ​​objektet, der skal oprettes, blive bestemt af værdien af ​​typefeltet.

"Nogle gange bruges klassenavnet som værdien af ​​typefeltet (f.eks. «com.example.entity.Cat.class»), men dette er ikke en god praksis. Hvordan ville en ekstern applikation, der modtager vores JSON, kende navnene på vores klasser? Hvad værre er, klasser bliver nogle gange omdøbt. Det er bedre at bruge et unikt navn til at identificere en bestemt klasse."

"Fedt! Suk. Jeg var ikke klar over at deserialisering var så kompliceret. Og at der er så meget, du kan finjustere."

"Jep. Det er nye koncepter for dig, men det er den slags praktisk viden, der vil gøre dig til en genial programmør."

"Amigo er en sej programmør. Fedt!"

"OK. Gå og tag en pause."