Bevezetés Moshi Json-ba

1. Bemutatkozás

Ebben az oktatóanyagban megnézzük a Moshi nevű modern JSON-könyvtárat a Java számára, amely erőteljes JSON-szerializációt és deserializációt biztosít számunkra kis erőfeszítések nélkül.

Moshi kisebb API-val rendelkezik, mint más könyvtárak, például Jackson vagy Gson, anélkül, hogy kompromisszumot kötne a funkcionalitás terén. Ez megkönnyíti az integrációt az alkalmazásainkba, és tesztelhetőbb kódokat írhatunk. Ez egy kisebb függőség is, amely bizonyos forgatókönyveknél fontos lehet - például az Android fejlesztése.

2. Moshi hozzáadása az építményünkhöz

Mielőtt használhatnánk, először hozzá kell adnunk a Moshi JSON függőségeket pom.xml fájl:

 com.squareup.moshi moshi 1.9.2 com.squareup.moshi moshi-adapterek 1.9.2 

A com.squareup.moshi: moshi a függőség a fő könyvtár, és a com.squareup.moshi: moshi-adapterek A függőség néhány standard típusú adapter - amelyeket később részletesebben megvizsgálunk.

3. Moshival és JSON-nal való együttműködés

A Moshi lehetővé teszi számunkra, hogy bármilyen Java-értéket JSON-vá alakítsunk át, és bárhonnan vissza tudjunk állítani bármilyen okból - például fájlok tárolására, REST API-k írására, bármilyen igényünk lehet.

Moshi az a koncepcióval dolgozik JsonAdapter osztály. Ez egy típusbiztonsági mechanizmus, amely egy adott osztályt JSON karakterláncokká sorosít és egy JSON karakterláncot deszerializál a megfelelő típusba:

public class Post {private String title; magánhúr-szerző; privát karakterlánc szöveg; // kivitelező, getterek és beállítók} Moshi moshi = new Moshi.Builder (). build (); JsonAdapter jsonAdapter = moshi.adapter (Post.osztály);

Miután megépítettük a sajátunkat JsonAdapter, bármikor használhatjuk, hogy értékeinket JSON-vá alakítsuk át a toJson () módszer:

Post post = new Post ("Saját üzenet", "Baeldung", "Ez az én üzenetem"); Karakterlánc json = jsonAdapter.toJson (post); // {"szerző": "Baeldung", "text": "Ez az én bejegyzésem", "title": "Saját bejegyzés"}

És természetesen a JSON-ot a megfelelő Java-típusokká alakíthatjuk vissza tólJson () módszer:

Post post = jsonAdapter.fromJson (json); // új hozzászólás ("My Post", "Baeldung", "This is my post");

4. Standard Java típusok

A Moshi beépített támogatással rendelkezik a standard Java típusokhoz, pontosan a vártnak megfelelően konvertálva a JSON-ba és onnan. Ez magában foglalja:

  • Minden primitív - int, float, charstb.
  • Minden Java dobozos megfelelője - Egész, úszó, karakterstb.
  • Húr
  • Enums
  • Az ilyen típusú tömbök
  • Ilyen típusú Java szabványos gyűjtemények - Lista, készlet, térkép

Ezek mellett a Moshi automatikusan együttműködik bármely tetszőleges Java-babtal, átalakítva ezt egy JSON-objektummá, ahol az értékeket ugyanolyan szabályok szerint konvertálják, mint bármely más típust. Ez nyilván azt jelenti, hogy a Java babon belüli Java-babok megfelelően sorosak, amilyen mélyre kell.

A moshi-adapterek a függőség ekkor hozzáférést biztosít néhány további konverziós szabályhoz, többek között:

