如何在实施GSON的数据类中创建计算属性?

时间:2019-07-01 16:55:53

标签: android json kotlin gson

背景:GSON,科特林,改造

我正在编写一个餐厅应用程序。在主页中,用户可以加载餐厅品牌列表。每个品牌最多可以提供3种美食类型,第一种是非空的,接下来的两种是可空的。每种美食类型都在CuisineType枚举类中。

我想做的是创建一个这样的连接字符串: cuisineType1.title + cuisineType2?.title + cuisineType3?.title =组合的Cuisines。这样可以使所有美食都显示在textView中。为此,我创建了一个帮助器类。在此帮助器类中,如果Brand的CuisineType无法映射任何枚举成员,它将显示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 :(得分:0)

第一个和第二个解决方案不好,因为初始化时数据可能未准备好。第三种解决方案是我们可以继续使用的解决方案:

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

SerializedName对于枚举常量没有用,并且不能像您期望的那样为您工作。因此,用于枚举的valueOf方法将找不到"hong_kong_style"之类的文字值,并且会引发异常。

您可以在枚举类中创建自己的帮助方法,如下所示:

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...