Úvod do Moshi Jsona

1. Úvod

V tomto tutoriáli sa pozrieme na Moshi, modernú knižnicu JSON pre Javu, ktorá nám s malým úsilím poskytne výkonnú serializáciu a deserializáciu JSON v našom kóde.

Moshi má menšie API ako iné knižnice ako Jackson alebo Gson bez toho, aby to ohrozilo funkčnosť. To uľahčuje integráciu do našich aplikácií a umožňuje nám písať viac testovateľných kódov. Je to tiež menšia závislosť, ktorá môže byť dôležitá pre určité scenáre - napríklad pri vývoji pre Android.

2. Pridanie Moshi do našej zostavy

Predtým, ako ho budeme môcť použiť, je potrebné najskôr do nášho pridať závislosti Moshi JSON pom.xml spis:

 com.squareup.moshi moshi 1.9.2 com.squareup.moshi moshi-adaptéry 1.9.2 

The com.squareup.moshi: moshi závislosť je hlavná knižnica a com.squareup.moshi: moshi-adaptéry závislosť je niekoľko adaptérov štandardného typu - ktoré si neskôr vysvetlíme podrobnejšie.

3. Spolupráca s Moshi a JSON

Moshi nám umožňuje prevádzať ľubovoľné hodnoty Javy na JSON a späť kdekoľvek potrebujeme z akýchkoľvek dôvodov - napr. pre ukladanie súborov, písanie rozhraní REST API, nech už máme akékoľvek potreby.

Moshi pracuje s konceptom a JsonAdapter trieda. Jedná sa o typicky bezpečný mechanizmus na serializáciu konkrétnej triedy do reťazca JSON a na deserializáciu reťazca JSON späť na správny typ:

