Gson -使用包含空值的字段解析jsonString(在Kotlin中)

dsekswqp  于 2022-11-06  发布在  Kotlin
关注(0)|答案(2)|浏览(196)

TL;DR

对于一个包含...,field=,...的json字符串,Gson不断抛出JsonSyntaxException,我该怎么办?
案例
我必须与第三个API进行通信,它往往会提供如下数据:

{
  "fieldA": "stringData",
  "fieldB": "",
  "fieldC": ""
}

然而,在我的应用程序项目中,它变成这样:

val jsonString = "{fieldA=stringData,fieldB=,fieldC=}"

问题
我尝试使用标准方法将其反序列化:

val jsonString = "{fieldA=stringData,fieldB=,fieldC=}"
val parseJson = Gson().fromJson(jsonString, JsonObject::class.java)
assertEquals(3, parseJson.size())

但它会导致Exception:

com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Unexpected value at line 1 column 28 path $.fieldB

不起作用的解决方案

我试过这么多的解决方案,没有一个有效。包括:

  • 设置自定义数据类并将值设置为可空
data class DataExample(
    val fieldA: String?,
    val fieldB: String?,
    val fieldC: String?,
)
val parseToObject = Gson().fromJson(jsonString, DataExample::class.java)
data class DataExample(
    val fieldA: JsonElement,
    val fieldB: JsonElement,
    val fieldC: JsonElement,
)
val parseToObject = Gson().fromJson(jsonString, DataExample::class.java)

第一个
using it in GsonBuilder

val gson = GsonBuilder()
    .registerTypeAdapter(DataExample::class.java, EmptyToNullDeserializer<String>())
    .create()
val parseToObject = gson.fromJson(jsonString, DataExample::class.java)

我还能做什么呢?

kkih6yb8

kkih6yb81#

不是有效的JSON,需要自己解析,可能这个字符串是用Map::toString()方法生成的,下面是解析成Map〈String,String〉的代码

val jsonString = "{fieldA=stringData,fieldB=,fieldC=}"

val userFieldsMap = jsonString.removeSurrounding("{", "}").split(",") // split by ","
    .mapNotNull { fieldString ->
        val keyVal = fieldString.split("=")
        // check if array contains exactly 2 items
        if (keyVal.size == 2) {
            keyVal[0].trim() to keyVal[1].trim()  // return@mapNotNull
        } else {
            null // return@mapNotNull
        }
    }
    .toMap()
py49o6xq

py49o6xq2#

事实证明,正如@frc129和其他许多人所说的那样,它不是一个有效的JSON。
然而事实是,Gson处理的情况比JSON应该处理的要多,如下面的数据:

val jsonString = "{fieldA=stringData,fieldB=s2,fieldC=s3}"
val parseJson = Gson().fromJson(jsonString, JsonObject::class.java)
// This will NOT throw exception, even the jsonString here is not actually a JSON string.
assertEquals(3, parseJson.size())
assertEquals("stringData", parseJson["fieldA"].asString)
assertEquals("s2", parseJson["fieldB"].asString)
assertEquals("s3", parseJson["fieldC"].asString)

进一步的研究表明--这里和问题中提到的字符串--更像是Map to字符串。
我对GSON处理Map有一点误解。这应该被当作一个额外的方便的支持,而不是一个法律的的程序。简而言之,它不应该被转换,数据格式应该被固定。我将去工作与服务器和基地转换。
如果将来有人想快速修复字符串,你可以看一下@frc129 answer;但是,理想的解决方案是修复数据提供程序,以提供“正确的JSON格式”:

val jsonString = "{\"fieldA\":\"stringData\",\"fieldB\":\"\",\"fieldC\":\"\"}"
val parseJson = Gson().fromJson(jsonString, JsonObject::class.java)
assertEquals(3, parseJson.size())
assertEquals("stringData", parseJson["fieldA"].asString)
assertEquals("", parseJson["fieldB"].asString)
assertEquals("", parseJson["fieldC"].asString)

相关问题