Java >> Java tutorial >  >> Tag >> Json

Introduktion til Jsoniter

1. Introduktion

JavaScript Object Notation, eller JSON, har vundet stor popularitet som et dataudvekslingsformat i de seneste år. Jsoniter er et nyt JSON-parsing-bibliotek, der sigter mod at tilbyde en mere fleksibel og mere effektiv JSON-parsing end de andre tilgængelige parsere.

I denne øvelse vil vi se, hvordan man parser JSON-objekter ved hjælp af Jsoniter-biblioteket til Java.

2. Afhængigheder

Den seneste version af Jsoniter kan findes fra Maven Central repository.

Lad os starte med at tilføje afhængighederne til pom.xml :

<dependency>
    <groupId>com.jsoniter<groupId> 
    <artifactId>jsoniter</artifactId>
    <version>0.9.23</version>
</dependency>

På samme måde kan vi tilføje afhængigheden til vores build.gradle fil:

compile group: 'com.jsoniter', name: 'jsoniter', version: '0.9.23'

3. JSON-parsing ved hjælp af Jsoniter

Jsoniter leverer 3 API'er til at parse JSON-dokumenter:

  • Bind API
  • Enhver API
  • Iterator API

Lad os se nærmere på hver af ovenstående API'er.

3.1. JSON-parsing ved hjælp af Bind API

Bind-API'en bruger den traditionelle måde at binde JSON-dokumentet til Java-klasser på.

Lad os overveje JSON-dokumentet med elevoplysninger:

{"id":1,"name":{"firstName":"Joe","surname":"Blogg"}}

Lad os nu definere Studenten og Navn skemaklasser til at repræsentere ovenstående JSON:

public class Student {
    private int id;
    private Name name;
    
    // standard setters and getters
}
public class Name {
    private String firstName;
    private String surname;
    
    // standard setters and getters
}

De-serialisering af JSON til et Java-objekt ved hjælp af bind API er meget simpelt. Vi bruger deserialize metode til JsonIterator :

@Test
public void whenParsedUsingBindAPI_thenConvertedToJavaObjectCorrectly() {
    String input = "{\"id\":1,\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
    
    Student student = JsonIterator.deserialize(input, Student.class);

    assertThat(student.getId()).isEqualTo(1);
    assertThat(student.getName().getFirstName()).isEqualTo("Joe");
    assertThat(student.getName().getSurname()).isEqualTo("Blogg");
}

Studenten skemaklassen erklærer id at være af int datatype. Men hvad nu hvis den JSON, vi modtager, indeholder en streng værdi for id i stedet for et tal? For eksempel:

{"id":"1","name":{"firstName":"Joe","surname":"Blogg"}}

Bemærk, hvordan id i JSON er en strengværdi “1” denne gang. Jsoniter giver Måske dekodere til at håndtere dette scenarie.

3.2. Måske Dekodere

Jsoniters Måske dekodere er nyttige, når datatypen for et JSON-element er uklar . Datatypen for student.id feltet er uskarpt – det kan enten være en streng eller en int . For at håndtere dette skal vi annotere id'et felt i vores skemaklasse ved hjælp af MaybeStringIntDecoder :

public class Student {
    @JsonProperty(decoder = MaybeStringIntDecoder.class)
    private int id;
    private Name name;
    
    // standard setters and getters
}

Vi kan nu parse JSON, selv når id værdi er en streng :

@Test
public void givenTypeInJsonFuzzy_whenFieldIsMaybeDecoded_thenFieldParsedCorrectly() {
    String input = "{\"id\":\"1\",\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
    
    Student student = JsonIterator.deserialize(input, Student.class);

    assertThat(student.getId()).isEqualTo(1); 
}

Tilsvarende tilbyder Jsoniter andre dekodere såsom MaybeStringLongDecoder og MaybeEmptyArrayDecoder .

Lad os nu forestille os, at vi forventede at modtage et JSON-dokument med Studenten detaljer, men vi modtager i stedet følgende dokument:

{"error":404,"description":"Student record not found"}

Hvad skete der her? Vi forventede et successvar med Student data, men vi modtog en fejl respons. Dette er et meget almindeligt scenarie, men hvordan ville vi håndtere dette?

En måde er at udføre en null tjek for at se, om vi modtog et fejlsvar, før vi udtrak eleven data. Dog er null kontrol kan føre til noget svær at læse kode, og problemet forværres, hvis vi har en indlejret JSON på flere niveauer.

Jsoniters parsing ved hjælp af Any API kommer til undsætning.

3.3. JSON-parsing ved hjælp af enhver API

Når selve JSON-strukturen er dynamisk, kan vi bruge Jsoniters Any API, der giver en skemafri parsing af JSON . Dette fungerer på samme måde som at parse JSON til et Map .

Lad os analysere eleven JSON som før, men ved at bruge Enhver API denne gang:

@Test
public void whenParsedUsingAnyAPI_thenFieldValueCanBeExtractedUsingTheFieldName() {
    String input = "{\"id\":1,\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
    
    Any any = JsonIterator.deserialize(input);

    assertThat(any.toInt("id")).isEqualTo(1);
    assertThat(any.toString("name", "firstName")).isEqualTo("Joe");
    assertThat(any.toString("name", "surname")).isEqualTo("Blogg"); 
}

