"Hei kamerat!"

"Hei, Diego."

"Jeg ser her at du har lært det grunnleggende om JSON-serialisering?"

"Hva mener du med "grunnleggende"? Jeg kan mye!"

"Så naivt. Du vet ikke halvparten av det. Ti prosent i beste fall."

"Du tuller. Hva mer er det?"

"Deserialisering av et objekthierarki (polymorf deserialisering), deserialisering av samlinger og mye mer! Jackson-rammeverket er stort og kraftig. Ærlig talt, du har bare begynt å skrape i overflaten."

"Ok, så fortell meg om det - jeg er alle ører."

"Jeg liker virkelig å bli smartere for hver leksjon!"

"Vel, det er en glede å hjelpe, robotvennen min!"

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

"Som du allerede har lært, brukes merknader for både serialisering og deserialisering. I praksis krever serialisering langt mindre informasjon enn 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 av Array, ArrayList, LinkedList og andre klasser gjøres om til JSON-matriser."

"Men når du deserialiserer en JSON-matrise, hvilket objekt bør du lage: en ArrayList eller en LinkedList?"

"Riktig. Hvis et klassemedlem er et grensesnitt (f.eks. offentlig List<Cat> cats ), hvilket objekt skal tilskrives det?"

"Vi kan legge til flere merknader til feltet eller eksplisitt angi målklassene under deserialisering. Se på dette eksemplet:"

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 deserialisert fra JSON
@JsonAutoDetect
class Cat {
 public String name;
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"Med andre ord kan vi bruke den andre parameteren til mapper . readValue- metoden for å sende listen over klasser som skal brukes under deserialisering."

"Jeg liker det. Det er praktisk. Så du kan deserialisere en JSON-array til det du trenger, en ArrayList eller en LinkedList.

"Du nevnte også å bruke merknader. Hvordan gjør du det?"

"Det er enkelt. 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 deserialisert fra JSON
@JsonAutoDetect
class Cat
{
 public String name;
 @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"Vi legger ganske enkelt til merknaden @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class) til linje 5 for å indikere hvilken implementering av List-grensesnittet som skal brukes."

"Ah. Jeg skjønner. Det er egentlig ganske enkelt."

"Men det er mer. Anta at datatypen i en liste også er et grensesnitt! Hva ville du gjort?"

"Bruker vi en merknad her også?"

"Ja, den samme. Du kan også bruke den til å angi parametertypen. Slik:"

Samlingstype Hvordan stille inn datatypen
Liste @JsonDeserialize(contentAs = ValueTypeImpl.class)
Kart @JsonDeserialize(keyAs = KeyTypeImpl.class)

"Kult! Det er virkelig mange merknader som trengs for forskjellige situasjoner vi ikke kan forutse."

"Det er ikke alt. Og det bringer oss til hovedkurset: I virkelige prosjekter arver klasser ganske ofte den samme basisklassen eller grensesnittet, som brukes praktisk talt overalt. Og forestill deg nå at du må deserialisere en datastruktur som inneholder slike 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 skjermutgang:
[
 { "name" : "Missy", "age" : 5},
 { "name" : "Killer", "age" : 8 , "owner" : "Bill Jeferson"}
]

"Vær oppmerksom på resultatet av serialisering."

"Vi kan ikke deserialisere disse dataene til et Java-objekt, siden det i hovedsak ikke kan skilles fra data for andre klasser."

"Det er noen kjennetegn: Hunden har et eierfelt."

"Ja, men dette feltet kan være null eller det kan hoppes fullstendig over under serialisering."

"Vel, kan vi ikke spesifisere datatypen ved å bruke merknader som vi vet?"

"Nei. Etter deserialisering skal en enkelt samling ha forskjellige katte- og hundobjekter, samt et dusin andre klasser som kan arve fra Pet."

"Hva i all verden kan du gjøre her?"

— Her brukes to ting.

"Først er et bestemt felt valgt for å skille en type fra en annen. Hvis det ikke er en, så blir den opprettet."

"For det andre er det spesielle merknader som lar deg kontrollere prosessen med «polymorf deserialisering». Her er hva du kan gjø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 skjermutgang:
{
 "pets" : [
 {"type" : "dog", "name" : "Killer", "age" : 8, "owner" : "Bill Jeferson"},
 {"type" : "cat", "name" : "Missy", "age" : 5}
]
}

Ved å bruke merknader indikerer vi at JSON-representasjonen vil inneholde et spesielt felt kalt type som vil inneholde verdien katt for Cat -klassen, og verdien hund for Dog - klassen. Denne informasjonen er nok til å deserialisere et objekt på riktig måte: under deserialisering vil typen av objektet som skal opprettes bli bestemt av verdien til typefeltet.

"Noen ganger brukes klassenavnet som verdien av typefeltet (f.eks. «com.example.entity.Cat.class»), men dette er ikke en god praksis. Hvordan vil en ekstern applikasjon som mottar vår JSON vite navnene på klassene våre? Verre er det at klassene noen ganger får nytt navn. Det er bedre å bruke et unikt navn for å identifisere en spesifikk klasse."

"Kult! Sukk. Jeg var ikke klar over at deserialisering var så komplisert. Og at det er så mye du kan finjustere."

"Jepp. Dette er nye konsepter for deg, men dette er den typen praktisk kunnskap som vil gjøre deg til en genial programmerer."

"Amigo er en kul programmerer. Kult!"

"OK. Gå og ta en pause."