Kotlin'de JSON nasıl ayrıştırılır?


122

Bir JSON nesnesine ayrıştırmam ve ardından sınıflara eşlemem gereken bir hizmetten oldukça derin bir JSON nesne dizesi alıyorum.

Bir JSON dizesini Kotlin'de nesneye nasıl dönüştürebilirim?

Bundan sonra ilgili sınıflarla eşleştirme, Jackson'dan StdDeserializer'ı kullanıyordum. Sorun, nesnenin sınıflara göre serileştirilmesi kaldırılması gereken özelliklere sahip olduğu anda ortaya çıkar. Nesne eşleştiricisini başka bir seriyi kaldırıcının içine alamadım, en azından nasıl olduğunu bilmiyordum.

Herhangi bir yardım için şimdiden teşekkürler. Tercihen, yerel olarak, ihtiyacım olan bağımlılıkların sayısını azaltmaya çalışıyorum, eğer cevap yalnızca JSON manipülasyonu ve ayrıştırması içinse yeterli olacaktır.


2
Java'da geliştirmedim. Aldığım bir hata değil. Kotlin'de yerel olarak nasıl etkili ayrıştıracağımı bilmiyorum. Tüm aramalar her zaman bir çerçeveye götürür. Java'da bir org.json.simple vardır. IDE'nin otomatik tamamlama özelliklerine güvenen Kotlin güvenmiyor.
AJ_1310

Org.json.simple paketi Java'ya özgü değildir. Sanırım bu kitaplık: github.com/fangyidong/json-simple . İsterseniz Kotlin ile de kullanabilirsiniz (ancak Jason Bourne'un önerdiği klaxon kütüphanesi Kotlin için daha iyi bir seçim olabilir).
marstran

Yanıtlar:


73

Bu kitaplığı https://github.com/cbeust/klaxon kullanabilirsiniz

Klaxon, Kotlin'de JSON'u ayrıştırmak için hafif bir kitaplıktır.


87
Burada yazar, sorularınız / önerileriniz varsa bana e-posta göndermekten çekinmeyin.
Cedric Beust

Doğru Ayrıştırıcıyı elde etmek için hangi java kitaplıklarını içe aktarmalıyım? Org.json. * 'I denedim, ancak Gradle ayarlarımda bir şey eksik olmalı. Klaxon belgelerinin çok fazla varsayımda bulunduğunu düşünüyorum (kullanıcıların Java kitaplıklarını bilmesi gibi).
Makis

@CedricBeust sqlite ile sınıf nesnesiyle çalışmayı denediniz mi? burada önerilen herhangi bir uygulama var mı?
Raju yourPepe

105

Kotlin'de ayrıştırmanın geleceğinin kotlinx.serialization ile olacağına şüphe yok. Kotlin kütüphanelerinin bir parçasıdır. Hala kuluçka aşamasında yazılma aşamasındadır.

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

3
Bununla ilgili sahip olduğum sorun, onu jeneriklerle neredeyse hiç kullanamamanız. En azından bunu nasıl yapacağımı bulamadım. Ve kesinlikle yansımayı kullanmak istemiyorum.
natronite

3
KotlinX Serileştirme hala deneysel aşamadadır, bu nedenle yeni sürümlerde önemli değişiklikler getirmektedir. Ayrıca, iş parçacığı açısından güvenli değildir, bu nedenle birkaç iş parçacığı tek bir örnek kullanmaya çalışırsa JSON'nuz bozulabilir Json(bu yaygındır). Ayrıca, hata etiketiyle ilgili birkaç açık Github sorunu var. Bu nedenle, üretimde kullanım için hala riskli olduğunu söyleyebilirim (potansiyel sorunları çözmek için zaman harcamak ve sık sık güncellemeyi planlamıyorsanız). Proje özellikle Kotlin Multiplatform projeleri için gerçekten ilginç, ancak henüz kararlı değil.
Javad Sadeqzadeh

Şimdiden bir değişiklik var gibi görünüyor, JSON artık Json olarak adlandırılıyor
xjcl

Bu ayrıca ek bir bağımlılık gerektirir, bu nedenle bir kılavuz için bağlantıyı izleyin
xjcl

34

