Bagaimana cara mengurai JSON di Kotlin?

121

Saya menerima string objek JSON yang cukup dalam dari layanan yang harus saya parse ke objek JSON dan kemudian memetakannya ke kelas.

Bagaimana cara mengubah string JSON menjadi objek di Kotlin?

Setelah itu pemetaan ke kelas masing-masing, saya menggunakan StdDeserializer dari Jackson. Masalah muncul saat objek memiliki properti yang juga harus di-deserialisasi menjadi kelas. Saya tidak bisa mendapatkan pemeta objek, setidaknya saya tidak tahu caranya, di dalam deserializer lain.

Terima kasih sebelumnya atas bantuannya. Lebih disukai, secara native, saya mencoba mengurangi jumlah dependensi yang saya butuhkan jadi jika jawabannya hanya untuk manipulasi JSON dan parsing saja sudah cukup.

AJ_1310
sumber
2
Saya belum mengembangkan di Jawa. Ini bukan kesalahan yang saya dapatkan. Saya hanya tidak tahu cara melakukan parsing yang efektif di Kotlin secara native. Semua pencarian selalu mengarah pada kerangka kerja. Java memiliki org.json.simple. Mempercayai fitur pelengkapan otomatis pada IDE, Kotlin tidak.
AJ_1310
Paket org.json.simple tidak asli untuk Java. Saya kira perpustakaan ini: github.com/fangyidong/json-simple . Anda dapat menggunakannya dengan Kotlin juga jika Anda mau (meskipun pustaka klaxon yang disarankan Jason Bourne mungkin merupakan pilihan yang lebih baik untuk Kotlin).
marstran
Lihatlah github.com/square/moshi . Ada posting blog tentang itu di medium.com/square-corner-blog/…
James Moore

Jawaban:

72

Anda dapat menggunakan perpustakaan ini https://github.com/cbeust/klaxon

Klaxon adalah library ringan untuk mengurai JSON di Kotlin.

Istiak Morsalin
sumber
86
Penulis di sini, jangan ragu untuk mengirimi saya email jika Anda memiliki pertanyaan / saran.
Cedric Beust
Perpustakaan java apa yang harus saya impor untuk mendapatkan Parser yang benar? Saya mencoba org.json. *, Tetapi saya pasti melewatkan sesuatu di setelan Gradle saya. Saya pikir dokumentasi Klaxon mengasumsikan terlalu banyak (seperti pengguna yang mengetahui perpustakaan Java).
Makis
@CedricBeust sudahkah Anda mencoba bekerja dengan objek kelas dengan sqlite? ada latihan yang direkomendasikan di sini?
Raju yourPepe
104

Tidak diragukan lagi bahwa masa depan penguraian di Kotlin adalah dengan kotlinx.serialization. Ini adalah bagian dari perpustakaan Kotlin. Ini masih pada saat penulisan dalam tahap inkubator.

https://github.com/Kotlin/kotlinx.serialization

import kotlinx.serialization.*
import kotlinx.serialization.json.JSON

@Serializable
data class MyModel(val a: Int, @Optional val b: String = "42")

fun main(args: Array<String>) {

    // serializing objects
    val jsonData = JSON.stringify(MyModel.serializer(), MyModel(42))
    println(jsonData) // {"a": 42, "b": "42"}

    // serializing lists
    val jsonList = JSON.stringify(MyModel.serializer().list, listOf(MyModel(42)))
    println(jsonList) // [{"a": 42, "b": "42"}]

    // parsing data back
    val obj = JSON.parse(MyModel.serializer(), """{"a":42}""")
    println(obj) // MyModel(a=42, b="42")
}
Elisha Sterngold
sumber
3
Masalah yang saya hadapi dengan ini adalah Anda hampir tidak dapat menggunakannya dengan obat generik. Setidaknya saya belum menemukan cara untuk melakukannya. Dan saya tentunya tidak ingin menggunakan refleksi.
natronite
3
Serialisasi KotlinX masih dalam tahap percobaan, jadi mereka memperkenalkan perubahan yang dapat menyebabkan gangguan dalam rilis baru. Selain itu, ini tidak aman untuk utas, jadi JSON Anda mungkin rusak jika beberapa utas mencoba menggunakan satu contoh Json(itu umum). Selain itu, ada beberapa masalah Github terbuka dengan label bug. Jadi, masih berisiko untuk digunakan dalam produksi menurut saya (kecuali Anda bersedia meluangkan waktu untuk memperbaiki masalah potensial dan tidak berencana untuk sering memperbaruinya). Project tersebut memang menarik terutama untuk project Kotlin Multiplatform, namun masih belum stabil.
Javad Sadeqzadeh
Sepertinya sudah ada perubahan yang
mengganggu
Ini juga membutuhkan ketergantungan tambahan, jadi ikuti tautan untuk panduan
xjcl
34

