Introduksjon til Moshi Json

1. Introduksjon

I denne opplæringen tar vi en titt på Moshi, et moderne JSON-bibliotek for Java som gir oss kraftig JSON-serialisering og deserialisering i koden vår med liten innsats.

Moshi har en mindre API enn andre biblioteker som Jackson eller Gson uten å gå på kompromiss med funksjonaliteten. Dette gjør det lettere å integrere i applikasjonene våre og lar oss skrive mer testbar kode. Det er også en mindre avhengighet, noe som kan være viktig for visse scenarier - for eksempel å utvikle for Android.

2. Legge til Moshi i byggingen vår

Før vi kan bruke den, må vi først legge til Moshi JSON-avhengighetene til våre pom.xml fil:

 com.squareup.moshi moshi 1.9.2 com.squareup.moshi moshi-adaptere 1.9.2 

De com.squareup.moshi: moshi avhengighet er hovedbiblioteket, og com.squareup.moshi: moshi-adaptere avhengighet er noen standardadaptere - som vi vil utforske mer detaljert senere.

3. Arbeide med Moshi og JSON

Moshi lar oss konvertere alle Java-verdier til JSON og tilbake igjen hvor som helst vi trenger, uansett årsak - f.eks. for lagring av filer, skriving av REST API-er, uansett hvilke behov vi måtte ha.

Moshi jobber med konseptet a JsonAdapter klasse. Dette er en typesafe mekanisme for å serieisere en bestemt klasse til en JSON-streng og for å deserialisere en JSON-streng tilbake til riktig type:

public class Post {private String title; privat strengforfatter; privat strengtekst; // constructor, getters and setters} Moshi moshi = ny Moshi.Builder (). build (); JsonAdapter jsonAdapter = moshi.adapter (Post.klasse);

Når vi har bygget vår JsonAdapter, kan vi bruke den når vi trenger det for å konvertere verdiene våre til JSON ved hjelp av toJson () metode:

Innlegg innlegg = nytt innlegg ("Mitt innlegg", "Baeldung", "Dette er mitt innlegg"); String json = jsonAdapter.toJson (innlegg); // {"author": "Baeldung", "text": "Dette er innlegget mitt", "title": "Mitt innlegg"}

Og selvfølgelig kan vi konvertere JSON tilbake til de forventede Java-typene med den tilsvarende fraJson () metode:

Innlegg innlegg = jsonAdapter.fromJson (json); // nytt innlegg ("Mitt innlegg", "Baeldung", "Dette er innlegget mitt");

4. Standard Java-typer

Moshi kommer med innebygd støtte for standard Java-typer, konvertering til og fra JSON akkurat som forventet. Dette dekker:

  • Alle primitiver - int, flyte, røye, etc.
  • Alle Java-boksekvivalenter - Heltall, flyte, karakter, etc.
  • String
  • Enums
  • Arrays av disse typene
  • Standard Java-samlinger av disse typene - Liste, sett, kart

I tillegg til disse vil Moshi også automatisk arbeide med vilkårlige Java-bønner, og konvertere dette til et JSON-objekt der verdiene konverteres ved å bruke de samme reglene som alle andre typer. Dette betyr åpenbart at Java-bønner i Java-bønner er riktig seriell så dypt som vi trenger å gå.

De moshi-adaptere avhengighet gir oss deretter tilgang til noen ekstra konverteringsregler, inkludert:

