Memproses JSON dengan Kotlin dan Klaxson

1. Gambaran keseluruhan

Klaxon adalah salah satu perpustakaan sumber terbuka yang dapat kita gunakan untuk menguraikan JSON di Kotlin.

Dalam tutorial ini, kita akan melihat ciri-cirinya.

2. Ketergantungan Maven

Pertama, kita perlu menambahkan pergantungan perpustakaan ke projek Maven kami:

 com.beust klaxon 3.0.4 

Versi terbaru boleh didapati di jcenter atau di Spring Plugins Repository.

3. Ciri API

Klaxon mempunyai empat API untuk bekerja dengan dokumen JSON. Kami akan menerangkannya dalam bahagian berikut.

4. Objek Mengikat API

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

Untuk memulakan, mari tentukan dokumen JSON berikut:

{ "name": "HDD" }

Seterusnya, kami akan membuat kelas Produk untuk mengikat:

class Product(val name: String)

Sekarang, kita boleh menguji serialisasi:

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

Dan kita boleh menguji deserialisasi:

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

API ini juga menyokong bekerja dengan kelas data dan juga kelas yang boleh berubah dan tidak berubah.

Klaxon membolehkan kami menyesuaikan proses pemetaan dengan anotasi @Json . Anotasi ini mempunyai dua sifat:

  • name - untuk menetapkan nama yang berbeza untuk bidang
  • diabaikan - kerana 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 mengesahkannya dengan ujian:

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

Seperti yang dapat kita lihat, nama properti diselaraskan sebagai productName , dan sifat id diabaikan.

5. Streaming API

Dengan Streaming API, kita dapat menangani dokumen JSON yang besar dengan membaca dari aliran. Ciri ini membolehkan kod kami memproses nilai JSON ketika masih membaca .

Kita perlu menggunakan kelas JsonReader dari API untuk membaca aliran JSON. Kelas ini mempunyai dua fungsi khas untuk menangani penstriman:

  • beginObject () - memastikan bahawa token seterusnya adalah permulaan objek
  • beginArray () - memastikan bahawa token seterusnya adalah permulaan array

Dengan fungsi-fungsi ini, kita dapat memastikan aliran diposisikan dengan benar dan ditutup setelah memakan objek atau array.

Mari uji API streaming dengan pelbagai 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 Pertanyaan Laluan JSON

Klaxon menyokong ciri lokasi elemen dari spesifikasi Jalur JSON. Dengan API ini, kita dapat menentukan pemadan jalan untuk mencari entri tertentu dalam dokumen kita .

Perhatikan bahawa API ini juga streaming, dan kami akan diberitahu setelah elemen dijumpai dan dihuraikan.

Kita perlu menggunakan antara muka PathMatcher . Antaramuka ini dipanggil apabila JSON Path menemui padanan dengan ungkapan biasa.

Untuk menggunakan ini, kita perlu menerapkan kaedahnya:

  • pathMatches () - kembali benar jika kita ingin memerhatikan jalan ini
  • onMatch () - dipecat semasa jalan dijumpai; perhatikan bahawa nilainya hanya boleh menjadi jenis asas (mis. int , String ) dan tidak pernah JsonObject atau JsonArray

Mari buat ujian untuk melihatnya beraksi.

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

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

Sekarang, kami melaksanakan antara muka PathMatcher seperti 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 bahawa kami menentukan regex agar sesuai dengan jenis cakera dokumen inventori kami.

Sekarang, kami bersedia untuk menentukan ujian kami:

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

7. API Peringkat Rendah

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

Mari buat ujian 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 buat ujian untuk melihat fungsi 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 dapat kita lihat dalam kedua kes ini, kita membuat penukaran tanpa definisi kelas tertentu.

8. Kesimpulannya

Dalam artikel ini, kami meneroka perpustakaan Klaxon dan APInya untuk menangani dokumen JSON.

Seperti biasa, kod sumber tersedia di Github.