verejná trieda Príspevok {private String title; súkromný autor reťazcov; súkromný textový reťazec; // konštruktor, hľadači a zakladatelia} Moshi moshi = nový Moshi.Builder (). build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class);

Len čo sme postavili našu JsonAdapter, môžeme ho použiť kedykoľvek potrebujeme na prevod našich hodnôt do formátu JSON pomocou toJson () metóda:

Príspevok príspevok = nový príspevok („Môj príspevok“, „Baeldung“, „Toto je môj príspevok“); Reťazec json = jsonAdapter.toJson (príspevok); // {"autor": "Baeldung", "text": "Toto je môj príspevok", "title": "Môj príspevok"}

A samozrejme môžeme zodpovedajúcim spôsobom previesť JSON späť na očakávané typy Java fromJson () metóda:

Príspevok post = jsonAdapter.fromJson (json); // nový príspevok („Môj príspevok“, „Baeldung“, „Toto je môj príspevok“);

4. Štandardné typy Java

Moshi je dodávaný so zabudovanou podporou pre štandardné typy Javy, prevádzajúcou na a z JSON presne podľa očakávaní. Patria sem:

  • Všetci primitívi - int, float, char, atď.
  • Všetky ekvivalenty Java v škatuli - Celé číslo, plavák, znak, atď.
  • String
  • Enums
  • Pole týchto typov
  • Štandardné zbierky Java týchto typov - Zoznam, Nastaviť, Mapa

Okrem nich bude Moshi tiež automaticky pracovať s ľubovoľným beanom Java a prevádzať ho na objekt JSON, kde sa hodnoty konvertujú pomocou rovnakých pravidiel ako akýkoľvek iný typ. To zjavne znamená, že Java fazuľa v Java fazule sú správne serializované tak hlboko, ako musíme.

The moshi-adaptéry závislosť nám potom poskytuje prístup k niektorým ďalším pravidlám konverzie, vrátane:

  • O niečo výkonnejší adaptér pre Enums - podporujúci záložnú hodnotu pri načítaní neznámej hodnoty z JSON
  • Adaptér pre java.util.Date podpora formátu RFC-3339

Ich podporu je potrebné zaregistrovať v a Moshi napríklad skôr, ako sa použijú. Tento presný vzor uvidíme čoskoro, keď pridáme podporu pre naše vlastné typy:

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

5. Vlastné typy v Moshi

Všetko nám doteraz poskytovalo úplnú podporu pre serializáciu a deserializáciu ľubovoľného objektu Java do formátu JSON a späť. Ale to nám nedáva veľkú kontrolu nad tým, ako vyzerá JSON, keď serializujeme objekty Java tak, že doslova napíšeme každé pole do objektu tak, ako je. To funguje, ale nie vždy to, čo chceme.

Namiesto toho môžeme napísať vlastné adaptéry pre naše vlastné typy a mať presnú kontrolu nad tým, ako funguje serializácia a deserializácia týchto typov.

5.1. Jednoduché prepočty

Jednoduchým prípadom je konverzia medzi typom Java a JSON - napríklad reťazec. To môže byť veľmi užitočné, keď potrebujeme reprezentovať komplexné údaje v konkrétnom formáte.

Napríklad si predstavte, že máme typ Java, ktorý predstavuje autora príspevku:

public class Autor {private String name; súkromný reťazcový e-mail; // konštruktor, getri a nastavovatelia}

Bez akejkoľvek námahy sa bude serializovať ako objekt JSON obsahujúci dve polia - názov a e-mail. Chceme ho však serializovať ako jeden reťazec kombinujúci meno a e-mailovú adresu.

Robíme to tak, že napíšeme štandardnú triedu, ktorá obsahuje metódu s poznámkami @ToJson:

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

Je zrejmé, že musíme ísť aj opačnou cestou. Musíme našu šnúru rozobrať späť do našej Autor objekt. To sa deje pridaním metódy anotovanej s @FromJson namiesto toho:

@FromJson public Autor fromJson (autor reťazca) {Pattern pattern = Pattern.compile ("^ (. *) $"); Matcher matcher = pattern.matcher (autor); vrátiť matcher.find ()? nový Autor (matcher.group (1), matcher.group (2)): null; }

Keď to bude hotové, musíme to skutočne využiť. Robíme to v čase, keď vytvárame naše Moshi pridaním adaptéra do nášho Moshi. Staviteľ:

Moshi moshi = nový Moshi.Builder () .add (new AuthorAdapter ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class);

Teraz môžeme okamžite začať prevádzať tieto objekty do az JSON a získať výsledky, ktoré sme chceli:

Príspevok príspevok = nový príspevok („Môj príspevok“, nový autor („Baeldung“, „[chránený e-mailom]“), „Toto je môj príspevok“); Reťazec json = jsonAdapter.toJson (príspevok); // {"author": "Baeldung <[email protected]>", "text": "Toto je môj príspevok", "title": "Môj príspevok"} Post post = jsonAdapter.fromJson (json); // nový príspevok („Môj príspevok“, nový autor („Baeldung“, „[chránený e-mailom]“), „Toto je môj príspevok“);

5.2. Komplexné konverzie

Tieto konverzie prebehli medzi Java fazuľami a primitívnymi typmi JSON. Môžeme tiež konvertovať na štruktúrovaný JSON - v zásade nám to umožňuje previesť typ Java na inú štruktúru na vykreslenie v našom JSON.

Napríklad by sme mohli mať potrebu vykresliť hodnotu dátumu a času ako tri rôzne hodnoty - dátum, čas a časové pásmo.

Pomocou Moshi stačí napísať typ Java predstavujúci požadovaný výstup a potom náš @ToJson metóda môže vrátiť tento nový objekt Java, ktorý potom Moshi prevedie na JSON pomocou svojich štandardných pravidiel:

public class JsonDateTime {private String date; súkromný čas reťazca; súkromné ​​časové pásmo reťazca; // constructor, getters and setters} public class JsonDateTimeAdapter {@ToJson public JsonDateTime toJson (ZonedDateTime input) {String date = input.toLocalDate (). toString (); Čas reťazca = input.toLocalTime (). ToString (); Reťazec časové pásmo = input.getZone (). ToString (); vrátiť nový JsonDateTime (dátum, čas, časové pásmo); }}

Ako môžeme očakávať, opačná cesta sa deje napísaním @FromJson metóda, ktorá prevezme náš nový štruktúrovaný typ JSON a vráti požadovaný:

@FromJson public ZonedDateTime fromJson (vstup JsonDateTime) {LocalDate date = LocalDate.parse (input.getDate ()); LocalTime time = LocalTime.parse (input.getTime ()); Časové pásmo ZoneId = ZoneId.of (input.getTimezone ()); návrat ZonedDateTime.of (dátum, čas, časové pásmo); }

Potom sme schopní použiť to presne tak, ako je uvedené vyššie, na premenu našich ZonedDateTime do nášho štruktúrovaného výstupu a späť:

Moshi moshi = nový Moshi.Builder () .add (nový JsonDateTimeAdapter ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (ZonedDateTime.class); Reťazec 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 [Europe / London]

5.3. Adaptéry alternatívneho typu

Niekedy chceme použiť alternatívny adaptér pre jedno pole, na rozdiel od toho, aby sme ho zakladali na type poľa.

Napríklad by sme mohli mať jediný prípad, keď budeme musieť vykresliť dátum a čas ako milisekundy z epochy, nie ako reťazec ISO-8601.

Moshi nám to umožňuje pomocou špeciálne anotovanej anotácie, ktorú potom môžeme použiť na naše pole aj na náš adaptér:

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

Kľúčovou súčasťou toho je @JsonQualifier anotácia, ktorá umožňuje Moshi viazať všetky polia s anotáciou k príslušným metódam adaptéra.

Ďalej musíme napísať adaptér. Ako vždy máme obaja a @FromJson a a @ToJson metóda na prevod medzi našim typom a JSON:

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

Tu sme použili našu anotáciu o vstupnom parametri na @ToJson metódy a na návratovej hodnote @FromJson metóda.

Moshi teraz môže používať tento adaptér alebo ľubovoľné pole, ktoré je tiež anotované @EpochMillis:

verejná trieda Príspevok {private String title; súkromný autor reťazcov; @EpochMillis Okamžité zverejnenie; // konštruktor, getri a nastavovatelia}

Teraz sme schopní konvertovať náš anotovaný typ na JSON a späť podľa potreby:

Moshi moshi = nový Moshi.Builder () .add (nový EpochMillisAdapter ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class); Reťazec json = jsonAdapter.toJson (nový príspevok ("Úvod do Moshi Json", "Baeldung", Instant.now ())); // {"autor": "Baeldung", "posted": 1582095384793, "title": "Úvod do Moshi Json"} Príspevok post = jsonAdapter.fromJson (json); // nový príspevok („Úvod do Moshi Json“, „Baeldung“, Instant.now ())

6. Pokročilé spracovanie JSON

Teraz, keď môžeme prevádzať naše typy na JSON a späť, a môžeme ovládať spôsob, akým sa táto premena deje. Existuje niekoľko pokročilejších vecí, ktoré možno budeme musieť občas pri našom spracovaní urobiť, čo Moshi ľahko dosahuje.

6.1. Premenovanie polí JSON

Príležitostne potrebujeme, aby náš JSON mal rôzne názvy polí ako naše fazule Java. To môže byť také jednoduché, ako chcieť camelCase v Jave a snake_case v JSON, alebo môže ísť o úplné premenovanie poľa tak, aby zodpovedalo požadovanej schéme.

Môžeme použiť @Json anotácia, ktorá umožňuje pomenovať ľubovoľné pole v ktorejkoľvek fazuli, ktorú ovládame:

verejná trieda Príspevok {private String title; @Json (name = "authored_by") private Autor reťazca; // konštruktor, getri a nastavovatelia}

Keď to urobíme, Moshi okamžite pochopí, že toto pole má v JSON iný názov:

Moshi moshi = nový Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class); Príspevok príspevok = nový príspevok („Môj príspevok“, „Baeldung“); Reťazec json = jsonAdapter.toJson (príspevok); // {"authored_by": "Baeldung", "title": "Môj príspevok"} Príspevok post = jsonAdapter.fromJson (json); // nový príspevok („Môj príspevok“, „Baeldung“)

6.2. Prechodné polia

V určitých prípadoch môžeme mať polia, ktoré by nemali byť zahrnuté v JSON. Moshi používa štandard prechodný kvalifikátor označujúci, že tieto polia sa nemajú serializovať alebo deserializovať:

verejná statická trieda Príspevok {súkromný názov reťazca; súkromný prechodný autor reťazcov; // konštruktor, getri a nastavovatelia}

Potom uvidíme, že toto pole je pri serializácii aj deserializácii úplne ignorované:

Moshi moshi = nový Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class); Príspevok príspevok = nový príspevok („Môj príspevok“, „Baeldung“); Reťazec json = jsonAdapter.toJson (príspevok); // {"title": "Môj príspevok"} Príspevok post = jsonAdapter.fromJson (json); // nový príspevok ("Môj príspevok", null) Príspevok post = jsonAdapter.fromJson ("{\" autor \ ": \" Baeldung \ ", \" title \ ": \" Môj príspevok \ "}"); // nový príspevok („Môj príspevok“, null)

6.3. Základné hodnoty

Niekedy analyzujeme súbor JSON, ktorý neobsahuje hodnoty pre každé pole v našom Java Bean. To je v poriadku a Moshi urobí všetko pre to, aby urobil správnu vec.

Moshi nie je schopný použiť žiadnu formu konštruktora argumentov pri deserializácii nášho JSON, ale je schopný použiť konštruktor bez argumentov, ak je prítomný.

To nám potom umožní vopred naplniť našu fazuľu pred serializáciou JSON, čím sa do našich polí poskytnú všetky požadované predvolené hodnoty:

verejná trieda Príspevok {private String title; súkromný autor reťazcov; súkromný reťazec zverejnený; public Post () {posted = Instant.now (). toString (); } // zakladatelia a zakladatelia}

Ak náš analyzovaný JSON chýba titul alebo autor polia potom tieto skončia s hodnotou nulový. Ak nám chýba zverejnené potom bude mať aktuálny dátum a čas:

Moshi moshi = nový Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class); Reťazec json = "{\" title \ ": \" Môj príspevok \ "}"; Príspevok post = jsonAdapter.fromJson (json); // nový príspevok („Môj príspevok“, null, „2020-02-19T07: 27: 01.141Z“);

6.4. Analýza polí JSON

Všetko, čo sme doteraz robili, predpokladalo, že serializujeme a deserializujeme jeden objekt JSON do jedinej fazule Java. Toto je veľmi častý prípad, ale nie je to jediný prípad. Niekedy chceme pracovať aj so zbierkami hodnôt, ktoré sú v našom JSON-e predstavované ako pole.

Keď je pole vnorené vo vnútri našich bôbov, nie je čo robiť. Moshi bude proste fungovať. Keď je celý JSON pole, musíme urobiť viac práce, aby sme to dosiahli, jednoducho kvôli niektorým obmedzeniam v generike Java. Musíme zostrojiť naše JsonAdapter spôsobom, že vie, že deserializuje všeobecnú zbierku, ako aj to, o čo ide.

Moshi ponúka pomoc pri výstavbe a java.lang.reflect.Type ktoré môžeme poskytnúť JsonAdapter keď ho zostavíme, aby sme mohli poskytnúť tieto ďalšie všeobecné informácie:

Moshi moshi = nový Moshi.Builder () .build (); Type type = Types.newParameterizedType (List.class, String.class); JsonAdapter jsonAdapter = moshi.adapter (typ);

Keď to bude hotové, náš adaptér bude pracovať presne podľa očakávaní a bude rešpektovať tieto nové všeobecné hranice:

Reťazec json = jsonAdapter.toJson (Arrays.asList ("Jeden", "Dva", "Tri")); // ["One", "Two", "Three"] Zoznam výsledkov = jsonAdapter.fromJson (json); // Arrays.asList ("Jeden", "Dva", "Tri");

7. Zhrnutie

Videli sme, ako môže knižnica Moshi skutočne uľahčiť prevod tried Java na az JSON a ako je flexibilná. Túto knižnicu môžeme použiť kdekoľvek, kde potrebujeme prevádzať medzi Java a JSON - či už je to načítanie a uloženie zo súborov, databázových stĺpcov alebo dokonca REST API. Prečo to nevyskúšať?

Ako obvykle, zdrojový kód tohto článku nájdete na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found