【问题标题】:Kotlinx.Serialization using OkHTTPClient return always FailureKotlinx.Serialization 使用 OkHTTPClient 总是返回失败
【发布时间】:2021-11-17 07:04:54
【问题描述】:

您好,我的 JSON 有问题。我正在使用 OkHTTPClient 从 web 获取 JSON - 使用 kotlinx.serialization 通过包含 this 的方法从 JSON 获取对象,并且方法的返回值应该是 Result :

private suspend inline fun <reified T> OkHttpClient.get(webUrl: HttpUrl): Result<T> =
    try {
        //Builder defined here ... but skipping this line of code
        val data = Json { ignoreUnknownKeys = true }.decodeFromString<T (result.body!!.string())
        Result.Success(data)
    } catch (e: Exception) {
        Result.Failure(e)
    }


 suspend fun getFact(): Result<Fact> =
        client.httpGet("myURL".toHttpUrl())

来自 myURL 的 JSON:

{"status":"success","data":[{"fact":"This is random information i need to get"}],"message":"Retrieved Fact"} 

我的序列化器和可序列化数据类:


@Serializable
data class Fact(
@Serializable(with = FactListSerializer::class)
val data: String) java.io.Serializable

object FactListSerializer : JsonTransformingSerializer<List<String>>(ListSerializer(String.serializer())) {
    override fun transformDeserialize(element: JsonElement): JsonElement {
        return if (element  is JsonArray) {
            JsonArray(listOf(element)).first()
        } else {
            element
        }
    }
}

说实话,我不确定自己在做什么,但是当我打印 val fact = api.getFact():

 Fact: Failure(error=kotlinx.serialization.json.internal.JsonDecodingException: Expected JsonPrimitive at 0, found {"fact":"This is random information i need to get"}

我需要返回的只是数组事实的第一个元素,因为 JSON 总是只获取数组内的 1 个事实。所以我不想从 Serializer/Json List 返回,而只想从 Fact 对象返回。 但是正如你所见,我总是得到 Result Failure,不知道为什么。我的目标是获得 Result Success 并从该 JSON 对象 Fact 获得(只有一个),但我不确定我是否正确(显然不是),即使它甚至可以从 JSONArray 返回一个对象(元素Fact 类型)。

所以我期望是这样的:

Fact: Success(value=Fact(fact=This is random information i need to get))

【问题讨论】:

    标签: json kotlin json-deserialization kotlinx.serialization


    【解决方案1】:

    我认为反序列化器的定义应该在 3 个级别上进行更改。如何使用JsonTransformingDeserializerin the docs的示例实际上描述了您需要的大部分内容。

    1. JsonArray(listOf(element)).first() 应该只是 element.first()。在这里,您正在构建一个 JsonArray,其中包含您的初始 JsonArray 作为唯一元素,然后采用第一个元素,因此您基本上会得到完全相同的元素。

    2. JsonTransformingSerializer 的类型参数T 应该是它所应用的属性的类型,所以你至少应该在代码中得到一个警告,因为你的被定义为在 List&lt;String&gt; 上工作但被应用了到String 属性。应该是JsonTransformingSerializer&lt;String&gt;(String.serializer())

    3. 您不仅需要解开data 数组,还需要提取该数组元素中fact 键的值。

    因此,有了所有这些更改,它应该给出如下内容:

    object FactListSerializer : JsonTransformingSerializer<String>(String.serializer()) {
        override fun transformDeserialize(element: JsonElement): JsonElement {
            val unwrappedData = if (element is JsonArray) element.first() else element
            return unwrappedData.jsonObject["fact"] ?: error("missing 'fact' key in 'data' array")
        }
    }
    

    【讨论】:

    • 按预期工作,非常感谢+感谢您解释出了什么问题/我需要做什么。
    猜你喜欢
    • 2018-05-22
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 2016-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多