【问题标题】:Exclude a Kotlin data class property/field from serialization/deserialization using gson使用 gson 从序列化/反序列化中排除 Kotlin 数据类属性/字段
【发布时间】:2018-11-22 07:12:08
【问题描述】:

我正在尝试使用 gson 从反序列化中排除 Kotlin 属性。我尝试了不同的方法,从使用 @Transient 注释属性到创建自定义注释策略(当然在 gson 构建器中指定策略),但似乎没有任何效果,因为属性不断变为 null 而不是我初始化的值属性。

我没有尝试使用@Expose注解,但我不想用@Expose注解其他字段

请问,请问如何使用 gson + Kotlin 实现这一点?

【问题讨论】:

    标签: kotlin gson retrofit2


    【解决方案1】:

    @Transient 为我工作。

    @Transient lateinit var bar: SomeCustomType
    

    每个@Transient 定义:

    将注解属性的 JVM 支持字段标记为transient, 意味着它不是对象的默认序列化形式的一部分。

    【讨论】:

      【解决方案2】:

      我还没有找到更优雅的解决方案,但现在,我已经给属性一个不同的名称,并将它从类的默认构造函数中删除。

      {
          "fName": "Bilbo"
          "lName": "Baggins"
      }
      
      data class Person(val fName: String) {
          lateinit var lNameObj: String
      }
      

      然后我可以在我的自定义解串器中分配lNameObj。

      【讨论】:

        【解决方案3】:

        您可以使用注释来实现相同的目的。示例

        package com.xently.utils
        
        import com.google.gson.*
        import com.xently.utils.Exclude.During.*
        import org.intellij.lang.annotations.Language
        import java.text.DateFormat
        
        @Retention(value = AnnotationRetention.RUNTIME)
        @Target(AnnotationTarget.FIELD)
        /**
         * Excludes field(s) from json serialization and/or deserialization depending on [during]
         * @param during When to exclude field from serialization and/or deserialization
         */
        annotation class Exclude(val during: During = BOTH) {
            /**
             * @see SERIALIZATION Exclude field ONLY from json serialization
             * @see DESERIALIZATION Exclude field ONLY from json deserialization
             * @see BOTH Exclude field from json serialization and deserialization
             */
            enum class During {
                /**
                 * Exclude field ONLY from json serialization
                 */
                SERIALIZATION,
        
                /**
                 * Exclude field ONLY from json deserialization
                 */
                DESERIALIZATION,
        
                /**
                 * Exclude field from json serialization and deserialization
                 */
                BOTH
            }
        }
        
        interface IData<T> {
            fun fromJson(@Language("JSON") json: String?): T?
        
            fun fromMap(map: Map<String, Any?>): T? = fromJson(JSON_CONVERTER.toJson(map))
        }
        
        inline fun <reified T> fromJson(json: String?): T? = if (json.isNullOrBlank()) null else try {
            JSON_CONVERTER.fromJson(json, T::class.java)
        } catch (ex: Exception) {
            null
        }
        
        private fun getExclusionStrategy(during: Exclude.During = Exclude.During.BOTH): ExclusionStrategy {
            return object : ExclusionStrategy {
                override fun shouldSkipClass(clazz: Class<*>?): Boolean {
                    return false
                }
        
                override fun shouldSkipField(f: FieldAttributes?): Boolean {
                    return if (f == null) true else {
                        val annotation = f.getAnnotation(Exclude::class.java)
                        if (annotation == null) {
                            false
                        } else {
                            annotation.during == during
                        }
                    }
                }
            }
        }
        
        val JSON_CONVERTER: Gson = GsonBuilder()
            .enableComplexMapKeySerialization()
            .addSerializationExclusionStrategy(getExclusionStrategy(SERIALIZATION))
            .addDeserializationExclusionStrategy(getExclusionStrategy(DESERIALIZATION))
            .setExclusionStrategies(getExclusionStrategy())
            .serializeNulls()
            .setDateFormat(DateFormat.LONG)
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .create()
        
        data class GsonSerializable(
            val name: String?,
            val age: Int = 0,
            val sex: Sex = Sex.MALE,
            @Exclude
            val ignore: String? = "ISD",
            @Exclude(DESERIALIZATION)
            val ignoreDes: String? = "ID",
            @Exclude(SERIALIZATION)
            val ignoreSer: String? = "IS"
        ) {
            enum class Sex {
                MALE,
                FEMALE
            }
        
            @Exclude(SERIALIZATION)
                    /**
                     * Without annotation it'd be serialized!
                     */
            val increaseAgeBy: (increment: Int) -> Int = {
                age + it
            }
        
            override fun toString(): String = JSON_CONVERTER.toJson(this)
        
            companion object : IData<GsonSerializable> {
                override fun fromJson(json: String?): GsonSerializable? = com.xently.utils.fromJson(json)
            }
        }
        

        单元测试

        package com.xently.utils
        
        import org.hamcrest.MatcherAssert.assertThat
        import org.hamcrest.Matchers.equalTo
        import org.hamcrest.Matchers.isEmptyOrNullString
        import org.junit.Test
        
        class GsonSerializableTest {
            @Test
            fun excludeAnnotationWorksCorrectly() {
                val test1 = GsonSerializable("My name", 23, GsonSerializable.Sex.FEMALE)
        
                val json1 = test1.toString()
                val testDesJson1 =
                    GsonSerializable.fromJson("""{"name":"My name","age":23,"sex":"FEMALE","ignore_des":"ID","ignore_ser":"IS"}""")
        
                assertThat(test1.increaseAgeBy.invoke(2), equalTo(25))
                assertThat(
                    json1,
                    equalTo("""{"name":"My name","age":23,"sex":"FEMALE","ignore_des":"ID"}""")
                )
                if (testDesJson1 != null) {
                    assertThat(testDesJson1.ignoreDes, isEmptyOrNullString())
                    assertThat(testDesJson1.ignoreSer, equalTo("IS"))
                }
            }
        }
        

        我从baeldung了解到注解的东西

        【讨论】:

          【解决方案4】:
          data class Foo (
              @Expose(deserialize = false) val bar: Bar
          )
          

          【讨论】:

          • 这是否不需要我用@Expose 标记我想要反序列化的其他字段,因为我同样试图避免这种情况
          • 这取决于您将如何创建 gson 构建器。例如:gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation() .create() - 将排除其他人
          • 如果我正在初始化 bar 属性怎么办?这正是问题所在。当我初始化属性时,它会返回 null
          【解决方案5】:

          我试图排除 displayedName 并且 我在这里尝试过解决方案,但对我有用的是

          data class Social(
          val id: Int? = null,
          var social_media_url: String? = null,
          val gym_id: Int? = null,
          val social_media: String? = null,
          val displayedName:String? = null)
          

          在上传请求之前,我将 displayedName 设置为 null,因此它不会被序列化

          【讨论】:

          • 有什么方法可以在运行时添加吗?
          • 运行时添加的方法是什么?
          猜你喜欢
          • 1970-01-01
          • 2021-01-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多