Tanpa perpustakaan eksternal (di Android)

Untuk mengurai ini:

val jsonString = """
    {
       "type":"Foo",
       "data":[
          {
             "id":1,
             "title":"Hello"
          },
          {
             "id":2,
             "title":"World"
          }
       ]
    }        
"""

Gunakan kelas-kelas ini:

import org.json.JSONObject

class Response(json: String) : JSONObject(json) {
    val type: String? = this.optString("type")
    val data = this.optJSONArray("data")
            ?.let { 0.until(it.length()).map { i -> it.optJSONObject(i) } } // returns an array of JSONObject
            ?.map { Foo(it.toString()) } // transforms each JSONObject of the array into Foo
}

class Foo(json: String) : JSONObject(json) {
    val id = this.optInt("id")
    val title: String? = this.optString("title")
}

Pemakaian:

val foos = Response(jsonString)
frouo
sumber
2
Jadi jika ini tidak memerlukan pustaka eksternal, itu berarti org.json.JSONObject adalah bagian dari pustaka standar bukan?
still_dreaming_1
@ still_dreaming_1 ya, "Ditambahkan dalam API level 1", lih. developer.android.com/reference/org/json/JSONObject.html
frouo
Saya kira itu hal Android? Saya mencarinya di perpustakaan standar Kotlin atau Java untuk JVM.
still_dreaming_1
Oh ya tentu saja, maaf saya lupa menyebutkannya dalam jawaban! Mungkin Anda dapat menggunakan JsonObjectjika JVM Anda berjalan di bawah Java7 ( docs.oracle.com/javaee/7/api/javax/json/JsonObject.html )?
frouo
Oh, saya tidak menemukan yang itu sebelumnya, terima kasih! Ada beberapa kelas terkait lainnya juga seperti JsonReader. Sepertinya mereka adalah bagian dari Java EE, tetapi bukan Java SE. Saya akan melihat kemungkinan beralih ke Java EE.
still_dreaming_1
26

Kamu bisa memakai Gson .

Contoh

Langkah 1

Tambahkan kompilasi

compile 'com.google.code.gson:gson:2.8.2'

Langkah 2

Konversi json ke Kotlin Bean(gunakan JsonToKotlinClass )

Seperti ini

Json data

{
"timestamp": "2018-02-13 15:45:45",
"code": "OK",
"message": "user info",
"path": "/user/info",
"data": {
    "userId": 8,
    "avatar": "/uploads/image/20180115/1516009286213053126.jpeg",
    "nickname": "",
    "gender": 0,
    "birthday": 1525968000000,
    "age": 0,
    "province": "",
    "city": "",
    "district": "",
    "workStatus": "Student",
    "userType": 0
},
"errorDetail": null
}

Kotlin Bean

class MineUserEntity {

    data class MineUserInfo(
        val timestamp: String,
        val code: String,
        val message: String,
        val path: String,
        val data: Data,
        val errorDetail: Any
    )

    data class Data(
        val userId: Int,
        val avatar: String,
        val nickname: String,
        val gender: Int,
        val birthday: Long,
        val age: Int,
        val province: String,
        val city: String,
        val district: String,
        val workStatus: String,
        val userType: Int
    )
}

LANGKAH 3

Menggunakan Gson