  • En litt kraftigere adapter for Enums - som støtter en reserveverdi når du leser en ukjent verdi fra JSON
  • En adapter for java.util.Date støtter RFC-3339-formatet

Støtte for disse må registreres hos en Moshi før de blir brukt. Vi ser dette nøyaktige mønsteret snart når vi legger til støtte for våre egne tilpassede typer:

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

5. Egendefinerte typer i Moshi

Alt hittil har gitt oss total støtte for serialisering og deserialisering av ethvert Java-objekt til JSON og tilbake. Men dette gir oss ikke mye kontroll over hvordan JSON ser ut, og serierer Java-objekter ved bokstavelig talt å skrive hvert felt i objektet som det er. Dette fungerer, men er ikke alltid det vi ønsker.

I stedet kan vi skrive våre egne adaptere for våre egne typer og ha nøyaktig kontroll over hvordan serialisering og deserialisering av disse typene fungerer.

5.1. Enkle konverteringer

Det enkle tilfellet er å konvertere mellom en Java-type og en JSON-en - for eksempel en streng. Dette kan være veldig nyttig når vi trenger å representere komplekse data i et bestemt format.

Tenk deg for eksempel at vi har en Java-type som representerer forfatteren av et innlegg:

offentlig klasse Forfatter {privat strengnavn; privat streng e-post; // constructor, getters and setters}

Uten anstrengelse i det hele tatt vil dette serienummereres som et JSON-objekt som inneholder to felt - Navn og e-post. Vi ønsker å serieisere det som en enkelt streng skjønt, og kombinerer navnet og e-postadressen sammen.

Vi gjør dette ved å skrive en standardklasse som inneholder en metode som er merket med @ToJson:

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

Tydeligvis må vi også gå den andre veien. Vi må analysere strengene våre igjen Forfatter gjenstand. Dette gjøres ved å legge til en metode som er merket med @FromJson i stedet:

@FromJson public Author fromJson (String author) {Mønster mønster = Mønster.kompil ("^ (. *) $"); Matcher matcher = pattern.matcher (forfatter); returner matcher.find ()? ny forfatter (matcher.group (1), matcher.group (2)): null; }

Når det er gjort, må vi faktisk bruke dette. Vi gjør dette på det tidspunktet vi lager vår Moshi ved å legge adapteren til Moshi.Bygger:

Moshi moshi = ny Moshi.Builder () .add (ny forfatteradapter ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.klasse);

Nå kan vi umiddelbart begynne å konvertere disse objektene til og fra JSON, og få de resultatene vi ønsket:

Innlegg innlegg = nytt innlegg ("Mitt innlegg", ny forfatter ("Baeldung", "[e-postbeskyttet]"), "Dette er innlegget mitt"); String json = jsonAdapter.toJson (innlegg); // {"author": "Baeldung <[email protected]>", "text": "Dette er innlegget mitt", "title": "Mitt innlegg"} Innlegg innlegg = jsonAdapter.fromJson (json); // nytt innlegg ("Mitt innlegg", ny forfatter ("Baeldung", "[email protected]"), "Dette er innlegget mitt");

5.2. Komplekse konverteringer

Disse konverteringene har vært mellom Java bønner og JSON primitive typer. Vi kan også konvertere til strukturert JSON også - i hovedsak la oss konvertere en Java-type til en annen struktur for gjengivelse i vår JSON.

For eksempel kan det hende at vi har behov for å gjengi en dato / tid-verdi som tre forskjellige verdier - datoen, klokkeslettet og tidssonen.

Ved å bruke Moshi er alt vi trenger å gjøre å skrive en Java-type som representerer ønsket utdata og deretter vår @ToJson metoden kan returnere dette nye Java-objektet, som Moshi deretter konverterer til JSON ved hjelp av standardregler:

offentlig klasse JsonDateTime {privat strengdato; privat streng tid; privat streng tidssone; // constructor, getters and setters} public class JsonDateTimeAdapter {@ToJson public JsonDateTime toJson (ZonedDateTime input) {String date = input.toLocalDate (). toString (); Strengtid = input.toLocalTime (). TilString (); Strengs tidssone = input.getZone (). Til String (); returner ny JsonDateTime (dato, tid, tidssone); }}

Som vi kan forvente, går den andre veien ved å skrive en @FromJson metode som tar vår nye JSON-strukturerte type og returnerer den ønskede:

@FromJson public ZonedDateTime fromJson (JsonDateTime input) {LocalDate date = LocalDate.parse (input.getDate ()); LocalTime tid = LocalTime.parse (input.getTime ()); ZoneId tidssone = ZoneId.of (input.getTimezone ()); returner ZonedDateTime.of (dato, tid, tidssone); }

Vi er i stand til å bruke dette nøyaktig som ovenfor for å konvertere vårt ZonedDateTime inn i vår strukturerte produksjon og tilbake:

Moshi moshi = ny Moshi.Builder () .add (ny JsonDateTimeAdapter ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (ZonedDateTime.class); String 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. Alternative adaptere

Noen ganger vil vi bruke en alternativ adapter for et enkelt felt, i motsetning til å basere det på felttypen.

For eksempel kan vi ha et enkelt tilfelle der vi trenger å gjengi dato og tid som millisekunder fra epoken i stedet for som en ISO-8601-streng.

Moshi lar oss gjøre dette ved å bruke en spesiell kommentert kommentar som vi kan bruke både på vårt felt og adapteren vår:

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

Den viktigste delen av dette er @JsonQualifier merknad, som gjør det mulig for Moshi å knytte felt som er merket med dette til de riktige adaptermetodene.

Deretter må vi skrive en adapter. Som alltid har vi begge en @FromJson og en @ToJson metode for å konvertere mellom vår type og JSON:

public class EpochMillisAdapter {@ToJson public Long toJson (@EpochMillis Instant input) {return input.toEpochMilli (); } @FromJson @EpochMillis offentlig øyeblikkelig fraJson (lang inngang) {retur Instant.ofEpochMilli (inngang); }}

Her har vi brukt merknaden vår om inngangsparameteren til @ToJson metode og på returverdien til @FromJson metode.

Moshi kan nå bruke denne adapteren eller hvilket som helst felt som også er merket med @EpochMillis:

public class Post {private String title; privat strengforfatter; @EpochMillis Instant postet; // constructor, getters and setters}

Vi kan nå konvertere den merkede typen til JSON og tilbake etter behov:

Moshi moshi = ny Moshi.Builder () .add (ny EpochMillisAdapter ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.klasse); String json = jsonAdapter.toJson (nytt innlegg ("Introduksjon til Moshi Json", "Baeldung", Instant.now ())); // {"author": "Baeldung", "posted": 1582095384793, "title": "Introduction to Moshi Json"} Innlegg post = jsonAdapter.fromJson (json); // nytt innlegg ("Introduksjon til Moshi Json", "Baeldung", Instant.now ())

6. Avansert JSON-behandling

Nå som vi kan konvertere typene våre til JSON og tilbake, og vi kan kontrollere hvordan denne konverteringen skjer. Det er noen mer avanserte ting som vi kanskje trenger å gjøre noen ganger med behandlingen vår, noe som Moshi gjør det enkelt å oppnå.

6.1. Gi nytt navn til JSON-felt

Noen ganger trenger vi at JSON har forskjellige feltnavn enn Java-bønnene. Dette kan være så enkelt som å ønske camelCase i Java og snake_case i JSON, eller det kan være å gi feltet helt nytt navn for å matche ønsket skjema.

Vi kan bruke @Json kommentar for å gi et nytt navn til ethvert felt i en hvilken som helst bønne som vi kontrollerer:

public class Post {private String title; @Json (name = "authored_by") privat strengforfatter; // constructor, getters and setters}

Når vi har gjort dette, forstår Moshi umiddelbart at dette feltet har et annet navn i JSON:

Moshi moshi = ny Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.klasse); Innlegg innlegg = nytt innlegg ("Mitt innlegg", "Baeldung"); String json = jsonAdapter.toJson (innlegg); // {"authored_by": "Baeldung", "title": "Mitt innlegg"} Innlegg innlegg = jsonAdapter.fromJson (json); // nytt innlegg ("Mitt innlegg", "Baeldung")

6.2. Forbigående felt

I visse tilfeller kan vi ha felt som ikke skal inkluderes i JSON. Moshi bruker standarden flyktig kvalifisering for å indikere at disse feltene ikke skal serieiseres eller deserialiseres:

offentlig statisk klasse Post {private String title; privat forbigående Stringforfatter; // constructor, getters and setters}

Vi vil da se at dette feltet ignoreres fullstendig både når vi serialiserer og deserialiserer:

Moshi moshi = ny Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.klasse); Innlegg innlegg = nytt innlegg ("Mitt innlegg", "Baeldung"); String json = jsonAdapter.toJson (innlegg); // {"title": "Mitt innlegg"} Innlegg innlegg = jsonAdapter.fromJson (json); // nytt innlegg ("Mitt innlegg", null) Innlegg innlegg = jsonAdapter.fromJson ("{\" forfatter \ ": \" Baeldung \ ", \" tittel \ ": \" Mitt innlegg \ "}"); // nytt innlegg ("Mitt innlegg", null)

6.3. Standardverdier

Noen ganger analyserer vi JSON som ikke inneholder verdier for hvert felt i Java Bean. Dette er greit, og Moshi vil gjøre sitt beste for å gjøre det rette.

Moshi er ikke i stand til å bruke noen form for argumentkonstruktør når han deserialiserer vår JSON, men den er i stand til å bruke en no-args-konstruktør hvis en er til stede.

Dette vil da tillate oss å forhåndsutfylle bønnen vår før JSON serialiseres, og gi alle nødvendige standardverdier til våre felt:

public class Post {private String title; privat strengforfatter; privat streng lagt ut; offentlig innlegg () {postet = Instant.now (). toString (); } // getters og setters}

Hvis vår analyserte JSON mangler tittel eller forfatter felt vil disse ende opp med verdien null. Hvis vi mangler postet feltet vil dette i stedet ha gjeldende dato og klokkeslett:

Moshi moshi = ny Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.klasse); String json = "{\" title \ ": \" Mitt innlegg \ "}"; Innlegg innlegg = jsonAdapter.fromJson (json); // nytt innlegg ("Mitt innlegg", null, "2020-02-19T07: 27: 01.141Z");

6.4. Analyse av JSON Arrays

Alt vi har gjort hittil har antatt at vi serialiserer og deserialiserer et enkelt JSON-objekt til en enkelt Java-bønne. Dette er en veldig vanlig sak, men det er ikke den eneste saken. Noen ganger vil vi også jobbe med verdisamlinger, som er representert som en matrise i vår JSON.

Når matrisen er nestet inne i bønnene våre, er det ingenting å gjøre. Moshi vil bare jobbe. Når hele JSON er en matrise, må vi gjøre mer arbeid for å oppnå dette, ganske enkelt på grunn av noen begrensninger i Java-generikk. Vi må konstruere våre JsonAdapter på en måte som den vet at den deserialiserer en generisk samling, samt hva samlingen er.

Moshi tilbyr litt hjelp til å konstruere en java.lang.reflect.Type som vi kan gi til JsonAdapter når vi bygger den slik at vi kan gi denne ekstra generelle informasjonen:

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

Når dette er gjort, fungerer adapteren vår akkurat som forventet, og respekterer disse nye generiske grensene:

String json = jsonAdapter.toJson (Arrays.asList ("One", "Two", "Three")); // ["One", "Two", "Three"] Listresultat = jsonAdapter.fromJson (json); // Arrays.asList ("One", "Two", "Three");

7. Oppsummering

Vi har sett hvordan Moshi-biblioteket kan gjøre det enkelt å konvertere Java-klasser til og fra JSON, og hvor fleksibelt det er. Vi kan bruke dette biblioteket hvor som helst vi trenger for å konvertere mellom Java og JSON - enten det er å laste og lagre fra filer, databasekolonner eller til og med REST APIer. Hvorfor ikke prøve det?

Som vanlig kan kildekoden for denne artikkelen finnes på GitHub.


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