"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 |
---|---|
|
|
|
|
|
|
"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:"
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));
}
@JsonAutoDetect
class Cat {
public String name;
public List<Cat> 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:"
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);
}
@JsonAutoDetect
class Cat
{
public String name;
@JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)
public List<Cat> 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:"
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());
}
@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;
}
[
{ "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:"
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());
}
@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<Pet> pets = new ArrayList<>();
}
{
"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."