Как создать вычисляемые свойства в классе данных с помощью GSON? - PullRequest
0 голосов
/ 01 июля 2019

Фон: GSON, Kotlin, Retrofit

Я пишу приложение для ресторана. На главной странице пользователь может загрузить список брендов ресторанов. У каждого бренда может быть до 3 типов кухонь, первый из которых не равен нулю, а следующие два являются обнуляемыми. Каждый тип кухни относится к классу перечислений CuisineType.

Что я хотел бы сделать, это создать объединенную строку следующим образом: kitchenType1.title + kitchenType2? .title + kitchenType3? .title = комбинированные кухни. Это может сделать все кухни, показанные в textView на китайском языке. Для этого я создал вспомогательный класс. В этом вспомогательном классе, если CuisineType из Brand не может отобразить ни одного из членов перечисления, он будет отображать необработанное имя из Brand JSON (в случае ошибки сервера). Я попробовал три решения, прокомментированные ниже, и ни одно из них не работает. Большая помощь будет оценена. Заранее спасибо!

data class Brand(
    @SerializedName("id")
    val id: Int,
    @SerializedName("name_en")
    val nameEN: String?,

    @SerializedName("cuisine_1")
    val cuisineType1: String,
    @SerializedName("cuisine_2")
    val cuisineType2: String?,
    @SerializedName("cuisine_3")
    val cuisineType3: String?,

    /*Solution 1(not working):
        val combinedCuisines = CombineCuisineHelper.combineCuisines(cuisineType1, cuisineType2, cuisineType3)
    ***java.lang.IllegalArgumentException: Unable to create converter for class
    */

    /*Solution 2(not working):
        @Transient
        val combinedCuisines = CombineCuisineHelper.combineCuisines(cuisineType1, cuisineType2, cuisineType3)
    ***combinedCuisines = null after network call in fragment
    */
) {
    /* Solution 3(not working):
        val combinedCuisines: String
            get() = CombineCuisineHelper.combineCuisines(cuisineType1, cuisineType2, cuisineType3)
        ***problem with GSON, I can only map the @SerializedName from the Cuisine enum class and will only run the illegal argument solution from the CombineCuisineHelper. For example, get hong_kong_style from the JSON brand but it will not convert to HongKongStyle and map to its title.
    */
}

//It should be a long list but I shortened it.
enum class CuisineType {
    @SerializedName("chinese")
    Chinese,
    @SerializedName("hong_kong_style")
    HongKongStyle,
    @SerializedName("cantonese")
    Cantonese,

    val title: Double
    get() {
        return when (this) {
            Chinese       -> "中菜"
            HongKongStyle -> "港式"
            Cantonese     -> "粵式"
}

class CombineCuisineHelper {
    companion object {
        fun combineCuisines(cuisineSubtype1: String, cuisineSubtype2: String?, cuisineSubtype3: String?): String {
            val combinedSubtypes = ArrayList<String?>()
            combinedSubtypes += try {
                CuisineSubtype.valueOf(cuisineSubtype1).title
            } catch (e: IllegalArgumentException) {
                cuisineSubtype1
            }
            if (cuisineSubtype2 != null) {
                combinedSubtypes += try {
                    CuisineSubtype.valueOf(cuisineSubtype2).title
                } catch (e: IllegalArgumentException) {
                    cuisineSubtype2
                }
            }
            if (cuisineSubtype3 != null) {
                combinedSubtypes += try {
                    CuisineSubtype.valueOf(cuisineSubtype3).title
                } catch (e: IllegalArgumentException) {
                    cuisineSubtype3
                }
            }
}

1 Ответ

0 голосов
/ 02 июля 2019

Первое и второе решения не годятся, потому что данные могут быть не готовы во время инициализации. Третье решение - это то, на котором мы можем продолжить:

        val combinedCuisines: String
            get() = CombineCuisineHelper.combineCuisines(cuisineType1, cuisineType2, cuisineType3)

SerializedName s бесполезны для констант enum и не будут работать для вас, как вы ожидаете. Таким образом, метод valueOf для enum не найдет значение для литералов, таких как "hong_kong_style", и выдаст исключение.

Вы можете создать свой собственный вспомогательный метод в своем классе enum следующим образом:

enum class CuisineType {
    Chinese,
    HongKongStyle,
    Cantonese;

    val title: String
        get() {
            return when (this) {
                Chinese -> "中菜"
                HongKongStyle -> "港式"
                Cantonese -> "粵式"
            }
        }

    companion object {
        //Note this helper method which manually maps string values to enum constants:
        fun enumValue(title: String): CuisineType = when (title) {
            "chinese" -> Chinese
            "hong_kong_style" -> HongKongStyle
            "cantonese" -> Cantonese
            else -> throw IllegalArgumentException("Unknown cuisine type $title")
        }
    }
}

А затем используйте этот новый метод вместо собственного valueOf метода перечисления:

            val combinedSubtypes = ArrayList<String?>()
            combinedSubtypes += try {
                CuisineType.enumValue(cuisineSubtype1).title
            } catch (e: IllegalArgumentException) {
                cuisineSubtype1
            }
            //continued...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...