Memproses JSON dengan Kotlin dan Klaxson

1. Ikhtisar

Klaxon adalah salah satu library open source yang bisa kita gunakan untuk mengurai JSON di Kotlin.

Dalam tutorial ini, kita akan melihat fitur-fiturnya.

2. Ketergantungan Maven

Pertama, kita perlu menambahkan dependensi perpustakaan ke proyek Maven kita:

 com.beust klaxon 3.0.4 

Versi terbaru dapat ditemukan di jcenter atau di Spring Plugins Repository.

3. Fitur API

Klaxon memiliki empat API untuk bekerja dengan dokumen JSON. Kami akan menjelajahi ini di bagian berikut.

4. API Binding Objek

Dengan API ini, kita dapat mengikat dokumen JSON ke objek Kotlin dan sebaliknya .

Untuk memulai, mari tentukan dokumen JSON berikut:

{ "name": "HDD" }

Selanjutnya, kita akan membuat kelas Produk untuk mengikat:

class Product(val name: String)

Sekarang, kami dapat menguji serialisasi:

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

Dan kami dapat menguji deserialisasi:

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

API ini juga mendukung bekerja dengan kelas data serta kelas yang dapat berubah dan tidak berubah.

Klaxon memungkinkan kita menyesuaikan proses pemetaan dengan anotasi @Json . Anotasi ini memiliki dua properti:

  • nama - untuk menetapkan nama yang berbeda pada bidang
  • diabaikan - untuk mengabaikan bidang proses pemetaan

Mari buat kelas CustomProduct untuk melihat cara kerjanya:

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

Sekarang, mari kita verifikasi dengan tes:

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

Seperti yang bisa kita lihat, properti name diserialkan sebagai productName , dan properti id diabaikan.

5. API Streaming

Dengan API Streaming, kami dapat menangani dokumen JSON yang sangat besar dengan membaca dari aliran. Fitur ini memungkinkan kode kami memproses nilai JSON saat masih membaca .

Kita perlu menggunakan kelas JsonReader dari API untuk membaca aliran JSON. Kelas ini memiliki dua fungsi khusus untuk menangani streaming:

  • beginObject () - memastikan bahwa token berikutnya adalah awal dari sebuah objek
  • beginArray () - memastikan bahwa token berikutnya adalah awal dari sebuah array

Dengan fungsi-fungsi ini, kita dapat memastikan bahwa aliran diposisikan dengan benar dan ditutup setelah mengkonsumsi objek atau larik.

Mari kita uji API streaming terhadap larik kelas ProductData berikut :

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. API Kueri Jalur JSON

Klaxon supports the element location feature from the JSON Path specification. With this API, we can define path matchers to locate specific entries in our documents.

Note that this API is streaming, too, and we'll be notified after an element is found and parsed.

We need to use the PathMatcher interface. This interface is called when the JSON Path found matches of the regular expression.

To use this, we need to implement its methods:

  • pathMatches() – return true if we want to observe this path
  • onMatch() – fired when the path is found; note that the value can only be a basic type (e.g., int, String) and never JsonObject or JsonArray

Mari kita uji untuk melihatnya beraksi.

Pertama, mari kita tentukan dokumen JSON inventaris sebagai sumber data:

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

Sekarang, kami mengimplementasikan antarmuka PathMatcher sebagai berikut:

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") } } }

Perhatikan bahwa kami mendefinisikan regex untuk mencocokkan jenis disk dari dokumen inventaris kami.

Sekarang, kami siap untuk menentukan pengujian kami:

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

7. API Tingkat Rendah

Dengan Klaxon, kita dapat memproses dokumen JSON seperti Peta atau Daftar. Untuk melakukan ini, kita dapat menggunakan kelas JsonObject dan JsonArray dari API.

Mari lakukan pengujian untuk melihat JsonObject beraksi:

@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) }

Sekarang, mari kita uji untuk melihat fungsionalitas JsonArray :

@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) }) }

Seperti yang bisa kita lihat di kedua kasus, kita membuat konversi tanpa definisi kelas tertentu.

8. Kesimpulan

Pada artikel ini, kami menjelajahi perpustakaan Klaxon dan API-nya untuk menangani dokumen JSON.

Seperti biasa, kode sumber tersedia di Github.