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

时间:2018-12-19 18:38:15

标签: android json serialization retrofit2

我正在努力更新API响应的解析,该API响应使用序列化数据类来解析JSON响应。现在,序列化工作正常,但是我尝试解析为数据类的新数据并不完全依赖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)
         }

    }

}

1 个答案:

答案 0 :(得分:0)

是的,您可以创建一个自定义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 */ ))
}