"Hi Kumpel!"

„Hey, Diego.“

„Wie ich sehe, haben Sie hier die Grundlagen der JSON-Serialisierung gelernt?“

„Was meinst du mit ‚Grundlagen‘? Ich weiß eine Menge!“

„So naiv. Du weißt nicht die Hälfte davon. Bestenfalls zehn Prozent.“

„Das ist ein Scherz. Was gibt es sonst noch?“

„Deserialisierung einer Objekthierarchie (polymorphe Deserialisierung), Deserialisierung von Sammlungen und vieles mehr! Das Jackson-Framework ist umfangreich und leistungsstark. Ehrlich gesagt haben Sie gerade erst begonnen, an der Oberfläche zu kratzen.“

„Okay, dann erzähl mir davon – ich bin ganz Ohr.“

„Ich genieße es wirklich, mit jeder Lektion schlauer zu werden!“

„Nun, es ist mir eine Freude zu helfen, mein Roboterfreund!“

„Bist du bereit? Dann hör zu.“

„Wie Sie bereits erfahren haben, werden Annotationen sowohl für die Serialisierung als auch für die Deserialisierung verwendet. In der Praxis erfordert die Serialisierung weitaus weniger Informationen als die Deserialisierung. Zum Beispiel:“

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

„Instanzen von Array, ArrayList, LinkedList und anderen Klassen werden in JSON-Arrays umgewandelt.“

„Aber wenn Sie ein JSON-Array deserialisieren, welches Objekt sollten Sie dann erstellen: eine ArrayList oder eine LinkedList?“

„Richtig. Wenn ein Klassenmitglied eine Schnittstelle ist (z. B. public List<Cat> cats ), welches Objekt sollte ihm zugeordnet werden?“

„Wir können dem Feld zusätzliche Anmerkungen hinzufügen oder die Zielklassen während der Deserialisierung explizit angeben. Schauen Sie sich dieses Beispiel an:“

Konvertieren Sie ein Objekt aus 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));
}
Eine Klasse, deren Objekte aus JSON deserialisiert werden
@JsonAutoDetect
class Cat {
 public String name;
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

„Mit anderen Worten, wir können den zweiten Parameter der Mapper . readValue- Methode verwenden, um die Liste der Klassen zu übergeben, die während der Deserialisierung verwendet werden sollen.“

„Mir gefällt es. Das ist praktisch. So können Sie ein JSON-Array in alles deserialisieren, was Sie brauchen, eine ArrayList oder eine LinkedList.“

„Sie haben auch die Verwendung von Anmerkungen erwähnt. Wie machen Sie das?“

„Es ist einfach. Zum Beispiel:“

Konvertieren Sie ein Objekt aus 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);
}
Eine Klasse, deren Objekte aus JSON deserialisiert werden
@JsonAutoDetect
class Cat
{
 public String name;
 @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

„Wir fügen einfach die Annotation @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class) zu Zeile 5 hinzu, um anzugeben, welche Implementierung der List-Schnittstelle verwendet werden soll.“

„Ah. Ich verstehe. Das ist wirklich ganz einfach.“

„Aber es gibt noch mehr. Angenommen, der Datentyp in einer Liste ist auch eine Schnittstelle! Was würden Sie tun?“

„Verwenden wir hier auch eine Annotation?“

„Ja, das Gleiche. Sie können es auch verwenden, um den Parametertyp anzugeben. So:“

Sammlungstyp So legen Sie den Datentyp fest
Aufführen @JsonDeserialize(contentAs = ValueTypeImpl.class)
Karte @JsonDeserialize(keyAs = KeyTypeImpl.class)

„Cool! Es sind wirklich viele Anmerkungen für verschiedene Situationen erforderlich, die wir nicht vorhersehen können.“

„Das ist noch nicht alles. Und das bringt uns zum Hauptthema: In realen Projekten erben Klassen häufig dieselbe Basisklasse oder Schnittstelle, die praktisch überall verwendet wird. Und nun stellen Sie sich vor, Sie müssten eine Datenstruktur deserialisieren, die solche Klassen enthält. Zum Beispiel:"

Konvertieren Sie ein Objekt in 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());
}
Eine Klasse, deren Objekte in JSON konvertiert werden
@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;
}
Serialisierungsergebnis und Bildschirmausgabe:
[
 { "name" : "Missy", "age" : 5},
 { "name" : "Killer", "age" : 8 , "owner" : "Bill Jeferson"}
]

„Achten Sie auf das Ergebnis der Serialisierung.“

„Wir können diese Daten nicht in ein Java-Objekt deserialisieren, da sie im Wesentlichen nicht von Daten für andere Klassen zu unterscheiden sind.“

„Es gibt einige Unterscheidungsmerkmale: Hund hat ein Besitzerfeld.“

„Ja, aber dieses Feld könnte null sein oder während der Serialisierung vollständig übersprungen werden.“

„Können wir den Datentyp nicht mithilfe von Anmerkungen angeben, die wir kennen?“

„Nein. Nach der Deserialisierung sollte eine einzelne Sammlung verschiedene Cat- und Dog-Objekte sowie ein Dutzend anderer Klassen enthalten, die von Pet erben könnten.“

„Was in aller Welt kannst du hier tun?“

„Hier kommen zwei Dinge zum Einsatz.“

„Zuerst wird ein bestimmtes Feld ausgewählt, um einen Typ von einem anderen zu unterscheiden. Wenn es keins gibt, wird es erstellt.“

„Zweitens gibt es spezielle Annotationen, mit denen Sie den Prozess der „polymorphen Deserialisierung“ steuern können. Folgendes können Sie tun:“

Konvertieren Sie ein Objekt in 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());
}
Eine Klasse, deren Objekte in JSON konvertiert werden
@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<>();
}
Serialisierungsergebnis und Bildschirmausgabe:
{
 "pets" : [
 {"type" : "dog", "name" : "Killer", "age" : 8, "owner" : "Bill Jeferson"},
 {"type" : "cat", "name" : "Missy", "age" : 5}
]
}

Mithilfe von Annotationen geben wir an, dass die JSON-Darstellung ein spezielles Feld namens „ type“ enthält, das den Wert „ cat“ für die Klasse „ Cat “ und den Wert „ dog“ für die Klasse „Dog“ enthält . Diese Informationen reichen aus, um ein Objekt ordnungsgemäß zu deserialisieren: Bei der Deserialisierung wird der Typ des zu erstellenden Objekts durch den Wert des Typfelds bestimmt.

„Manchmal wird der Klassenname als Wert des Typfelds verwendet (z. B. „com.example.entity.Cat.class“), aber das ist keine gute Praxis. Wie soll eine externe Anwendung, die unser JSON empfängt, die Namen kennen? unsere Klassen? Schlimmer noch, Klassen werden manchmal umbenannt. Es ist besser, einen eindeutigen Namen zu verwenden, um eine bestimmte Klasse zu identifizieren.“

„Cool! Seufz. Ich wusste nicht, dass Deserialisierung so kompliziert ist. Und dass es so viel gibt, was man feinabstimmen kann.“

„Ja. Das sind neue Konzepte für Sie, aber das ist die Art von praktischem Wissen, das Sie zu einem genialen Programmierer machen wird.“

„Amigo ist ein cooler Programmierer. Cool!“

„OK. Geh und mach eine Pause.“