简体   繁体   English

序列化数据类结合内置修改

[英]Serialized Data Class combined with built-in modifications

I am working on updating the parsing of an API response that uses a Serialized Data Class to parse the JSON response. 我正在更新使用序列化数据类来解析JSON响应的API响应的解析。 The serialization works perfectly fine right now, but the new data that I'm attempting to parse into data class is not fully reliant on data in the json. 现在,序列化工作正常,但是我尝试解析为数据类的新数据并不完全依赖json中的数据。 Here is what I mean by that: 这是我的意思:

The data class is Career , and the new data I need to parse is a set of skills and each have a rating . 数据类是Career ,我需要解析的新数据是一套skills ,每个都有rating The json data is very simple and contains the skills as such: json数据非常简单,包含如下技能:

{
    // other career data

    ... 

    "mathematics_skill": 8,
    "critical_thinking_skill": 6

    ... // the remaining skills
}

Using straight serialization, I would only be able to store the data as such: 使用直接序列化,我将只能这样存储数据:

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

However, I would like to store all skills in an array variable of a custom skills class that not only contains the rating, but also the name of the skill and a color. 但是,我想将所有技能存储在自定义技能类的数组变量中,该变量不仅包含等级,还包含技能名称和颜色。 Basically, when I access the skills data of a career, I would like to access it like such: 基本上,当我访问职业技能数据时,我想像这样访问它:

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

Is it possible to use the serialized data from the data class to add non-serialized data to the same data class? 是否可以使用数据类中的序列化数据将非序列化数据添加到同一数据类中? (Sorry for the weird wording, not sure how else to explain it) (对不起,措辞怪异,不确定是否还有其他解释方法)

EDIT: Here is what I have: 编辑:这是我所拥有的:

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,
    )
}

Here is what I am hoping to do in a way 这是我希望以某种方式做的事情

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>

    )
}

EDIT: The suggested solution 编辑:建议的解决方案

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)
         }

    }

}

Yes, you can create a custom JsonDeserializer to modify how the JSON is parsed. 是的,您可以创建一个自定义JsonDeserializer来修改JSON的解析方式。

Here is a basic example of what that would look like. 这是一个什么样的基本示例。

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)
    }
}

And make sure to register that within your GsonBuilder. 并确保在您的GsonBuilder中进行注册。

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

Note, you'll also have to create a JsonSerializer if you want to go the other way too. 请注意,如果您也想使用其他方法,则还必须创建一个JsonSerializer

Edit: 编辑:

However, if you're just looking to change the syntax of how you're accessing that data, you can do something like this. 但是,如果您只是想更改访问该数据的语法,则可以执行以下操作。

data class Career(
        // Other career data
        val mathSkill: Int,
        val thinkSkill: Int
        // remaining skills
) {

    val skills: List<Int>
        get() = listOf(mathSkill, thinkSkill)

}

This would give you a skills list back whenever you needed it, and it would be created when you accessed it, so you won't have to worry about the data being out of sync. 这样一来,您就可以在需要时返回skills列表,并且可以在访问时创建它,因此您不必担心数据不同步。 This would allow you to access your data as such. 这样您就可以访问自己的数据。

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

And you can take this another step further by adding a get operator to your Career class. 您可以通过将一个get运算符添加到Career类中来进一步走这一步。

data class Career(
        // Other career data
        val mathSkill: Int,
        val thinkSkill: Int
        // remaining skills
) {
    ...

    operator fun get(pos: Int) = skills[pos]

}

Now, you can simply do 现在,您只需

career[0] // get the math skill.

Warning, this is dangerous because you're accessing an Array so you could get OutOfBoundsExceptions . 警告,这很危险,因为您正在访问Array因此可能会得到OutOfBoundsExceptions Use constants to help you out. 使用常量可以帮助您。

Edit 2: 编辑2:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM