Verarbeitung von JSON mit Kotlin und Klaxson

1. Übersicht

Klaxon ist eine der Open Source-Bibliotheken, mit denen wir JSON in Kotlin analysieren können.

In diesem Tutorial werden wir uns die Funktionen ansehen.

2. Maven-Abhängigkeit

Zuerst müssen wir die Bibliotheksabhängigkeit zu unserem Maven-Projekt hinzufügen:

 com.beust klaxon 3.0.4 

Die neueste Version finden Sie im jcenter oder im Spring Plugins Repository.

3. API-Funktionen

Klaxon verfügt über vier APIs für die Arbeit mit JSON-Dokumenten. Wir werden diese in den folgenden Abschnitten untersuchen.

4. Objektbindungs-API

Mit dieser API können wir JSON-Dokumente an Kotlin-Objekte binden und umgekehrt .

Definieren wir zunächst das folgende JSON-Dokument:

{ "name": "HDD" }

Als Nächstes erstellen wir die Produktklasse für die Bindung:

class Product(val name: String)

Jetzt können wir die Serialisierung testen:

@Test fun givenProduct_whenSerialize_thenGetJsonString() { val product = Product("HDD") val result = Klaxon().toJsonString(product) assertThat(result).isEqualTo("""{"name" : "HDD"}""") }

Und wir können die Deserialisierung testen:

@Test fun givenJsonString_whenDeserialize_thenGetProduct() { val result = Klaxon().parse( """ { "name" : "RAM" } """) assertThat(result?.name).isEqualTo("RAM") }

Diese API unterstützt auch die Arbeit mit Datenklassen sowie veränderlichen und unveränderlichen Klassen.

Mit Klaxon können wir den Zuordnungsprozess mit der Annotation @Json anpassen . Diese Anmerkung hat zwei Eigenschaften:

  • name - zum Festlegen eines anderen Namens für die Felder
  • ignoriert - zum Ignorieren von Feldern des Zuordnungsprozesses

Erstellen wir eine CustomProduct- Klasse, um zu sehen, wie diese funktionieren:

class CustomProduct( @Json(name = "productName") val name: String, @Json(ignored = true) val id: Int)

Lassen Sie es uns jetzt mit einem Test überprüfen:

@Test fun givenCustomProduct_whenSerialize_thenGetJsonString() { val product = CustomProduct("HDD", 1) val result = Klaxon().toJsonString(product) assertThat(result).isEqualTo("""{"productName" : "HDD"}""") }

Wie wir sehen können, wird die name- Eigenschaft als productName serialisiert und die id- Eigenschaft wird ignoriert.

5. Streaming-API

Mit der Streaming-API können wir große JSON-Dokumente verarbeiten, indem wir aus einem Stream lesen. Mit dieser Funktion kann unser Code JSON-Werte verarbeiten, während er noch liest .

Wir müssen die JsonReader- Klasse aus der API verwenden, um einen JSON-Stream zu lesen. Diese Klasse verfügt über zwei spezielle Funktionen für das Streaming:

  • beginObject () - stellt sicher, dass das nächste Token der Anfang eines Objekts ist
  • beginArray () - stellt sicher, dass das nächste Token der Anfang eines Arrays ist

Mit diesen Funktionen können wir sicher sein, dass der Stream korrekt positioniert und nach dem Verzehr des Objekts oder Arrays geschlossen ist.

Testen wir die Streaming-API anhand eines Arrays der folgenden ProductData- Klasse:

data class ProductData(val name: String, val capacityInGb: Int)
@Test fun givenJsonArray_whenStreaming_thenGetProductArray() { val jsonArray = """ [ { "name" : "HDD", "capacityInGb" : 512 }, { "name" : "RAM", "capacityInGb" : 16 } ]""" val expectedArray = arrayListOf( ProductData("HDD", 512), ProductData("RAM", 16)) val klaxon = Klaxon() val productArray = arrayListOf() JsonReader(StringReader(jsonArray)).use { reader -> reader.beginArray { while (reader.hasNext()) { val product = klaxon.parse(reader) productArray.add(product!!) } } } assertThat(productArray).hasSize(2).isEqualTo(expectedArray) }

