Raščlanjivanje YAML-a sa SnakeYAML-om

1. Pregled

U ovom uputstvu naučit ćemo kako koristiti SnakeYAML knjižnicu za serializirajte Java objekte u YAML dokumentima i obrnuto.

2. Postavljanje projekta

Da bismo koristili SnakeYAML u našem projektu, dodati ćemo sljedeću ovisnost o Mavenu (najnoviju verziju možete pronaći ovdje):

 org.yaml snakeyaml 1.21 

3. Točka ulaza

The Yaml class je ulazna točka za API:

Yaml yaml = novi Yaml ();

Budući da implementacija nije sigurna u nitima, različite niti moraju imati svoje Yaml primjer.

4. Učitavanje YAML dokumenta

Knjižnica pruža podršku za učitavanje dokumenta iz a Niz ili an InputStream. Većina uzoraka koda ovdje bi se temeljila na raščlanjivanju InputStream.

Počnimo s definiranjem jednostavnog YAML dokumenta i imenovanjem datoteke kao kupac.yaml:

firstName: "John" lastName: "Košuta" dob: 20

4.1. Osnovna upotreba

Sada ćemo raščlaniti gornji YAML dokument sa Yaml razred:

Yaml yaml = novi Yaml (); InputStream inputStream = this.getClass () .getClassLoader () .getResourceAsStream ("customer.yaml"); Karta obj = yaml.load (inputStream); System.out.println (obj);

Gornji kod generira sljedeći izlaz:

{ime = Ivan, prezime = srna, dob = 20}

Prema zadanim postavkama opterećenje() metoda vraća a Karta primjer. Upit o Karta Objekt bi svaki put trebao unaprijed znati imena ključeva svojstva, a također nije lako preći preko ugniježđenih svojstava.

4.2. Prilagođena vrsta

Knjižnica također pruža način učitavanja dokumenta kao prilagođene klase. Ova bi opcija omogućila lako prevrtanje podataka u memoriji.

Definirajmo a Kupac razreda i pokušajte ponovo učitati dokument:

