【发布时间】:2018-11-22 07:12:08
【问题描述】:
我正在尝试使用 gson 从反序列化中排除 Kotlin 属性。我尝试了不同的方法,从使用 @Transient 注释属性到创建自定义注释策略(当然在 gson 构建器中指定策略),但似乎没有任何效果,因为属性不断变为 null 而不是我初始化的值属性。
我没有尝试使用@Expose注解,但我不想用@Expose注解其他字段
请问,请问如何使用 gson + Kotlin 实现这一点?
【问题讨论】:
我正在尝试使用 gson 从反序列化中排除 Kotlin 属性。我尝试了不同的方法,从使用 @Transient 注释属性到创建自定义注释策略(当然在 gson 构建器中指定策略),但似乎没有任何效果,因为属性不断变为 null 而不是我初始化的值属性。
我没有尝试使用@Expose注解,但我不想用@Expose注解其他字段
请问,请问如何使用 gson + Kotlin 实现这一点?
【问题讨论】:
@Transient 为我工作。
@Transient lateinit var bar: SomeCustomType
每个@Transient 定义:
将注解属性的 JVM 支持字段标记为
transient, 意味着它不是对象的默认序列化形式的一部分。
【讨论】:
我还没有找到更优雅的解决方案,但现在,我已经给属性一个不同的名称,并将它从类的默认构造函数中删除。
{
"fName": "Bilbo"
"lName": "Baggins"
}
data class Person(val fName: String) {
lateinit var lNameObj: String
}
然后我可以在我的自定义解串器中分配lNameObj。
【讨论】:
您可以使用注释来实现相同的目的。示例
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了解到注解的东西
【讨论】:
data class Foo (
@Expose(deserialize = false) val bar: Bar
)
【讨论】:
@Expose 标记我想要反序列化的其他字段,因为我同样试图避免这种情况
gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation() .create() - 将排除其他人
我试图排除 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,因此它不会被序列化
【讨论】: