【问题标题】:Serialized Data Class combined with built-in modifications序列化数据类与内置修改相结合
【发布时间】:2019-05-20 07:20:52
【问题描述】:

我正在更新对使用序列化数据类解析 JSON 响应的 API 响应的解析。序列化现在工作得很好,但是我试图解析成数据类的新数据并不完全依赖于 json 中的数据。这就是我的意思:

数据类是Career,我需要解析的新数据是一组skills,每个都有一个rating。 json数据很简单,包含的技能如下:

{
    // other career data

    ... 

    "mathematics_skill": 8,
    "critical_thinking_skill": 6

    ... // the remaining skills
}

使用直接序列化,我只能这样存储数据:

data class Career(
    // Other career data
    @serializableName("mathematic_skill") val mathSkill: Int,
    @serializableName("critical_thinking_skill") val mathSkill: Int,
    // remaining skills
)

但是,我想将所有技能存储在自定义技能类的数组变量中,该变量不仅包含评级,还包含技能名称和颜色。基本上,当我访问职业的技能数据时,我想像这样访问它:

val careerMathSkill = career.skills[0]
val mathRating = careerMathSkill.rating
val mathColor = careerMathSkill.color

是否可以使用数据类中的序列化数据将非序列化数据添加到同一个数据类中? (抱歉措辞奇怪,不知道怎么解释)

编辑:这是我所拥有的:

class CareersRemote(
    @SerializedName("careers") val careers: List<Career>
) {

    companion object {
        fun parseResponse(response: Response<CareersRemote>): CareersResponse {
        return if (response.isSuccessful) {
            response.body()!!.format()
        } else
           CareersResponse(listOf(CareersResponse.ErrorType.Generic()))
        }
    }

    fun format(): CareersResponse {

        val careers = topCareers.map {
            Career(
                id = it.id,
                title = it.title,
            )
        }.toMutableList()

        return CareersResponse(CareersResponse.SuccessData(careers = careers))
    }

    data class Career(
        @SerializedName("id") val id: String,
        @SerializedName("title") val title: String,
    )
}

这是我希望以某种方式做的事情

class CareersRemote(
    @SerializedName("careers") val careers: List<Career>
) {

    companion object {
        fun parseResponse(response: Response<CareersRemote>): CareersResponse {
        return if (response.isSuccessful) {
            response.body()!!.format()
        } else
           CareersResponse(listOf(CareersResponse.ErrorType.Generic()))
        }
    }

    fun format(): CareersResponse {

        val careers = topCareers.map {
            Career(
                id = it.id,
                title = it.title,
            )
        }.toMutableList()

        return CareersResponse(CareersResponse.SuccessData(careers = careers))
    }

    data class Career(
        @SerializedName("id") val id: String,
        @SerializedName("title") val title: String,

        // skills array that will need to be filled out based on the data I got in the json
        var skills: List<Skill>

    )
}

编辑:建议的解决方案

class CareersRemote(
    @SerializedName("careers") val careers: List<Career>
) {

    companion object {
        fun parseResponse(response: Response<CareersRemote>): CareersResponse {
        return if (response.isSuccessful) {
            response.body()!!.format()
        } else
           CareersResponse(listOf(CareersResponse.ErrorType.Generic()))
        }
    }

    fun format(): CareersResponse {

        val careers = topCareers.map {
            Career(
                id = it.id,
                title = it.title,
            )
        }.toMutableList()

        return CareersResponse(CareersResponse.SuccessData(careers = careers))
    }

    data class Career(
        @SerializedName("id") val id: String,
        @SerializedName("title") val title: String,
        @SerializedName("math_skill") val mathSkill: Int
        @SerializedName("other_skill") val mathSkill: Int
    ) {

         var skills: List<Skill> = {
              val mathSkill = Skill(name: "Math", rating: mathSkill, color: /**some color*/)
              val otherSkill = Skill(name: "Other", rating: otherSkill, color: /**some color*/)
              return listOf(mathSkill, otherSkill)
         }

    }

}

【问题讨论】:

    标签: android json serialization retrofit2


    【解决方案1】:

    是的,您可以创建自定义 JsonDeserializer 来修改 JSON 的解析方式。

    这是一个基本示例。

    class CareerDeserializer : JsonDeserializer<Career> {
    
        override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Career {
            val obj = json.asJsonObject
    
            // standard career data
            val id = obj.get("id")?.asString
            val name = obj.get("name").asString
    
            // making a Skill object
            val skill = Skill(
                    obj.get("mathematic_skill").asInt,
                    obj.get("critical_thinking_skill").asInt,
                    obj.get("swimming_skill").asInt
                    // etc
            )
    
            return Career(id, name, skill)
        }
    }
    

    并确保在您的 GsonBuilder 中进行注册。

    val gson = GsonBuilder()
                        .registerTypeAdapter(Career::class.java, CareerDeserializer())
                        .create()
    

    请注意,如果您也想另辟蹊径,还必须创建 JsonSerializer

    编辑:

    但是,如果您只是想更改访问该数据的语法,则可以执行以下操作。

    data class Career(
            // Other career data
            val mathSkill: Int,
            val thinkSkill: Int
            // remaining skills
    ) {
    
        val skills: List<Int>
            get() = listOf(mathSkill, thinkSkill)
    
    }
    

    这会在您需要时返回skills 列表,并且会在您访问它时创建,因此您不必担心数据不同步。这将允许您访问您的数据。

    career.skills[0] // get the math skill.
    

    您可以更进一步,将get 运算符添加到您的Career 类。

    data class Career(
            // Other career data
            val mathSkill: Int,
            val thinkSkill: Int
            // remaining skills
    ) {
        ...
    
        operator fun get(pos: Int) = skills[pos]
    
    }
    

    现在,你可以简单地做

    career[0] // get the math skill.
    

    警告,这很危险,因为您正在访问Array,因此您可能会得到OutOfBoundsExceptions。使用常量来帮助你。

    编辑 2:

    val skills = {
        listOf(Skill("Math", mathSkill, /** some color */ ),
                Skill("Other", otherSkill, /** some color */ ))
    }
    

    【讨论】:

    • 好的,要么构建一个完全自定义的 JsonDeserializer 类,要么我不能做我需要的?我不能将 @Serialized 数据类与自定义 JsonDeserializer 结合使用?
    • @BlondeSwan 差不多。如果您只想更改访问数据的方式,您可以在 Class 本身中执行此操作。给我一点时间,我会用另一个可能更适合你的建议来编辑我的答案。
    • @BlondeSwan 我编辑了我的答案,这对你更有效吗?
    • 我更新了我的答案以显示我目前拥有的内容以及我希望做的事情。我认为我最好的选择是像我一样继续解析数据,然后使用您建议的计算出的skills 变量来解释我需要的数组中的序列化数据!谢谢!
    • 我编辑了我的答案以解释我对上述评论的意思。您认为这是一个可行的解决方案吗?感谢您的提示!
    猜你喜欢
    • 1970-01-01
    • 2021-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    相关资源
    最近更新 更多