Lad os forstå dette eksempel. Først bruger vi JsonIterator.deserialize(..) at parse JSON. Vi angiver dog ikke en skemaklasse i dette tilfælde. Resultatet er af typen Alle.

Dernæst læser vi feltværdierne ved hjælp af feltnavnene. Vi læser "id" feltværdien ved hjælp af Any.toInt metode. toInt metode konverterer "id"-værdien til et heltal. På samme måde læser vi feltværdierne "name.firstName" og "name.surname" som strengværdier ved hjælp af toString metode.

Brug af Alle API, kan vi også kontrollere, om et element er til stede i JSON. Vi kan gøre dette ved at slå elementet op og derefter inspicere valueType af opslagsresultatet. valueType vil være UGYLDIG når elementet ikke er til stede i JSON.

For eksempel:

@Test
public void whenParsedUsingAnyAPI_thenFieldValueTypeIsCorrect() {
    String input = "{\"id\":1,\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
    
    Any any = JsonIterator.deserialize(input);

    assertThat(any.get("id").valueType()).isEqualTo(ValueType.NUMBER);
    assertThat(any.get("name").valueType()).isEqualTo(ValueType.OBJECT);
    assertThat(any.get("error").valueType()).isEqualTo(ValueType.INVALID);
}

Felterne "id" og "name" er til stede i JSON og dermed deres valueType er NUMBER og OBJEKT henholdsvis. JSON-inputtet har dog ikke et element med navnet "error", og derfor er valueType er UGYLDIG .

Går vi tilbage til scenariet nævnt i slutningen af ​​det foregående afsnit, skal vi opdage, om det JSON-input, vi modtog, er en succes eller et fejlsvar. Vi kan kontrollere, om vi har modtaget et fejlsvar ved at inspicere valueType af "fejl"-elementet:

String input = "{\"error\":404,\"description\":\"Student record not found\"}";
Any response = JsonIterator.deserialize(input);

if (response.get("error").valueType() != ValueType.INVALID) {
    return "Error!! Error code is " + response.toInt("error");
}
return "Success!! Student id is " + response.toInt("id");

Når den køres, vil ovenstående kode returnere “Fejl!! Fejlkoden er 404” .

Dernæst vil vi se på at bruge Iterator API til at parse JSON-dokumenter.

3.4. JSON-parsing ved hjælp af Iterator API

Hvis vi ønsker at udføre bindingen manuelt, kan vi bruge Jsoniters Iterator API. Lad os overveje JSON:

{"firstName":"Joe","surname":"Blogg"}

Vi bruger navnet skemaklasse, som vi tidligere brugte til at parse JSON ved hjælp af Iterator API:

@Test
public void whenParsedUsingIteratorAPI_thenFieldValuesExtractedCorrectly() throws Exception {
    Name name = new Name();    
    String input = "{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}";
    JsonIterator iterator = JsonIterator.parse(input);

    for (String field = iterator.readObject(); field != null; field = iterator.readObject()) {
        switch (field) {
            case "firstName":
                if (iterator.whatIsNext() == ValueType.STRING) {
                    name.setFirstName(iterator.readString());
                }
                continue;
            case "surname":
                if (iterator.whatIsNext() == ValueType.STRING) {
                    name.setSurname(iterator.readString());
                }
                continue;
            default:
                iterator.skip();
        }
    }

    assertThat(name.getFirstName()).isEqualTo("Joe");
    assertThat(name.getSurname()).isEqualTo("Blogg");
}

Lad os forstå ovenstående eksempel. Først parser vi JSON-dokumentet som en iterator. Vi bruger den resulterende JsonIterator instans for at iterere over JSON-elementerne:

  1. Vi starter med at kalde readObject metode, som returnerer det næste feltnavn (eller et null). hvis slutningen af ​​dokumentet er nået).
  2. Hvis feltnavnet ikke er interessant for os, springer vi JSON-elementet over ved at bruge spring over metode. Ellers inspicerer vi elementets datatype ved at bruge whatIsNext metode. Påkaldelse af whatIsNext metode er ikke obligatorisk, men er nyttig, når feltets datatype er ukendt for os.
  3. Til sidst udtrækker vi værdien af ​​JSON-elementet ved hjælp af readString metode.

4. Konklusion

I denne artikel diskuterede vi de forskellige tilgange, der tilbydes af Jsoniter til at parse JSON-dokumenter som Java-objekter.

Først så vi på standardmåden til at parse et JSON-dokument ved hjælp af en skemaklasse.

Dernæst så vi på håndteringen af ​​uklare datatyper og de dynamiske strukturer ved parsing af JSON-dokumenter ved hjælp af Måske dekodere og Alle datatype, henholdsvis.

Til sidst så vi på Iterator API til at binde JSON manuelt til et Java-objekt.

Som altid er kildekoden til eksemplerne brugt i denne artikel tilgængelig på GitHub.


Java tag