【问题标题】:Using default JsonDeserializer inside custom JsonDeserializer in Kotlin在 Kotlin 的自定义 JsonDeserializer 中使用默认的 JsonDeserializer
【发布时间】:2020-05-15 13:21:08
【问题描述】:

我正在尝试为我从OMDb API 收到的响应构建自定义反序列化器。

这是Movie 的数据类:

data class Movie(
    val title: String?,
    val year: String?,
    val imdbID: String?,
    val type: String?,
    val poster: String?,
    val mpaRating: String?,
    val runtime: String?,
    val genres: String?,
    val director: String?,
    val writers: List<String>?,
    val actors: List<String>?,
    val plot: String?,
    val awards: String?,
    val boxOfficeEarnings: String?,
    val ratings: List<Rating>,
    val response: Boolean?
)

对于Rating

data class Rating(
    @SerializedName("Source")
    val source: String,
    @SerializedName("Value")
    val value: String
)

这是迄今为止的自定义JsonDeserializer

class MovieDeserializer : JsonDeserializer<Movie>
{
    override fun deserialize(
        json: JsonElement?,
        typeOfT: Type?,
        context: JsonDeserializationContext?
    ): Movie
    {
        val movieJsonObject = json?.asJsonObject
        return Movie(
            movieJsonObject?.get("Title")?.asString,
            movieJsonObject?.get("Year")?.asString,
            movieJsonObject?.get("imdbID")?.asString,
            movieJsonObject?.get("Type")?.asString,
            movieJsonObject?.get("Poster")?.asString,
            movieJsonObject?.get("Rated")?.asString,
            movieJsonObject?.get("Runtime")?.asString,
            movieJsonObject?.get("Genre")?.asString,
            movieJsonObject?.get("Director")?.asString,
            separateStringByComma(movieJsonObject?.get("Writer")?.asString),
            separateStringByComma(movieJsonObject?.get("Actors")?.asString),
            movieJsonObject?.get("Plot")?.asString,
            movieJsonObject?.get("Awards")?.asString,
            movieJsonObject?.get("BoxOffice")?.asString,
            // this is where I need help,
            movieJsonObject?.get("Response")?.asBoolean
        )
    }

    fun separateStringByComma(stringToSeparate: String?): List<String>?
    {
        return stringToSeparate?.split(", ")
    }
}

如何在不进行一些 json 字符串操作的情况下将该 JsonElement 直接转换为 List&lt;Rating&gt;

顺便说一句,我正在使用 Retrofit 和 Gson:

val gsonMovieDeserializer = GsonBuilder()
            .registerTypeAdapter(Movie::class.java, MovieDeserializer())
            .create()
        val retrofit = Retrofit.Builder()
            .baseUrl("https://www.omdbapi.com/")
            .addConverterFactory(GsonConverterFactory.create(gsonMovieDeserializer))
            .build()
        val omdbApi = retrofit.create(OmdbApi::class.java)
        val movie = omdbApi.getMovie(movieImdbId.value.toString())

【问题讨论】:

    标签: android json kotlin gson retrofit2


    【解决方案1】:

    首先,我想指出 nullables 的用法:不要检查 movieJsonObject 是否为 deserialize() 内的每个调用是否为空,而是应该将函数参数更改为不为空,然后只检查一次,就在开始时,如果jsonJsonObject,如果不是,则跳过所有内容。这样,我们就有了提取数据的坚实基础。此外,对于 Movie 数据类,检查 API 文档中哪些字段是可选的,并且只将它们设置为 nulalble(我很确定至少标题和 ID 总是存在的,所以拥有它们会更有用不可为空)。

    现在,对于问题本身,您应该能够使用 context.deserialize&lt;List&lt;Rating&gt;&gt;(movieJsonObject.get("Ratings"), List::class.java) 反序列化该列表,在 Kotlin 中,该列表将返回一个类型安全的 List&lt;Rating&gt;(但再次确保这不是可选字段在 API 中,如果是,则使其可为空)。

    【讨论】:

    • 这似乎可行,谢谢!另外,也感谢可以为空的建议。现在,如果我需要使用另一个自定义解串器而不是这个默认解串器怎么办?我只是使用RatingDeserializer().deserialize(movieJsonObject.get("Ratings"), List::class.java, context)
    • 这可能是一种方法,但是您可以简单地为适当的类型创建一个扩展JsonDeserializer 的新类,并将其注册到GsonBuilder 中,Gson 将为您完成一切。我不建议实例化一个反序列化器,因为这是由 Gson 自己完成的,它会在每次需要时重用它。此外,如果你真的需要完全手动模式,那么只需在 MovieDeserializer 本身内部创建一个函数,并在需要时从 deserialize() 调用它,因为它可能更简洁,也是重用代码的好方法。跨度>
    猜你喜欢
    • 2020-09-08
    • 1970-01-01
    • 2019-12-18
    • 1970-01-01
    • 2021-05-13
    • 1970-01-01
    • 2011-10-29
    • 2018-02-08
    • 1970-01-01
    相关资源
    最近更新 更多