6. JSON Path Query API

Klaxon unterstützt die Elementpositionierungsfunktion aus der JSON-Pfadspezifikation. Mit dieser API können wir Pfadvergleiche definieren, um bestimmte Einträge in unseren Dokumenten zu finden .

Beachten Sie, dass diese API auch gestreamt wird und wir benachrichtigt werden, nachdem ein Element gefunden und analysiert wurde.

Wir müssen die PathMatcher- Schnittstelle verwenden. Diese Schnittstelle wird aufgerufen, wenn der JSON-Pfad Übereinstimmungen mit dem regulären Ausdruck gefunden hat.

Um dies zu nutzen, müssen wir seine Methoden implementieren:

  • pathMatches () - gibt true zurück, wenn wir diesen Pfad beobachten möchten
  • onMatch () - wird ausgelöst, wenn der Pfad gefunden wird; Beachten Sie, dass der Wert nur ein Basistyp sein kann (z. B. int , String ) und niemals JsonObject oder JsonArray

Lassen Sie uns einen Test machen, um es in Aktion zu sehen.

Definieren wir zunächst ein Inventar-JSON-Dokument als Datenquelle:

{ "inventory" : { "disks" : [ { "type" : "HDD", "sizeInGb" : 1000 }, { "type" : "SDD", "sizeInGb" : 512 } ] } }

Jetzt implementieren wir die PathMatcher- Schnittstelle wie folgt:

val pathMatcher = object : PathMatcher { override fun pathMatches(path: String) = Pattern.matches(".*inventory.*disks.*type.*", path) override fun onMatch(path: String, value: Any) { when (path) { "$.inventory.disks[0].type" -> assertThat(value).isEqualTo("HDD") "$.inventory.disks[1].type" -> assertThat(value).isEqualTo("SDD") } } }

Beachten Sie, dass wir den regulären Ausdruck so definiert haben, dass er dem Datenträgertyp unseres Inventardokuments entspricht.

Jetzt können wir unseren Test definieren:

@Test fun givenDiskInventory_whenRegexMatches_thenGetTypes() { val jsonString = """...""" val pathMatcher = //... Klaxon().pathMatcher(pathMatcher) .parseJsonObject(StringReader(jsonString)) }

7. Low-Level-API

Mit Klaxon können wir JSON-Dokumente wie eine Karte oder eine Liste verarbeiten. Dazu können wir die Klassen JsonObject und JsonArray aus der API verwenden.

Machen wir einen Test, um das JsonObject in Aktion zu sehen:

@Test fun givenJsonString_whenParser_thenGetJsonObject() { val jsonString = StringBuilder(""" { "name" : "HDD", "capacityInGb" : 512, "sizeInInch" : 2.5 } """) val parser = Parser() val json = parser.parse(jsonString) as JsonObject assertThat(json) .hasSize(3) .containsEntry("name", "HDD") .containsEntry("capacityInGb", 512) .containsEntry("sizeInInch", 2.5) }

Lassen Sie uns nun einen Test durchführen, um die JsonArray- Funktionalität zu sehen:

@Test fun givenJsonStringArray_whenParser_thenGetJsonArray() { val jsonString = StringBuilder(""" [ { "name" : "SDD" }, { "madeIn" : "Taiwan" }, { "warrantyInYears" : 5 } ]""") val parser = Parser() val json = parser.parse(jsonString) as JsonArray assertSoftly({ softly -> softly.assertThat(json).hasSize(3) softly.assertThat(json[0]["name"]).isEqualTo("SDD") softly.assertThat(json[1]["madeIn"]).isEqualTo("Taiwan") softly.assertThat(json[2]["warrantyInYears"]).isEqualTo(5) }) }

Wie wir in beiden Fällen sehen können, haben wir die Konvertierungen ohne die Definition bestimmter Klassen durchgeführt.

8. Fazit

In diesem Artikel haben wir die Klaxon-Bibliothek und ihre APIs untersucht, um JSON-Dokumente zu verarbeiten.

Wie immer ist der Quellcode über Github verfügbar.