"Hey vriend!"

"Hé, Diego."

"Ik zie hier dat je de basis van JSON-serialisatie hebt geleerd?"

"Hoe bedoel je 'basics'? Ik weet veel!"

'Zo naïef. Je weet de helft nog niet. Tien procent op zijn best.'

'Je maakt een grapje. Wat is er nog meer?'

"Deserialisatie van een objecthiërarchie (polymorfe deserialisatie), deserialisatie van collecties en nog veel meer! Het Jackson-framework is groot en krachtig. Eerlijk gezegd ben je nog maar aan het begin begonnen."

"Oké, vertel me er dan over - ik ben een en al oor."

"Ik geniet er echt van om met elke les slimmer te worden!"

"Nou, het is mij een genoegen om te helpen, mijn robotvriend!"

"Ben je klaar? Luister dan goed."

"Zoals je al hebt geleerd, worden annotaties gebruikt voor zowel serialisatie als deserialisatie. In de praktijk vereist serialisatie veel minder informatie dan deserialisatie. Bijvoorbeeld:"

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

"Instances van Array, ArrayList, LinkedList en andere klassen worden omgezet in JSON-arrays."

"Maar als je een JSON-array deserialiseert, welk object moet je dan maken: een ArrayList of een LinkedList?"

"Juist. Als een klaslid een interface is (bijv. openbare List<Cat> cats ), welk object moet er dan aan worden toegeschreven?"

"We kunnen extra annotaties toevoegen aan het veld of expliciet de doelklassen aangeven tijdens deserialisatie. Kijk naar dit voorbeeld:"

Converteer een object vanuit 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));
}
Een klasse waarvan de objecten zijn gedeserialiseerd vanuit JSON
@JsonAutoDetect
class Cat {
 public String name;
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"Met andere woorden, we kunnen de tweede parameter van de mapper . readValue- methode gebruiken om de lijst met klassen door te geven die tijdens deserialisatie moeten worden gebruikt."

"Ik vind het leuk. Dat is handig. Je kunt dus een JSON-array deserialiseren naar wat je maar nodig hebt, een ArrayList of een LinkedList.

"Je noemde ook het gebruik van annotaties. Hoe doe je dat?"

"Het is makkelijk. Bijvoorbeeld:"

Converteer een object vanuit 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);
}
Een klasse waarvan de objecten zijn gedeserialiseerd vanuit JSON
@JsonAutoDetect
class Cat
{
 public String name;
 @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"We voegen eenvoudigweg de annotatie @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class) toe aan regel 5 om aan te geven welke implementatie van de List-interface moet worden gebruikt."

"Ah. Ik begrijp het. Dat is echt heel simpel."

"Maar er is meer. Stel dat het gegevenstype in een lijst ook een interface is! Wat zou je doen?"

"Gebruiken we hier ook een annotatie?"

"Ja, dezelfde. Je kunt het ook gebruiken om het parametertype aan te geven. Zoals dit:"

Soort verzameling Hoe het gegevenstype in te stellen
Lijst @JsonDeserialize(contentAs = ValueTypeImpl.class)
Kaart @JsonDeserialize(keyAs = KeyTypeImpl.class)

"Cool! Er zijn echt veel annotaties nodig voor verschillende situaties die we niet kunnen voorzien."

"Dat is niet alles. En dat brengt ons bij het belangrijkste: in echte projecten erven klassen vaak dezelfde basisklasse of interface, die vrijwel overal wordt gebruikt. En stel je nu voor dat je een datastructuur met dergelijke klassen moet deserialiseren. Bijvoorbeeld:"

Converteer een object naar 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());
}
Een klasse waarvan de objecten worden geconverteerd naar 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;
}
Serialisatieresultaat en schermuitvoer:
[
 { "name" : "Missy", "age" : 5},
 { "name" : "Killer", "age" : 8 , "owner" : "Bill Jeferson"}
]

"Let op het resultaat van serialisatie."

"We kunnen deze gegevens niet deserialiseren naar een Java-object, omdat ze in wezen niet te onderscheiden zijn van gegevens voor andere klassen."

"Er zijn enkele onderscheidende kenmerken: Hond heeft een eigenaarsveld."

"Ja, maar dit veld kan null zijn of helemaal worden overgeslagen tijdens serialisatie."

"Nou, kunnen we het gegevenstype niet specificeren met annotaties die we wel kennen?"

"Nee. Na deserialisatie zou een enkele verzameling verschillende Cat- en Dog-objecten moeten hebben, evenals een dozijn andere klassen die van Pet zouden kunnen erven."

"Wat ter wereld kun je hier doen?"

"Hier worden twee dingen gebruikt."

"Eerst wordt een bepaald veld gekozen om het ene type van het andere te onderscheiden. Is er geen, dan wordt het aangemaakt."

"Ten tweede zijn er speciale annotaties waarmee u het proces van "polymorfe deserialisatie" kunt regelen. Dit is wat u kunt doen:"

Converteer een object naar 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());
}
Een klasse waarvan de objecten worden geconverteerd naar 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<>();
}
Serialisatieresultaat en schermuitvoer:
{
 "pets" : [
 {"type" : "dog", "name" : "Killer", "age" : 8, "owner" : "Bill Jeferson"},
 {"type" : "cat", "name" : "Missy", "age" : 5}
]
}

Met behulp van annotaties geven we aan dat de JSON-representatie een speciaal veld met de naam type zal bevatten dat de waarde cat bevat voor de Cat- klasse en de waarde dog voor de Dog- klasse. Deze informatie is voldoende om een ​​object correct te deserialiseren: tijdens de deserialisatie wordt het type van het aan te maken object bepaald door de waarde van het typeveld.

"Soms wordt de klassenaam gebruikt als de waarde van het typeveld (bijv. «com.example.entity.Cat.class»), maar dit is geen goede gewoonte. Hoe zou een externe applicatie die onze JSON ontvangt de namen van onze klassen? Erger nog, klassen worden soms hernoemd. Het is beter om een ​​unieke naam te gebruiken om een ​​specifieke klasse te identificeren."

"Cool! Sigh. I didn't realize deserialization was so complicated. And that there is so much you can fine-tune."

"Yep. These are new concepts for you, but this is the kind of practical knowledge that will make you a genius programmer."

"Amigo is a cool programmer. Cool!"

"OK. Go and take a break."