var gson = Gson()
var mMineUserEntity = gson?.fromJson(response, MineUserEntity.MineUserInfo::class.java)
KeLiuyue
sumber
ini memberi saya java.lang.IllegalStateException: Diharapkan string tetapi BEGIN_OBJECT pada baris 1 kolom 700 jalur
Srishti Roy
Anda harus memeriksa data pengembalian Anda terlebih dahulu. @ SrishtiRoy
KeLiuyue
berhasil, tetapi jika tanggapan json saya seperti "kategori": ["Direkomendasikan"], lalu?
Srishti Roy
@SrishtiRoy tanggapannya adalah data JSON ilegal. Data legal JSON dimulai dengan {atau[
KeLiuyue
1
Masalah dengan Gson adalah ia mengabaikan nullability. Sebuah valproperti bisa dengan mudah hilang nulljika tidak ada di JSON. Selain itu, nilai default tidak digunakan sama sekali.
pengguna3738870
21

Tidak yakin apakah ini yang Anda butuhkan tetapi inilah cara saya melakukannya.

Menggunakan import org.json.JSONObject:

    val jsonObj = JSONObject(json.substring(json.indexOf("{"), json.lastIndexOf("}") + 1))
    val foodJson = jsonObj.getJSONArray("Foods")
    for (i in 0..foodJson!!.length() - 1) {
        val categories = FoodCategoryObject()
        val name = foodJson.getJSONObject(i).getString("FoodName")
        categories.name = name
    }

Berikut contoh json:

{"Foods": [{"FoodName": "Apel", "Berat": "110"}]}

markB
sumber
8
apa ketergantungannya?
Luís Soares
Saya menggunakan org.json. Ini tautannya: mvnrepository.com/artifact/org.json/json/20180813
tandaiB
Metode ini mensyaratkan bahwa kelas harus memiliki konstruktor default tanpa parameter apa pun. Bagaimana jika kelas data memiliki params dalam konstruktor seperti di bawah ini: data class SomeClass(val param1: Int, val param2: Int).
leimenghao
@leimenghao Anda dapat melakukan ini dalam satu baris: val categories = SomeClass (param1 = foodJson.getJSONObject (i) .getString ("FoodName"), param2 = foodJson.getJSONObject (i) .getInt ("Weight"))
markB
Bekerja dengan sangat baik. Hanya untuk mengatakan, Anda dapat menggunakan for (i in 0 until foodJson!!.length()) {bukan for (i in 0..foodJson!!.length() - 1) {. Itu melakukan hal yang sama, dan itu lebih visual
Arnyminer Z
12

Saya pribadi menggunakan modul Jackson untuk Kotlin yang dapat Anda temukan di sini: jackson-module-kotlin .

implementation "com.fasterxml.jackson.module:jackson-module-kotlin:$version"

Sebagai contoh, berikut adalah kode untuk mengurai JSON dari skilltree Path of Exile yang cukup berat (84k baris saat diformat):

Kode Kotlin:

package util

import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.module.kotlin.*
import java.io.File

data class SkillTreeData( val characterData: Map<String, CharacterData>, val groups: Map<String, Group>, val root: Root,
                          val nodes: List<Node>, val extraImages: Map<String, ExtraImage>, val min_x: Double,
                          val min_y: Double, val max_x: Double, val max_y: Double,
                          val assets: Map<String, Map<String, String>>, val constants: Constants, val imageRoot: String,
                          val skillSprites: SkillSprites, val imageZoomLevels: List<Int> )


data class CharacterData( val base_str: Int, val base_dex: Int, val base_int: Int )

data class Group( val x: Double, val y: Double, val oo: Map<String, Boolean>?, val n: List<Int> )

data class Root( val g: Int, val o: Int, val oidx: Int, val sa: Int, val da: Int, val ia: Int, val out: List<Int> )

data class Node( val id: Int, val icon: String, val ks: Boolean, val not: Boolean, val dn: String, val m: Boolean,
                 val isJewelSocket: Boolean, val isMultipleChoice: Boolean, val isMultipleChoiceOption: Boolean,
                 val passivePointsGranted: Int, val flavourText: List<String>?, val ascendancyName: String?,
                 val isAscendancyStart: Boolean?, val reminderText: List<String>?, val spc: List<Int>, val sd: List<String>,
                 val g: Int, val o: Int, val oidx: Int, val sa: Int, val da: Int, val ia: Int, val out: List<Int> )

data class ExtraImage( val x: Double, val y: Double, val image: String )

data class Constants( val classes: Map<String, Int>, val characterAttributes: Map<String, Int>,
                      val PSSCentreInnerRadius: Int )

data class SubSpriteCoords( val x: Int, val y: Int, val w: Int, val h: Int )

data class Sprite( val filename: String, val coords: Map<String, SubSpriteCoords> )

data class SkillSprites( val normalActive: List<Sprite>, val notableActive: List<Sprite>,
                         val keystoneActive: List<Sprite>, val normalInactive: List<Sprite>,
                         val notableInactive: List<Sprite>, val keystoneInactive: List<Sprite>,
                         val mastery: List<Sprite> )

private fun convert( jsonFile: File ) {
    val mapper = jacksonObjectMapper()
    mapper.configure( DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true )

    val skillTreeData = mapper.readValue<SkillTreeData>( jsonFile )
    println("Conversion finished !")
}

fun main( args : Array<String> ) {
    val jsonFile: File = File( """rawSkilltree.json""" )
    convert( jsonFile )

JSON (tidak diformat): http://filebin.ca/3B3reNQf3KXJ/rawSkilltree.json

Mengingat deskripsi Anda, saya yakin itu sesuai dengan kebutuhan Anda.

Neurf
sumber
1
Berbeda dari Klaxon (ada bug ketika saya mencoba), Jackson benar-benar berfungsi :)
redsk
Selain itu, Anda dapat menggunakan plugin kelas data JSON ke Kotlin di intellij untuk membuat kelas data untuk Anda.
Brooks DuBois
7

Untuk mengonversi JSON ke Kotlin gunakan http://www.json2kotlin.com/

Anda juga dapat menggunakan plugin Android Studio. File> Settings, pilih Pluginsdi pohon kiri, tekan "Browse repositories ...", cari " JsonToKotlinClass ", pilih dan klik tombol hijau "Install".

plugin

Setelah AS restart, Anda dapat menggunakannya. Anda dapat membuat kelas dengan File > New > JSON To Kotlin Class (JsonToKotlinClass). Cara lain adalah dengan menekan Alt + K.

masukkan deskripsi gambar di sini

Kemudian Anda akan melihat dialog untuk menempelkan JSON.

Pada tahun 2018 saya harus menambahkan package com.my.package_namedi awal kelas.

CoolMind
sumber
4

Pertama-tama.

Anda dapat menggunakan plugin pengonversi kelas Data JSON ke Kotlin di Android Studio untuk pemetaan JSON ke kelas POJO (kelas data kotlin). Plugin ini akan membuat anotasi kelas data Kotlin Anda sesuai dengan JSON.

Kemudian Anda dapat menggunakan pengonversi GSON untuk mengonversi JSON ke Kotlin.

Ikuti tutorial Lengkap ini: Tutorial Parsing JSON Android Kotlin

Jika Anda ingin mengurai json secara manual.

val **sampleJson** = """
  [
  {
   "userId": 1,
   "id": 1,
   "title": "sunt aut facere repellat provident occaecati excepturi optio 
    reprehenderit",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita"
   }]
   """

Kode untuk Parse di atas Array JSON dan objeknya di indeks 0.

var jsonArray = JSONArray(sampleJson)
for (jsonIndex in 0..(jsonArray.length() - 1)) {
Log.d("JSON", jsonArray.getJSONObject(jsonIndex).getString("title"))
}
Developine
sumber
1

http://www.jsonschema2pojo.org/ Hai, Anda dapat menggunakan situs web ini untuk mengonversi json ke pojo.
control + Alt + shift + k

Setelah itu Anda dapat secara manual mengonversi kelas model tersebut ke kelas model kotlin. dengan bantuan shortcut di atas.

kundan kamal
sumber
1
Ini akan dikonversi ke Java.
CoolMind
0

Agak terlambat, tapi terserah.

Jika Anda lebih suka mengurai JSON daripada JavaScript seperti konstruksi yang menggunakan semantik Kotlin, saya merekomendasikan JSONKraken , di mana saya penulisnya.

Saran dan pendapat tentang masalah ini sangat kami hargai!

Facundo Garcia
sumber
-4

Unduh sumber deme dari sini ( Json parsing di android kotlin )

Tambahkan ketergantungan ini:

compile 'com.squareup.okhttp3:okhttp:3.8.1'

Fungsi api panggilan:

 fun run(url: String) {
    dialog.show()
    val request = Request.Builder()
            .url(url)
            .build()

    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            dialog.dismiss()

        }

        override fun onResponse(call: Call, response: Response) {
            var str_response = response.body()!!.string()
            val json_contact:JSONObject = JSONObject(str_response)

            var jsonarray_contacts:JSONArray= json_contact.getJSONArray("contacts")

            var i:Int = 0
            var size:Int = jsonarray_contacts.length()

            al_details= ArrayList();

            for (i in 0.. size-1) {
                var json_objectdetail:JSONObject=jsonarray_contacts.getJSONObject(i)


                var model:Model= Model();
                model.id=json_objectdetail.getString("id")
                model.name=json_objectdetail.getString("name")
                model.email=json_objectdetail.getString("email")
                model.address=json_objectdetail.getString("address")
                model.gender=json_objectdetail.getString("gender")

                al_details.add(model)


            }

            runOnUiThread {
                //stuff that updates ui
                val obj_adapter : CustomAdapter
                obj_adapter = CustomAdapter(applicationContext,al_details)
                lv_details.adapter=obj_adapter
            }

            dialog.dismiss()

        }

    })
Deepshikha Puri
sumber