Kotlinx Serialization缺少字段异常。

51

我正在使用Ktor将Moshi转换为kotlinx serialization,但是当我尝试请求获取数据时出现此错误:

kotlinx.serialization.MissingFieldException: Field 'attachments' is required, but it was missing

这很有道理,因为特定的响应并不包含此字段。

响应Json

{
    "data": {
        "id": "1299418846990921728",
        "text": "This is a test"
    }
}

但是我的序列化类将attachments字段设置为可空(仅在需要时才在响应中存在),所以我认为它应该像Moshi那样忽略它。


@Serializable
data class ResponseData(
    val id: Long
    val attachments: Attachments?,
    val author_id: String?,
    val text: String
}
在我的Ktor客户端设置中,我将其设置为忽略未知的键。
private val _client: HttpClient = HttpClient(engine) {
    install(JsonFeature) {
        val json = Json {
            this.isLenient = true
            this.ignoreUnknownKeys = true
        }
        serializer = KotlinxSerializer(json)
    }
}

即使该字段可为空,为什么仍然显示该字段是必填的?

3个回答

98

我明白了,即使你将某个东西标记为可为空(nullable),它仍然被认为是必需的。

要使其真正成为可选项,需要给它一个默认值,例如,有空值的数据类应该像这样:

@Serializable
data class ResponseData(
    val id: Long
    val attachments: Attachments? = null,
    val author_id: String? = null,
    val text: String
}

一旦您设置了值,该字段将变为可选字段,并且不会抛出异常。


6
我仍在收到这个错误,我尝试了所有的建议,但还是无法解决。 - Sakiboy
3
@Sakiboy 请检查你的 explicitNulls 变量是否设置为 false 而不是 true。这应该解决在解码时 json 中不存在可空属性的问题。 - oblakr24
@oblakr24,这就是我最终需要在设置 - 初始化中做的事情。 - Sakiboy
它按照说明正常运行,无需进一步更改。我的情况恰好与问题所述的一样。谢谢! - nrod
对于kTor 1.6版本,这个解决方案有效;但对于2.0版本,这个解决方案无效。 - manivanna perumal

36

从v1.3.0开始,你可以使用 explicitNulls = false 来配置Json功能将缺失的字段视为null。

install(JsonFeature) {
    serializer = KotlinxSerializer(
        json = kotlinx.serialization.json.Json {
            explicitNulls = false
        }
    )
}
explicitNulls 的文档: 指定是否应编码可空属性的 null 值,并且在解码期间必须存在于 JSON 对象中。 当禁用此标志时,没有默认值的 null 值属性不会被编码;在解码期间,字段值的缺失被视为可空属性的 null 值,而没有默认值。 默认情况下为 true。

1
哦,好的,谢谢提醒! - tyczj
更多的解释和示例请参考 https://github.com/Kotlin/kotlinx.serialization/blob/v1.3.0-RC/docs/json.md#explicit-nulls。 - solamour
太好了!它有效果。 - undefined

-2

我在使用Spring的RestController时遇到了同样的异常,当数据缺失时,我需要发送BAD_REQUEST响应。我可以通过以下代码实现。

@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = [SerializationException::class])
open fun handleRequestError(ex: SerializationException) = //
        log.warn("Unable to process incomplete request", ex)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接