  • Egy kissé erősebb adapter az Enums számára - egy tartalékérték támogatása, ha ismeretlen értéket olvas le a JSON-ból
  • Adapter a java.util.Dátum támogatja az RFC-3339 formátumot

Ezek támogatását regisztrálni kell a Moshi például, mielőtt felhasználják őket. Hamarosan ezt a pontos mintát látjuk, amikor támogatást adunk saját egyéni típusainkhoz:

Moshi moshi = new Moshi.builder () .add (new Rfc3339DateJsonAdapter ()) .add (CurrencyCode.class, EnumJsonAdapter.create (CurrencyCode.class) .withUnknownFallback (CurrencyCode.USD)) .build ()

5. Egyedi típusok Moshiban

Eddig minden teljes támogatást nyújtott számunkra a Java objektumok sorosításához és deszerializálásához JSON-ba és vissza. De ez nem jelent sok irányítást a JSON kinézete felett, a Java objektumok sorosítása azáltal, hogy szó szerint az objektum minden mezőjét a jelenlegi állapotba írja. Ez működik, de nem mindig az, amit akarunk.

Ehelyett megírhatjuk saját adaptereinket a saját típusainkhoz, és pontosan ellenőrizhetjük, hogyan működik az ilyen típusok sorosítása és deserializációja.

5.1. Egyszerű konverziók

Az egyszerű eset a Java és a JSON típusok közötti konvertálás - például egy karakterlánc. Ez nagyon hasznos lehet, ha a komplex adatokat meghatározott formátumban kell ábrázolnunk.

Képzeljük el például, hogy van egy Java-típusunk, amely a bejegyzés szerzőjét képviseli:

public class Szerző {private String name; privát karakterlánc e-mail; // kivitelező, mérőeszközök és beállítók}

Erőfeszítés nélkül ez két mezőt tartalmazó JSON objektumként sorosodik - név és email. Ennek ellenére egyetlen karaktersorozatként szeretnénk sorosítani, a nevet és az e-mail címet kombinálva.

Ezt úgy tesszük, hogy írunk egy szabványos osztályt, amely egy metódust tartalmaz, amelyhez annotáltunk @ToJson:

public class AuthorAdapter {@ToJson public String toJson (Author author) {return author.name + ""; }}

Nyilvánvalóan a másik utat is meg kell haladnunk. Vissza kell elemeznünk a húrunkat a sajátunkba Szerző tárgy. Ez egy metódussal van kiegészítve, amellyel annotáltunk @FromJson helyette:

@FromJson public Author fromJson (karakterlánc-készítő) {Pattern pattern = Pattern.compile ("^ (. *) $"); Matcher matcher = minta.matcher (szerző); return matcher.find ()? új Szerző (matcher.group (1), matcher.group (2)): null; }

Miután elkészült, ezt valóban ki kell használnunk. Ezt akkor tesszük, amikor létrehozzuk Moshi az adapter hozzáadásával a mi Moshi.építő:

Moshi moshi = new Moshi.Builder () .add (new AuthorAdapter ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.osztály);

Most azonnal elkezdhetjük átalakítani ezeket az objektumokat JSON-ba és onnan, és megkapjuk a kívánt eredményeket:

Post post = new Post ("Saját bejegyzés", új Szerző ("Baeldung", "[e-mail védett]"), "Ez az én bejegyzésem"); Karakterlánc json = jsonAdapter.toJson (post); // {"author": "Baeldung <[email protected]>", "text": "Ez az én bejegyzésem", "title": "Saját bejegyzés"} Post post = jsonAdapter.fromJson (json); // új hozzászólás ("Saját bejegyzés", új Szerző ("Baeldung", "[e-mail védett]"), "Ez az én bejegyzésem");

5.2. Összetett konverziók

Ezek a konverziók a Java bab és a JSON primitív típusai között történtek. Konvertálhatunk strukturált JSON-ra is - lényegében hagyva, hogy egy Java-típust más struktúrává alakítsunk át a JSON-ban történő megjelenítéshez.

Előfordulhat például, hogy egy Dátum / Idő értéket három különböző értékként - a dátum, az idő és az időzóna - kell megjelenítenünk.

A Moshi használatával mindössze annyit kell tennünk, hogy írunk egy Java-típust, amely a kívánt kimenetet képviseli, majd a mi-t @ToJson metódus vissza tudja adni ezt az új Java objektumot, amelyet a Moshi JSON-vá alakít át a szokásos szabályai szerint:

public class JsonDateTime {private String date; privát String idő; privát String időzóna; // konstruktor, getterek és beállítók} public class JsonDateTimeAdapter {@ToJson public JsonDateTime toJson (ZonedDateTime input) {String date = input.toLocalDate (). toString (); Karakterlánc ideje = input.toLocalTime (). ToString (); Karakterlánc időzónája = input.getZone (). ToString (); return new JsonDateTime (dátum, idő, időzóna); }}

Ahogy számíthatunk rá, a másik irányba haladás egy an írásával történik @FromJson módszer, amely átveszi az új JSON strukturált típusunkat és visszaadja a kívántat:

@FromJson public ZonedDateTime fromJson (JsonDateTime input) {LocalDate date = LocalDate.parse (input.getDate ()); LocalTime time = LocalTime.parse (input.getTime ()); ZoneId timezone = ZoneId.of (input.getTimezone ()); return ZonedDateTime.of (dátum, idő, időzóna); }

Ezután pontosan ezt használhatjuk a fentieknek megfelelően ZonedDateTime strukturált kimenetünkbe és vissza:

Moshi moshi = new Moshi.Builder () .add (new JsonDateTimeAdapter ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (ZonedDateTime.class); Karakterlánc json = jsonAdapter.toJson (ZonedDateTime.now ()); // {{date ":" 2020-02-17 "," time ":" 07: 53: 27.064 "," timezone ":" Europe / London "} ZonedDateTime now = jsonAdapter.fromJson (json); // 2020-02-17T07: 53: 27.064Z [Európa / London]

5.3. Alternatív típusú adapterek

Néha egy mezőhöz alternatív adaptert szeretnénk használni, szemben azzal, hogy azt a mező típusára alapozzuk.

Például lehet egyetlen esetünk, amikor a dátumot és az időt milliszekundumban kell megjelenítenünk a korszakból, nem pedig ISO-8601 karakterláncként.

Moshi ezt egy speciálisan feljegyzett kommentár segítségével teszi lehetővé, amelyet aztán alkalmazhatunk a mezőnkre és az adapterünkre is:

@Retention (RUNTIME) @Target ({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) @JsonQualifier public @interface EpochMillis {}

Ennek legfontosabb része a @JsonQualifier annotáció, amely lehetővé teszi Moshi számára, hogy az ezzel kommentált mezőket a megfelelő Adapter módszerekhez kösse.

Ezután meg kell írnunk egy adaptert. Mint mindig, mindkettőnknek van egy @FromJson és a @ToJson módszer a típusunk és a JSON közötti konverzióra:

public class EpochMillisAdapter {@ToJson public Long toJson (@EpochMillis Instant input) {return input.toEpochMilli (); } @FromJson @EpochMillis public Instant fromJson (hosszú bemenet) {return Instant.ofEpochMilli (input); }}

Itt használtuk a bemeneti paraméter kommentárját a @ToJson módszer és a @FromJson módszer.

Moshi mostantól használhatja ezt az adaptert vagy bármely más mezőt, amelyhez szintén jegyzeteket fűznek @EpochMillis:

public class Post {private String title; magánhúr-szerző; @EpochMillis Azonnali közzétett; // kivitelező, mérőeszközök és beállítók}

Szükség szerint most konvertálhatjuk a kommentált típusunkat JSON-vá és vissza:

Moshi moshi = új Moshi.Builder () .add (új EpochMillisAdapter ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.osztály); Karakterlánc json = jsonAdapter.toJson (új bejegyzés ("Bevezetés a Moshi Jsonba", "Baeldung", Instant.now ())); // {"szerző": "Baeldung", "kiküldött": 1582095384793, "title": "Bevezetés a Moshi Jsonba"} Hozzászólás = jsonAdapter.fromJson (json); // új hozzászólás ("Bevezetés a Moshi Jsonba", "Baeldung", Instant.now ())

6. Haladó JSON-feldolgozás

Most, hogy konvertálhatjuk a típusainkat JSON-ba és vissza, és mi szabályozhatjuk, hogy ez a konverzió hogyan történik. Van még néhány fejlettebb dolog, amelyet alkalmanként meg kell tennünk a feldolgozással, amit Moshi megkönnyít.

6.1. JSON mezők átnevezése

Időnként szükségünk van a JSON-ra, hogy a Java babjainktól eltérő mezőnevekkel rendelkezzen. Ez lehet olyan egyszerű, mint akarni camelCase Java-ban és kígyóház a JSON-ban, vagy lehet, hogy teljesen átnevezi a mezőt, hogy megfeleljen a kívánt sémának.

Használhatjuk a @Json megjegyzés, hogy új nevet adjon az általunk ellenőrzött bab bármely mezőjének:

public class Post {private String title; @Json (name = "authored_by") private String szerző; // kivitelező, mérőeszközök és beállítók}

Miután ezt megtettük, Moshi azonnal megérti, hogy ennek a mezőnek más neve van a JSON-ban:

Moshi moshi = új Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.osztály); Post post = new Post ("Saját üzenet", "Baeldung"); Karakterlánc json = jsonAdapter.toJson (post); // {"authored_by": "Baeldung", "title": "Saját hozzászólás"} Post post = jsonAdapter.fromJson (json); // új hozzászólás ("Saját hozzászólás", "Baeldung")

6.2. Átmeneti mezők

Bizonyos esetekben előfordulhatnak olyan mezők, amelyeket nem kellene felvenni a JSON-ba. Moshi használja a szabványt átmeneti minősítő annak jelzésére, hogy ezeket a mezőket nem kell sorosítani vagy deserializálni:

public static class Post {private String title; privát tranziens String szerző; // kivitelező, mérőeszközök és beállítók}

Ekkor látni fogjuk, hogy ezt a mezőt teljesen figyelmen kívül hagyják a sorozatosítás és a deserializálás során:

Moshi moshi = új Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.osztály); Post post = new Post ("Saját üzenet", "Baeldung"); Karakterlánc json = jsonAdapter.toJson (post); // {"title": "Saját hozzászólás"} Post post = jsonAdapter.fromJson (json); // new Post ("My Post", null) Post post = jsonAdapter.fromJson ("{\" author \ ": \" Baeldung \ ", \" title \ ": \" My Post \ "}"); // új hozzászólás ("Saját hozzászólás", null)

6.3. Alapértelmezett értékek

Néha olyan JSON-t elemzünk, amely nem tartalmaz értékeket minden Java-mezőnk mezőjéhez. Ez rendben van, és Moshi mindent megtesz a helyes cselekedetért.

Moshi nem képes az argumentumkonstruktor semmilyen formáját használni a JSON -unk deszerializálásakor, de képes használni argon nélküli konstruktort, ha van ilyen.

Ez lehetővé teszi számunkra, hogy a JSON sorosítása előtt feltöltsük a babunkat, megadva a mezőknek a szükséges alapértelmezett értékeket:

public class Post {private String title; magánhúr-szerző; privát húr kiküldve; public Post () {posted = Instant.now (). toString (); } // szerelők és beállítók}

Ha az elemzett JSON-ból hiányzik a cím vagy szerző mezők, akkor ezek az értéket kapják nulla. Ha hiányzik a kiküldve mező, akkor ennek helyette az aktuális dátum és idő lesz:

Moshi moshi = új Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.osztály); Karakterlánc json = "{\" title \ ": \" Saját bejegyzés \ "}"; Post post = jsonAdapter.fromJson (json); // új hozzászólás ("My Post", null, "2020-02-19T07: 27: 01.141Z");

6.4. A JSON tömbök elemzése

Minden, amit eddig tettünk, feltételezte, hogy egyetlen JSON-objektumot sorosítunk és deserializálunk egyetlen Java-babdá. Ez nagyon gyakori eset, de nem ez az egyetlen eset. Néha olyan értékgyűjteményekkel is szeretnénk dolgozni, amelyek tömbként szerepelnek a JSON-ban.

Ha a tömb beágyazódik a babunkba, akkor nincs mit tenni. Moshi csak működni fog. Amikor a teljes JSON tömb, akkor több munkát kell végeznünk ennek elérése érdekében, egyszerűen a Java generikák bizonyos korlátai miatt. Meg kell építeni a sajátunkat JsonAdapter oly módon, hogy tudja, hogy deserializálja a generikus gyűjteményt, valamint azt, hogy mi a gyűjtemény.

Moshi némi segítséget kínál a java.lang.reflect.Type hogy tudunk nyújtani a JsonAdapter amikor felépítjük, hogy meg tudjuk adni ezeket a további általános információkat:

Moshi moshi = új Moshi.Builder () .build (); Type type = Types.newParameterizedType (List.class, String.class); JsonAdapter jsonAdapter = moshi.adapter (típus);

Miután ez megtörtént, adapterünk pontosan a várakozásoknak megfelelően működik, tiszteletben tartva ezeket az új általános korlátokat:

Karakterlánc json = jsonAdapter.toJson (Tömbök.asList ("Egy", "Két", "Három"); // ["Egy", "Két", "Három"] Lista eredménye = jsonAdapter.fromJson (json); // Arrays.asList ("egy", "kettő", "három");

7. Összegzés

Láttuk, hogy a Moshi könyvtár hogyan teheti igazán egyszerűvé és rugalmasvá a Java osztályok JSON-ba történő konvertálását és mennyire rugalmas. Bárhol használhatjuk ezt a könyvtárat, amelyet konvertálnunk kell a Java és a JSON között - legyen az fájlokból, adatbázis-oszlopokból vagy akár REST API-kból történő betöltés és mentés. Miért ne próbálná ki?

Szokás szerint a cikk forráskódja megtalálható a GitHubon.