如何在 Retrofit2 中处理空 JSON?

问题描述 投票:0回答:1

我的 API 返回 null 或帖子列表。帖子的数据类如下所示

@Serializable
data class Post(
    val id: Int,
    val text: String,
    @SerialName("img_url") val imgURL: String,
    var author: User
)

@Serializable
data class User(
    val id: Int,
    @SerialName("profile_img") val profileImgUrl: String,
    @SerialName("user_name") val userName: String
)

我还有一个如下的API接口

interface PosterApiInterface {
    @GET("posts")
    suspend fun getPosts(
        @Query("start") lastPostId: Int,
        @Query("limit") posts: Int,
        @Query("username") username: String? = null
    ): List<Post>?
    // There's also code that relates to security components and other functionality,
    // but I've decided to hide it
}

但我看到仅仅使

List<Post>
可为空是不够的,因为转换器工厂仍然返回此错误:

io.github.xn32.json5k.UnexpectedValueError: array expected at position 1:1

每次服务器发送空值。这是我的改造:

private val baseUrl = "https://127.0.0.1:3001/" // Poster API

    private val json = Json5 { prettyPrint = true; }

    @OptIn(ExperimentalSerializationApi::class)
    private val retrofit = Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
        .build()
android json kotlin retrofit2
1个回答
0
投票

您遇到的问题与Retrofit中的JSON反序列化过程有关。当服务器返回 null 时,JSON 响应不是一个有效的 JSON 数组,而是一个 JSON 空值。尝试将响应反序列化为帖子列表时,这会导致 UnexpectedValueError。

要解决此问题,您可以为您的 Post 类创建一个自定义 JSON 反序列化器,以正确处理空值。这是一个例子:

object PostJsonDeserializer : JsonDeserializer<List<Post>?> {
override fun deserialize(
    json: JsonElement?,
    typeOfT: Type?,
    context: JsonDeserializationContext?
): List<Post>? {
    if (json == null || json.isJsonNull) {
        return null
    }
    return context?.deserialize<List<Post>>(json, typeOfT)
}

}

这个反序列化器检查 JSON 元素是否为 null,如果是则返回 null。如果该元素不为 null,它将反序列化委托给 JsonDeserializationContext 提供的默认反序列化器。

要在 Retrofit 中使用这个反序列化器,您需要在您的 JSON 转换器工厂注册它:

private val json = Json5 {
prettyPrint = true
serializersModule = SerializersModule {
    contextual(Post::class, PostJsonSerializer)
}
deserializersModule = DeserializersModule {
    contextual(List::class, PostJsonDeserializer)
}

}

private val retrofit = Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) .build()

在这里,我们将 PostJsonDeserializer 注册到我们的 JSON 配置的 DeserializersModule 中。这将确保 Retrofit 在响应中遇到空 JSON 值时使用我们的自定义反序列化器。

使用此设置,您的 getPosts 方法现在应该在服务器发送空响应时返回 null,并在响应为非空时返回帖子列表。

© www.soinside.com 2019 - 2024. All rights reserved.