【问题标题】:How to parse JSON in Kotlin?如何在 Kotlin 中解析 JSON?
【发布时间】:2017-06-15 04:35:03
【问题描述】:

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

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

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

最好,在本地,我试图减少我需要的依赖项的数量,所以如果答案只是用于 JSON 操作和解析就足够了。

【问题讨论】:

  • 我没有用 Java 开发过。这不是我得到的错误。我只是不知道如何在 Kotlin 本地进行有效的解析。所有的搜索总是指向一个框架。 Java 有一个 org.json.simple。 Kotlin 不信任 IDE 的自动完成功能。
  • org.json.simple 包不是 Java 原生的。我猜是这个库:github.com/fangyidong/json-simple。如果您愿意,您也可以将它与 Kotlin 一起使用(尽管 Jason Bourne 建议的 klaxon 库可能是 Kotlin 的更好选择)。
  • 看看github.com/square/moshi。在medium.com/square-corner-blog/… 有一篇关于它的博客文章

标签: java json kotlin


【解决方案1】:

毫无疑问,Kotlin 解析的未来将是 kotlinx.serialization。它是 Kotlin 库的一部分。 kotlinx.serialization 1.0 版本终于发布了

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

【讨论】:

  • 我遇到的问题是你很难将它与泛型一起使用。至少我还没有弄清楚该怎么做。而且我当然不想使用反射。
  • KotlinX 序列化仍处于实验阶段,因此它们在新版本中引入了重大更改。此外,它不是线程安全的,因此如果多个线程尝试使用 Json 的单个实例(这很常见),您的 JSON 可能会损坏。此外,错误标签还有几个开放的 Github 问题。因此,我想说,在生产中使用它仍然存在风险(除非您愿意花时间解决潜在问题并且不打算经常更新它)。该项目确实很有趣,尤其是对于 Kotlin 多平台项目而言,但它还不稳定。
  • 似乎已经有了突破性的变化,JSON 现在被称为 Json
  • 1.0 终于出来了!这里同样的例子:Https://blog.jetbrains.com/kotlin/2020/10/…
  • kotlinlang.org/docs/releases.html 多次显示此插件。这似乎是在 Kotlin 中使用 json 的最佳方式。
【解决方案2】:

你可以使用这个库https://github.com/cbeust/klaxon

Klaxon 是一个在 Kotlin 中解析 JSON 的轻量级库。

【讨论】:

  • 作者在这里,如果您有任何问题/建议,请随时给我发电子邮件。
  • 在与其他库折腾两天后,我今天尝试了这个,效果非常好。多态支持和文档看起来也不错,在集合之后,这是我经常测试的第二件事。很棒的包@Cedric!
  • 为什么在内置支持可用时使用库?
  • 如果您正在考虑做多平台或想要最佳性能。你应该在下面使用 Kotlinx 序列化。
【解决方案3】:

没有外部库(在 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)

【讨论】:

  • 所以如果这不需要任何外部库,那应该意味着 org.json.JSONObject 是标准库的一部分吧?
  • @still_dreaming_1 是的,“在 API 级别 1 中添加”,参见。 developer.android.com/reference/org/json/JSONObject.html
  • 我猜这是Android的东西?我在 JVM 的 Kotlin 或 Java 标准库中寻找它。
  • 哦,是的,很抱歉,我忘了在答案中提到这一点!如果您的 JVM 在 Java7 (docs.oracle.com/javaee/7/api/javax/json/JsonObject.html) 下运行,也许您可​​以使用 JsonObject
  • 它必须有性能问题,因为您为每个键重新解析了 JSONObject。
【解决方案4】:

你可以使用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
    )
}

第 3 步

使用Gson

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

【讨论】:

  • 该插件目前不适用于嵌套的 JSON 对象。
  • Gson 的问题在于它忽略了可空性。如果 JSON 中缺少 val 属性,则它很容易成为 null。此外,根本不使用默认值。
  • @user3738870 你找到更好的选择了吗?我对我尝试的每个解析器的这种行为感到沮丧
  • @anshsachdeva 是的,有多个,我发现 moshi 是最快和最容易使用的。 github.com/square/moshi
【解决方案5】:

不确定这是否是您需要的,但我就是这样做的。

使用导入 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”}]}

