如何在Kotlin中解析JSON?


121

我从服务中收到一个很深的JSON对象字符串,必须将其解析为JSON对象,然后将其映射到类。

如何在Kotlin中将JSON字符串转换为对象?

在映射到各个类之后,我使用了Jackson的StdDeserializer。当对象具有必须反序列化为类的属性时,就会出现问题。我无法在另一个反序列化器中获取对象映射器,至少我不知道该怎么做。

在此先感谢您的帮助。最好是在本地,我试图减少所需的依赖项数量,因此,如果答案仅用于JSON操作并进行解析就足够了。


2
我还没有用Java开发过。这不是我得到的错误。我只是不知道如何在Kotlin内进行有效的解析。所有搜索总是导致一个框架。Java具有org.json.simple。Kotlin不信任IDE的自动完成功能。
AJ_1310 2015年

org.json.simple包不是Java固有的。我猜是这个库:github.com/fangyidong/json-simple。如果需要,也可以将其与Kotlin一起使用(尽管Jason Bourne建议的klaxon库对于Kotlin可能是更好的选择)。
marstran

Answers:


72

您可以使用此库 https://github.com/cbeust/klaxon

Klaxon是一个轻量级的库,用于解析Kotlin中的JSON。


85
在这里作者,如果您有任何疑问/建议,请随时给我发送电子邮件。
Cedric Beust

我必须导入哪些Java库才能获取正确的解析器?我尝试了org.json。*,但是我的Gradle设置中一定缺少一些东西。我认为Klaxon文档假设太多(就像用户知道Java库一样)。
Makis

@CedricBeust您是否尝试过使用sqlite处理类对象?有什么推荐的做法吗?
Raju yourPepe

104

毫无疑问,在Kotlin中进行解析的未来将是kotlinx.serialization。它是Kotlin库的一部分。目前仍处于孵化器编写阶段。

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
我的问题是,您几乎无法将其与泛型一起使用。至少我还没有弄清楚该怎么做。而且我当然不想使用反射。
natronite

3
KotlinX序列化仍处于试验阶段,因此它们在新版本中引入了重大更改。此外,它也不是线程安全的,因此,如果多个线程尝试使用的单个实例Json(很常见),您的JSON可能会损坏。此外,还有一些带有错误标签的未解决的Github问题。因此,我要说的是,在生产中使用它仍然存在风险(除非您愿意花时间解决潜在的问题并且不打算经常进行更新)。这个项目确实很有趣,特别是对于Kotlin Multiplatform项目,但是它还不稳定。
Javad Sadeqzadeh

似乎已经发生了重大变化,JSON现在称为Json
xjcl,

这也需要附加的依赖关系,因此请遵循指南的链接
xjcl

34

没有外部库(在Android上)

要解析此:

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

使用这些类:

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

用法:

val foos = Response(jsonString)

2
因此,如果这不需要任何外部库,那应该意味着org.json.JSONObject是标准库的一部分吗?
still_dreaming_1

@ still_dreaming_1是的,它是“已添加到API级别1”,请参见。developer.android.com/reference/org/json/JSONObject.html
Frouo

我猜这是Android的东西吗?我在JVM的Kotlin或Java标准库中寻找它。
still_dreaming_1

哦,是的,绝对对不起,我忘了在答案中提到这一点!JsonObject如果您的JVM在Java7(docs.oracle.com/javaee/7/api/javax/json/JsonObject.html)下运行,也许可以使用?
Frouo

哦,我以前没有找到那个,谢谢!还有其他一些相关的类,例如JsonReader。看来它们是Java EE的一部分,但不是Java SE。我将研究是否可能切换到Java EE。
still_dreaming_1 '19

25

您可以使用Gson

第1步

添加编译

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

第2步

将json转换为Kotlin Bean(使用JsonToKotlinClass

像这样

Json 数据

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

第三步

Gson

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

这给了我java.lang.IllegalStateException:应该是一个字符串,但在行1列700路径处为BEGIN_OBJECT
Srishti Roy

您应该先检查返回数据。@ SrishtiRoy
KeLiuyue

它起作用了,但是如果我的json响应就像“类别”:[“推荐”],那么呢?
斯里什蒂·罗伊

@SrishtiRoy响应是非法的JSON数据。合法JSON数据始于{[
KeLiuyue

1
Gson的问题在于它忽略了可为空性。一个val属性可以很容易地null,如果是从JSON失踪。另外,根本不使用默认值。
user3738870

21

不知道这是否是您需要的,但是这就是我的方法。

使用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
    }

这是json的示例:

{“食物”:[{“食物名称”:“苹果”,“重量”:“ 110”}]}


8
有什么依赖性?
路易斯·苏亚雷斯

我使用了org.json。这是链接: mvnrepository.com/artifact/org.json/json/20180813
markB

此方法要求该类必须具有不带任何参数的默认构造函数。如果数据类有构造PARAMS象下面这样: data class SomeClass(val param1: Int, val param2: Int)
leimenghao

@leimenghao您可以在一行中完成此操作:val类别= SomeClass(param1 = foodJson.getJSONObject(i).getString(“ FoodName”),param2 = foodJson.getJSONObject(i).getInt(“ Weight”))
markB

真的很好。只是说,您可以使用for (i in 0 until foodJson!!.length()) {代替for (i in 0..foodJson!!.length() - 1) {。它的作用相同,而且更加直观
Arnyminer Z

12

我个人使用了Kotlin的Jackson模块,可以在这里找到:jackson-module-kotlin

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

例如,以下是解析流放之路技能树的JSON的代码,该代码非常繁重(格式化时为84k行):

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(未格式化):http//filebin.ca/3B3reNQf3KXJ/rawSkilltree.json

根据您的描述,我相信它可以满足您的需求。


1
与Klaxon不同(我尝试时有一个错误),Jackson实际起作用:)
redsk 18/12/11

此外,您可以使用intellij中的JSON to Kotlin数据类插件为您生成数据类。
Brooks DuBois

7

要将JSON转换为Kotlin,请使用http://www.json2kotlin.com/

您也可以使用Android Studio插件。文件>设置,Plugins在左树中选择,按“浏览存储库...”,搜索“ JsonToKotlinClass ”,选择它,然后单击绿色按钮“安装”。

插入

AS重新启动后,即可使用它。您可以使用创建类File > New > JSON To Kotlin Class (JsonToKotlinClass)。另一种方法是按Alt +K。

在此处输入图片说明

然后,您将看到一个粘贴JSON的对话框。

在2018年,我不得不package com.my.package_name在课程开始时添加。


4

首先。

您可以在Android Studio中使用JSON到Kotlin数据类转换器插件,以将JSON映射到POJO类(kotlin数据类)。该插件将根据JSON注释您的Kotlin数据类。

然后,您可以使用GSON转换器将JSON转换为Kotlin。

请遵循以下完整教程: Kotlin Android JSON解析教程

如果要手动解析json。

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 Array及其对象上方的索引0处解析的代码。

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



-4

从这里下载deme的源代码(android kotlin中的Json解析

添加此依赖项:

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

调用api函数:

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

        }

    })
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.