Класс сериализированных данных в сочетании со встроенными модификациями - PullRequest
0 голосов
/ 19 декабря 2018

Я работаю над обновлением синтаксического анализа ответа API, который использует Serialized Data Class для анализа ответа 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 голосов
/ 19 декабря 2018

Да, вы можете создать пользовательский 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 */ ))
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...