【讨论】:

  • 依赖是什么?
  • 我使用了 org.json。这是链接:mvnrepository.com/artifact/org.json/json/20180813
  • 该方法要求类必须有默认构造函数,不带任何参数。如果数据类在构造函数中有如下参数怎么办:data class SomeClass(val param1: Int, val param2: Int).
  • @leimenghao 您可以在一行中执行此操作: val categories = SomeClass(param1 = foodJson.getJSONObject(i).getString("FoodName"),param2 = foodJson.getJSONObject(i).getInt( “重量”))
  • 效果很好。只是说,您可以使用for (i in 0 until foodJson!!.length()) { 而不是for (i in 0..foodJson!!.length() - 1) {。它的作用相同,而且更直观
【解决方案6】:

我个人使用用于 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

根据您的描述,我相信它符合您的需求。

【讨论】:

  • 与 Klaxon 不同(我尝试时它有一个错误),Jackson 确实有效 :)
  • 另外,您可以使用 intellij 中的 JSON to Kotlin 数据类插件为您生成数据类。
【解决方案7】:

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

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

AS重启后就可以使用了。您可以使用File &gt; New &gt; JSON To Kotlin Class (JsonToKotlinClass) 创建一个类。另一种方法是按 Alt + K。

然后你会看到一个粘贴 JSON 的对话框。

2018 年我不得不在课程的开头添加package com.my.package_name

【讨论】:

    【解决方案8】:

    首先。

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

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

    按照此完整教程进行操作: Kotlin Android JSON Parsing Tutorial

    如果你想手动解析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 数组及其索引为 0 的对象的代码。

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

    【讨论】:

      【解决方案9】:

      GSON 是 Android 和 Web 平台在 Kotlin 项目中解析 JSON 的不错选择。这个库是由谷歌开发的。 https://github.com/google/gson

      1.首先将 GSON 添加到您的项目中:

      dependencies {
         implementation 'com.google.code.gson:gson:2.8.6'
      }
      

      2。现在您需要将 JSON 转换为 Kotlin Data 类:

      复制您的 JSON 并转到此 (https://json2kt.com) 网站并将您的 JSON 粘贴到 Input Json 框中。在适当的框中写入包(例如:com.example.appName)和类名(例如:UserData)。该站点将在下面显示您的数据类的实时预览,您也可以一次下载所有类的 zip 文件。

      下载所有类后,解压缩 zip 文件并将它们放入您的项目中。

      3.现在解析如下:

      val myJson = """
      {
          "user_name": "john123",
          "email": "john@example.com",
          "name": "John Doe"
      }
      """.trimIndent()
      
      val gson = Gson()
      var mUser = gson.fromJson(myJson, UserData::class.java)
      println(mUser.userName)
      

      完成:)

      【讨论】:

        【解决方案10】:

        这使用 kotlinx.serialization,如 Elisha's answer。同时,该项目已超过 1.0 版,因此 API 已更改。请注意,例如JSON.parse 已重命名为 Json.decodeFromString。它也是从 Kotlin 1.4.0 开始以 gradle differently 导入的:

        dependencies {
            implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.0"
        }
        apply plugin: 'kotlinx-serialization'
        

        示例用法:

        import kotlinx.serialization.Serializable
        import kotlinx.serialization.json.Json
        import kotlinx.serialization.decodeFromString
        import kotlinx.serialization.encodeToString
        
        @Serializable
        data class Point(val x: Int, val y: Int)
        
        val pt = Json.decodeFromString<Point>("""{"y": 1, "x": 2}""")
        val str = Json.encodeToString(pt)  // type can be inferred!
        
        val ilist = Json.decodeFromString<List<Int>>("[-1, -2]")
        val ptlist = Json.decodeFromString<List<Point>>(
            """[{"x": 3, "y": 4}, {"x": 5, "y": 6}]"""
        )
        

        您可以对可空字段和可选字段使用可空类型 (T?):

        @Serializable
        data class Point2(val x: Int, val y: Int? = null)
        
        val nlist = Json.decodeFromString<List<Point2>>(
            """[{"x": 7}, {"x": 8, "y": null}, {"x": 9, "y": 0}]"""
        )
        

        Kotlin 的data class 是一个主要保存数据并自动定义了成员、.toString() 和其他方法(例如解构声明)的类。

        【讨论】:

          【解决方案11】:

          有点晚了,不过没关系。

          如果您更喜欢将 JSON 解析为使用 Kotlin 语法的类似 JavaScript 的结构,我推荐 JSONKraken,我是其中的作者。

          非常感谢您对此事的建议和意见!

          【讨论】:

            【解决方案12】:

            Kotin 序列化

            Jetbrains 的 Kotlin 特定库适用于所有支持的平台 - Android、JVM、JavaScript、Native

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

            莫希

            Moshi 是 Square 为 Android 和 Java 开发的 JSON 库。

            https://github.com/square/moshi

            杰克逊

            https://github.com/FasterXML/jackson

            格森

            最受欢迎但几乎已弃用

            https://github.com/google/gson

            JSON 到 Java

            http://www.jsonschema2pojo.org/

            JSON 到 Kotlin

            IntelliJ 插件 - https://plugins.jetbrains.com/plugin/9960-json-to-kotlin-class-jsontokotlinclass-

            【讨论】:

              【解决方案13】:

              http://www.jsonschema2pojo.org/ 您好,您可以使用本网站将 json 转换为 pojo。
              控制+Alt+shift+k

              之后,您可以手动将该模型类转换为 kotlin 模型类。借助上述快捷方式。

              【讨论】:

              • 它将转换为 Java。
              【解决方案14】:

              我在 kotlin 中使用我的自定义实现:

              /**
               * Created by Anton Kogan on 10/9/2020
               */
              object JsonParser {
              
                  val TAG = "JsonParser"
                  /**
               * parse json object
               * @param objJson
               * @param include - all  keys, that you want to display
               * @return  Map<String, String>
               * @throws JSONException
               */
                  @Throws(JSONException::class)
                  fun parseJson(objJson: Any?, map :HashMap<String, String>, include : Array<String>?): Map<String, String> {
                      // If obj is a json array
                      if (objJson is JSONArray) {
                          for (i in 0 until objJson.length()) {
                              parseJson(objJson[i], map, include)
                          }
                      } else if (objJson is JSONObject) {
                          val it: Iterator<*> = objJson.keys()
                          while (it.hasNext()) {
                              val key = it.next().toString()
                              // If you get an array
                              when (val jobject = objJson[key]) {
                                  is JSONArray -> {
                                      Log.e(TAG, " JSONArray: $jobject")
                                      parseJson(
                                          jobject, map, include
                                      )
                                  }
                                  is JSONObject -> {
                                      Log.e(TAG, " JSONObject: $jobject")
                                      parseJson(
                                          jobject, map, include
                                      )
                                  }
                                  else -> {
              //
                                      if(include == null || include.contains(key)) // here is check for include param
                                      {
                                          map[key] = jobject.toString()
                                          Log.e(TAG, " adding to map: $key $jobject")
                                      }
                                  }
                              }
                          }
                      }
                      return map
                  }
              
                  /**
                   * parse json object
                   * @param objJson
                   * @param include - all  keys, that you want to display
                   * @return  Map<String, String>
                   * @throws JSONException
                   */
                  @Throws(JSONException::class)
                  fun parseJson(objJson: Any?, map :HashMap<String, String>): Map<String, String> {
                      return parseJson(objJson, map, null)
                  }
              }
              

              你可以像这样使用它:

                  val include= arrayOf(
                      "atHome",//JSONArray
                      "cat",
                      "dog",
                      "persons",//JSONArray
                      "man",
                      "woman"
                  )
                  JsonParser.parseJson(jsonObject, map, include)
                  val linearContent: LinearLayout = taskInfoFragmentBinding.infoContainer
              

              这里有一些有用的链接:

              json解析:

              插件: https://plugins.jetbrains.com/plugin/9960-json-to-kotlin-class-jsontokotlinclass-

              从 json 创建 POJO: https://codebeautify.org/jsonviewer

              改造: https://square.github.io/retrofit/

              格森: https://github.com/google/gson

              【讨论】:

                【解决方案15】:

                从这里下载deme的源码(Json parsing in android kotlin)

                添加这个依赖:

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

                【讨论】:

                  猜你喜欢
                  • 2018-07-23
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-11-08
                  • 2022-01-03
                  • 2021-10-08
                  • 1970-01-01
                  相关资源
                  最近更新 更多