kupac javne klase {private String firstName; private String lastName; privatno int doba; // geteri i postavljači}

Pod pretpostavkom da će YAML dokument biti deserijaliziran kao poznati tip, možemo odrediti eksplicitni global označiti u dokumentu.

Ažurirajmo dokument i spremimo ga u novu datoteku kupac_z_tipom.yaml:

!! com.baeldung.snakeyaml.Prvo ime kupca: "Ivan" Prezime: "Srna" dob: 20

Zabilježite prvi redak u dokumentu koji sadrži informacije o klasi koja će se koristiti prilikom učitavanja.

Sada ćemo ažurirati gore korišteni kod i proslijediti novo ime datoteke kao ulaz:

Yaml yaml = novi Yaml (); InputStream inputStream = this.getClass () .getClassLoader () .getResourceAsStream ("yaml / customer_with_type.yaml"); Kupac kupac = yaml.load (inputStream); 

The opterećenje() metoda sada vraća instancu Kupac tip. Nedostatak ovog pristupa je taj što se tip mora izvesti kao knjižnica da bi se koristio tamo gdje je potrebno.

Iako bismo mogli koristiti eksplicitnu lokalnu oznaku za koju nismo obvezni izvoziti knjižnice.

Drugi način učitavanja prilagođene vrste je korištenje Konstruktor razred. Na taj način možemo odrediti vrstu korijena za YAML dokument koji će se raščlaniti. Stvorimo a Konstruktor primjer s Kupac upišite kao root tip i prenesite ga na Yaml primjer.

Sada na učitavanju kupac.yaml, dobit ćemo Kupac objekt:

Yaml yaml = novi Yaml (novi konstruktor (kupac.klasa));

4.3. Implicitne vrste

U slučaju da za određeno svojstvo nije definiran tip, knjižnica automatski pretvara vrijednost u implicitni tip.

Na primjer:

1.0 -> Float 42 -> Integer 30.03.2009 -> Datum

Isprobajmo ovu implicitnu pretvorbu tipa pomoću test slučaja:

@Test public void whenLoadYAML_thenLoadCorrectImplicitTypes () {Yaml yaml = novi Yaml (); Dokument karte = yaml.load ("3.0: 2018-07-22"); assertNotNull (dokument); assertEquals (1, document.size ()); assertTrue (document.containsKey (3.0d)); }

4.4. Ugniježđeni predmeti i zbirke

S obzirom na tip najviše razine, knjižnica automatski otkriva vrste ugniježđenih objekata, osim ako nisu sučelje ili apstraktna klasa i ako deserijalizira dokument u odgovarajući ugniježđeni tip.

Dodajmo Kontakt i Adresa pojedinosti o kupac.yaml, i spremite novu datoteku kao kupac_sa_kontaktnim_detajlima_i_adresom.yaml.

Sada ćemo raščlaniti novi YAML dokument:

firstName: "John" lastName: "Doe" dob: 31 kontaktDetalji: - type: "mobile" number: 123456789 - type: "fiksni" number: 456786868 homeAddress: line: "Xyz, DEF Street" grad: "City Y" state : "State Y" zip: 345657 

Kupac razred također treba odražavati ove promjene. Evo ažurirane klase:

kupac javne klase {private String firstName; private String lastName; privatno int doba; privatni popis contactDetails; privatna adresa homeAddress; // geteri i postavljači} 

Da vidimo kako Kontakt i Adresa satovi izgledaju kao:

javna klasa Kontakt {private String type; privatni int broj; // geteri i postavljači}
javna klasa Adresa {private String line; privatni gudački grad; privatna država gudača; privatni Integer zip; // geteri i postavljači}

Sad ćemo testirati Yaml#opterećenje() s danim test slučajem:

@Test public void whenLoadYAMLDocumentWithTopLevelClass_thenLoadCorrectJavaObjectWithNestedObjects () {Yaml yaml = novi Yaml (novi konstruktor (Customer.class)); InputStream inputStream = this.getClass () .getClassLoader () .getResourceAsStream ("yaml / customer_with_contact_details_and_address.yaml"); Kupac kupac = yaml.load (inputStream); assertNotNull (kupac); assertEquals ("John", customer.getFirstName ()); assertEquals ("Doe", customer.getLastName ()); assertEquals (31, customer.getAge ()); assertNotNull (customer.getContactDetails ()); assertEquals (2, customer.getContactDetails (). size ()); assertEquals ("mobile", customer.getContactDetails () .get (0) .getType ()); assertEquals (123456789, kupac.getContactDetails () .get (0) .getNumber ()); assertEquals ("fiksna mreža", customer.getContactDetails () .get (1) .getType ()); assertEquals (456786868, customer.getContactDetails () .get (1) .getNumber ()); assertNotNull (customer.getHomeAddress ()); assertEquals ("Xyz, ulica DEF", customer.getHomeAddress () .getLine ()); }

4.5. Zbirke sigurne za tip

Kada su jedno ili više svojstava određene Java klase kolekcije zaštićene od tipa (generičke), tada je važno navesti TypeDescription tako da se utvrdi točan parametarski tip.

Uzmimo jedan Kupac imaju više od jednog Kontakt, i pokušajte ga učitati:

firstName: "John" lastName: "Doe" dob: 31 contactDetails: - {type: "mobile", number: 123456789} - {type: "fiksni telefon", number: 123456789}

Da biste učitali ovaj dokument, možemo odrediti TypeDescription za dano svojstvo u klasi najviše razine:

Konstruktor konstruktora = novi konstruktor (kupac.klasa); TypeDescription customTypeDescription = novi TypeDescription (Customer.class); customTypeDescription.addPropertyParameters ("contactDetails", Contact.class); konstruktor.addTypeDescription (customTypeDescription); Yaml yaml = novi Yaml (konstruktor);

4.6. Učitavanje više dokumenata

Moglo bi biti slučajeva kada, u jednom Datoteka postoji nekoliko YAML dokumenata i želimo ih raščlaniti. The Yaml razred pruža a loadAll () metoda za izvršenje takve vrste raščlanjivanja.

Prema zadanim postavkama metoda vraća instancu Iterativ gdje je svaki objekt tipa Karta. Ako je željena prilagođena vrsta, tada možemo koristiti Konstruktor primjer kao što je gore spomenuto.

Razmotrite sljedeće dokumente u jednoj datoteci:

--- firstName: "John" lastName: "Doe" dob: 20 --- firstName: "Jack" lastName: "Jones" dob: 25

Gore možemo raščlaniti pomoću loadAll () metoda kao što je prikazano u donjem uzorku koda:

@Test public void whenLoadMultipleYAMLDocuments_thenLoadCorrectJavaObjects () {Yaml yaml = novi Yaml (novi konstruktor (kupac.klasa)); InputStream inputStream = this.getClass () .getClassLoader () .getResourceAsStream ("yaml / kupci.yaml"); broj brojeva = 0; za (Objekt objekt: yaml.loadAll (inputStream)) {count ++; assertTrue (objekt kupca); } assertEquals (2, count); }

5. Damping YAML dokumenata

Knjižnica također nudi metodu za dump danog Java objekta u YAML dokument. Izlaz bi mogao biti a Niz ili određena datoteka / tok.

5.1. Osnovna upotreba

Počet ćemo s jednostavnim primjerom izbacivanja instance Karta u YAML dokument (Niz):

@Test public void whenDumpMap_thenGenerateCorrectYAML () {Podaci karte = novi LinkedHashMap (); data.put ("ime", "Silenthand Olleander"); data.put ("rasa", "Čovjek"); data.put ("osobine", novi niz [] {"ONE_HAND", "ONE_EYE"}); Yaml yaml = novi Yaml (); StringWriter Writer = novi StringWriter (); yaml.dump (podaci, pisac); Niz se očekujeYaml = "name: Silenthand Olleander \ nrace: Human \ ntraits: [ONE_HAND, ONE_EYE] \ n"; assertEquals (očekivaniYaml, Writer.toString ()); }

Gornji kod daje sljedeći izlaz (imajte na umu da se pomoću instance LinkedHashMap čuva redoslijed izlaznih podataka):

ime: Utrka tihog Olleandera: Ljudske osobine: [ONE_HAND, ONE_EYE]

5.2. Prilagođeni Java objekti

Možemo i odabrati izbaci prilagođene tipove Java u izlazni tok. To će, međutim, dodati globalni eksplicitni označiti na izlazni dokument:

@Test public void whenDumpACustomType_thenGenerateCorrectYAML () {Kupac kupac = novi kupac (); kupac.setAge (45); customer.setFirstName ("Greg"); customer.setLastName ("McDowell"); Yaml yaml = novi Yaml (); StringWriter Writer = novi StringWriter (); yaml.dump (kupac, pisac); Niz se očekujeYaml = "!! com.baeldung.snakeyaml.Customer {dob: 45, contactDetails: null, firstName: Greg, \ n homeAddress: null, lastName: McDowell} \ n"; assertEquals (očekivaniYaml, Writer.toString ()); }

S gornjim pristupom i dalje izbacujemo podatke o oznakama u YAML dokument.

To znači da klasu moramo izvesti kao knjižnicu za svakog potrošača koji je deserijalizira. Da bismo izbjegli naziv oznake u izlaznoj datoteci, možemo koristiti dumpAs () metoda koju pruža knjižnica.

Dakle, u gornjem kodu mogli bismo prilagoditi sljedeće da bismo uklonili oznaku:

yaml.dumpAs (kupac, Tag.MAP, null);

6. Zaključak

Ovaj je članak ilustrirao upotrebu SnakeYAML biblioteke za serializaciju Java objekata na YAML i obrnuto.

Svi primjeri mogu se naći u projektu GitHub - ovo je projekt zasnovan na Mavenu, pa bi ga trebalo lako uvesti i pokrenuti kakav jest.