使用改造对 JSON 数据建模的更有效方法 - Kotlin

Posted

技术标签:

【中文标题】使用改造对 JSON 数据建模的更有效方法 - Kotlin【英文标题】:More efficient way to model JSON data using retrofit - Kotlin 【发布时间】:2021-10-25 03:18:48 【问题描述】:

我要使用的数据有这样的结构:


    "1": 
        "id": 1,
        "name": "Bulbasaur"
    ,
    "2": 
        "id": 2,
        "name": "Ivysaur"
    ,
    "3": 
        "id": 3,
        "name": "Venusaur"
    

注意: 标记每个对象的数字与神奇宝贝的 id 匹配,而不是神奇宝贝的数量

我的问题是,当我尝试为此创建数据类时,它最终会为每个对象创建一个数据类。没有一个数据类适合每个对象。我相信这是由于标记对象(神奇宝贝)的数字对于每个对象都不同。

有没有一种方法可以将这些数据格式化为一个或两个数据类,而不是超过 800 个?

理想情况下,我希望数据具有这样的结构,但运行时不起作用。

data class ReleasedPokemonModel(
    val id: Int,
    val name: String
)

【问题讨论】:

如果我的评论能帮助你解决问题,希望你能接受我的回答。谢谢! 【参考方案1】:

当使用这种特殊情况将 Json 解析为 Object 时,您应该自己自定义 Json Deserializer。

这里我使用 Gson 库将 Json 解析为 Object。

首先,使用 Gson 创建一个自定义的 Json Deserializer。如下:

PokemonResponse.kt

data class PokemonResponse(
    val pokemonMap: List<StringReleasedPokemonModel>
)

data class ReleasedPokemonModel(
    val id: Int,
    val name: String
)

GsonHelper.kt

object GsonHelper 
    fun create(): Gson = GsonBuilder().apply 
        registerTypeAdapter(PokemonResponse::class.java, PokemonType())
        setLenient()
    .create()

    private class PokemonType : JsonDeserializer<PokemonResponse> 
        override fun deserialize(
            json: JsonElement?,
            typeOfT: Type?,
            context: JsonDeserializationContext?
        ): PokemonResponse 
            val list = mutableListOf<ReleasedPokemonModel>()
            // Get your all key
            val keys = json?.asJsonObject?.keySet()
            keys?.forEach  key ->
                // Get your item with key
                val item = Gson().fromJson<ReleasedPokemonModel>(
                    json.asJsonObject[key],
                    object : TypeToken<ReleasedPokemonModel>() .type
                )
                list.add(item)
            
            return PokemonResponse(list)
        
    

接下来我将创建一个GsonConverterFactory,以便我可以addConvertFactory 进行改造。

val gsonConverterFactory = GsonConverterFactory.create(GsonHelper.create())

现在我将添加改造。

val retrofit = Retrofit.Builder()
    // Custom your Retrofit
    .addConverterFactory(gsonConverterFactory) // Add GsonConverterFactoty
    .build()

最后在 ApiService 中,您的响应现在将返回类型 PokemonResponse

interface ApiService 
    @GET("your_link")
    suspend fun getGenres(): PokemonResponse

【讨论】:

【参考方案2】:

问题是那里没有 JSON 数组。它实际上是一个 JSON 对象,每个口袋妖怪都被列为一个属性。我建议您事先重新格式化 JSON,使其看起来像这样:

[
    
        "id": 1,
        "name": "Bulbasaur"
    ,
    
        "id": 2,
        "name": "Ivysaur"
    ,
    
        "id": 3,
        "name": "Venusaur"
    
]

然后你可以这样建模:

data class ReleasedPokemonModel(
    val id: Int,
    val name: String
)

data class Response(
    val items: List<ReleasedPokemonModel>
)

See more here.

And see here for discussion about reformatting the data before handing it to Retrofit.

【讨论】:

【参考方案3】:

您可以使用 Map 来存储密钥,如下所示

data class PokemonResponse(
    val pokemonMap:Map<String,ReleasedPokemonModel>
)

data class ReleasedPokemonModel(
    val id: Int,
    val name: String
)

【讨论】:

以上是关于使用改造对 JSON 数据建模的更有效方法 - Kotlin的主要内容,如果未能解决你的问题,请参考以下文章

排序和过滤核心数据关系的更有效方法是啥?

检索 Firebase 数据的更有效方法?

从 MySQL 获取数据的更有效方法

在 PLSQL 中比较日期时间的更有效方法?

处理用户输入数据验证的更有效方法?

记一次企业级爬虫系统升级改造:文本分析与数据建模规则化处理