Harici kitaplık olmadan (Android'de)

Bunu ayrıştırmak için:

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

Şu sınıfları kullanın:

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

Kullanımı:

val foos = Response(jsonString)

2
Yani bu herhangi bir harici kitaplık gerektirmiyorsa, bu org.json.JSONObject'in standart kitaplığın bir parçası olduğu anlamına gelmelidir, değil mi?
still_dreaming_1

@ still_dreaming_1 evet, "API seviyesi 1'de eklendi", cf. developer.android.com/reference/org/json/JSONObject.html
frouo

Sanırım bu bir Android şey mi? JVM için Kotlin veya Java standart kitaplığında arıyordum.
still_dreaming_1

Oh evet kesinlikle, özür dilerim cevapta bundan bahsetmeyi unuttum! Belki kullanabilirsiniz JsonObjectJVM Java7 (altında çalışıyorsa docs.oracle.com/javaee/7/api/javax/json/JsonObject.html )?
frouo

Bunu daha önce bulamadım, teşekkürler! JsonReader gibi başka ilgili sınıflar da var. Görünüşe göre bunlar Java EE'nin bir parçası, ancak Java SE değil. Muhtemelen Java EE'ye geçmeye bakacağım.
still_dreaming_1

26

Kullanabilirsiniz Gson.

Misal

Aşama 1

Derleme ekle

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

Adım 2

Dönüştür json Kotlin Bean(kullanım JsonToKotlinClass )

Bunun gibi

Json veri

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

Aşama 3

kullanım Gson

var gson = Gson()
var mMineUserEntity = gson?.fromJson(response, MineUserEntity.MineUserInfo::class.java)

bu bana java.lang.IllegalStateException: Bir dize bekleniyordu, ancak satır 1 sütun 700 yolunda
BEGIN_OBJECT idi

Önce iade verilerinizi kontrol etmelisiniz. @ SrishtiRoy
KeLiuyue

işe yaradı, ancak json yanıtım "kategoriler": ["Önerilen"] gibiyse, o zaman?
Srishti Roy

@SrishtiRoy yanıt yasadışı JSON verisi. Yasal JSON verileri {veya ile başlatılır[
KeLiuyue

1
Gson ile ilgili sorun, boş atanabilirliği göz ardı etmesidir. JSON'da eksik olan bir valözellik kolayca olabilir null. Ayrıca, varsayılan değerler hiç kullanılmaz.
user3738870

21

İhtiyacın olan bu mu emin değilim ama ben böyle yaptım.

İmport org.json.JSONObject kullanarak:

    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
    }

İşte bir json örneği:

{"Yiyecekler": [{"YiyecekAdı": "Elmalar", "Ağırlık": "110"}]}


8
bağımlılık nedir?
Luís Soares

Org.json kullandım. İşte bağlantı: mvnrepository.com/artifact/org.json/json/20180813
markB

Bu yöntem, sınıfın herhangi bir parametre içermeyen varsayılan kurucuya sahip olmasını gerektirir. Veri sınıfı ise aşağıdaki gibi yapıcı içinde params var Ne: data class SomeClass(val param1: Int, val param2: Int).
leimenghao

@leimenghao Bunu tek satırda yapabilirsiniz: val kategorileri = SomeClass (param1 = foodJson.getJSONObject (i) .getString ("FoodName"), param2 = foodJson.getJSONObject (i) .getInt ("Weight"))
markB

Gerçekten iyi çalışıyor. Sadece söylemek for (i in 0 until foodJson!!.length()) {yerine kullanabilirsiniz for (i in 0..foodJson!!.length() - 1) {. Aynı şeyi yapıyor ve oldukça daha görsel
Arnyminer Z

12

Ben şahsen Kotlin için burada bulabileceğiniz Jackson modülünü kullanıyorum: jackson-module-kotlin .

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

Örnek olarak, oldukça ağır olan (biçimlendirildiğinde 84k satır) Sürgün Yolu beceri ağacının JSON'sini ayrıştırmak için kod:

Kotlin kodu:

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 (biçimlendirilmemiş): http://filebin.ca/3B3reNQf3KXJ/rawSkilltree.json

Açıklamanıza bakılırsa, ihtiyaçlarınıza uygun olduğuna inanıyorum.


1
Klaxon'dan farklı olarak (denediğimde bir hata vardı), Jackson aslında çalışıyor :)
redsk

Ek olarak, sizin için veri sınıfları oluşturmak için JSON'dan Kotlin'e veri sınıfı eklentisini intellij'de kullanabilirsiniz.
Brooks DuBois

7

JSON'u Kotlin'e dönüştürmek için http://www.json2kotlin.com/ adresini kullanın.

Ayrıca Android Studio eklentisini de kullanabilirsiniz. Dosya> Ayarlar, Pluginssol ağaçtan seçin , " Depolara göz at ..." düğmesine basın, " JsonToKotlinClass " ı arayın , seçin ve yeşil "Yükle" düğmesine tıklayın.

Eklenti

AS yeniden başlattıktan sonra kullanabilirsiniz. İle bir sınıf oluşturabilirsiniz File > New > JSON To Kotlin Class (JsonToKotlinClass). Başka bir yol da Alt + K tuşlarına basmaktır.

görüntü açıklamasını buraya girin

Ardından JSON'u yapıştırmak için bir iletişim kutusu göreceksiniz.

2018'de bir dersin package com.my.package_namebaşına eklemek zorunda kaldım .


4

Her şeyden önce.

JSON'dan POJO sınıflarına (kotlin veri sınıfı) JSON eşlemesi için Android Studio'da JSON'dan Kotlin Data sınıfına dönüştürücü eklentisini kullanabilirsiniz. Bu eklenti, Kotlin veri sınıfınızı JSON'a göre açıklayacaktır.

Daha sonra JSON'u Kotlin'e dönüştürmek için GSON dönüştürücüyü kullanabilirsiniz.

Bu Tam öğreticiyi izleyin: Kotlin Android JSON Ayrıştırma Eğitimi

Json'u manuel olarak ayrıştırmak istiyorsanız.

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

JSON Dizisinin ve 0 dizinindeki nesnesinin üzerinde Ayrıştırılacak Kod.

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

1

http://www.jsonschema2pojo.org/ Merhaba, json'u pojo'ya dönüştürmek için bu web sitesini kullanabilirsiniz.
Kontrol + Alt + shift + k

Bundan sonra bu model sınıfını manuel olarak kotlin model sınıfına dönüştürebilirsiniz. yukarıdaki kısayol yardımıyla.


1
Java'ya dönüşecek.
CoolMind

0

Biraz geç ama her neyse.

Kotlin semantiğini kullanan yapılar gibi JSON'u JavaScript'e ayrıştırmayı tercih ediyorsanız , yazarı benim de olduğum JSONKraken'ı öneririm .

Konuyla ilgili öneri ve görüşler çok takdir edilmektedir!


-4

Deme kaynağını buradan indirin ( android kotlin'de Json ayrıştırma )

Bu bağımlılığı ekleyin:

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

API işlevini çağırın:

 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()

        }

    })
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.