Kotlinx序列化与Atlas SDK结合:反序列化能否忽略type的setter?
问题
我正尝试将kotlinx.serialization与Atlas Device SDK结合使用,计划通过Kotlin序列化type字段,借助Atlas SDK将_type字段存入数据库。因此在type的setter方法中会同步为_type赋值,但测试序列化时发现_type未被正确设置,请问反序列化过程中能否忽略type的setter?
测试代码
@Test fun testClassTest() { val dialogValue = TestClass(type = HeaderDialogValueType.DECIMAL_NUMBER) val dialogValueString = KotlinUtils.json.encodeToString(dialogValue) println(dialogValueString) val dialogValue2 = KotlinUtils.json.decodeFromString<HeaderDialogValue>(dialogValueString) assert(dialogValue.type == dialogValue2.type) }
待序列化并通过Atlas SDK存储的类
@Serializable class TestClass() { @Transient private var _type: String = HeaderDialogValueType.TEXT.name var type: HeaderDialogValueType = HeaderDialogValueType.TEXT get() { return HeaderDialogValueType.valueOf(_type) } set(value) { field = value _type = value.name } constructor(type: HeaderDialogValueType) : this() { this.type = type } }
枚举类
@Serializable enum class HeaderDialogValueType { @SerialName("NUMBER") NUMBER, @SerialName("TEXT") TEXT, @SerialName("ROLL") ROLL, @SerialName("DECIMAL_NUMBER") DECIMAL_NUMBER }
解决方案
可以通过以下几种方式实现反序列化时忽略type的setter,同时保证_type字段能正确同步:
给setter添加
@set:Transient注解
直接在type的setter上标记@set:Transient,让kotlinx.serialization反序列化时绕过自定义setter,直接给幕后字段赋值。之后通过@AfterDeserialize注解的方法手动同步_type的值:@Serializable class TestClass() { @Transient private var _type: String = HeaderDialogValueType.TEXT.name var type: HeaderDialogValueType = HeaderDialogValueType.TEXT get() { return HeaderDialogValueType.valueOf(_type) } @set:Transient set(value) { field = value _type = value.name } constructor(type: HeaderDialogValueType) : this() { this.type = type } @AfterDeserialize private fun afterDeserialize() { _type = type.name } }重构逻辑让
_type成为唯一数据源
既然type的getter是从_type取值,直接把type改成无幕后字段的属性,同时给_type绑定序列化逻辑(映射到JSON的type字段):@Serializable class TestClass() { private var _type: String = HeaderDialogValueType.TEXT.name var type: HeaderDialogValueType get() = HeaderDialogValueType.valueOf(_type) set(value) { _type = value.name } constructor(type: HeaderDialogValueType) : this() { this.type = type } @Serializer(forClass = TestClass::class) companion object : KSerializer<TestClass> { override val descriptor: SerialDescriptor = buildClassSerialDescriptor("TestClass") { element("type", HeaderDialogValueType.serializer().descriptor) } override fun serialize(encoder: Encoder, value: TestClass) { encoder.encodeSerializableElement(descriptor, 0, HeaderDialogValueType.serializer(), value.type) } override fun deserialize(decoder: Decoder): TestClass { val type = decoder.decodeSerializableElement(descriptor, 0, HeaderDialogValueType.serializer()) return TestClass(type) } } }这种方式反序列化时直接通过构造函数初始化
type,自然会同步_type,逻辑更简洁。拆分字段+反序列化后同步
把kotlinx.serialization实际序列化的字段和业务字段拆分,反序列化完成后再同步_type:@OptIn(ExperimentalSerializationApi::class) @Serializable class TestClass() { @Transient private var _type: String = HeaderDialogValueType.TEXT.name private var _serializedType: HeaderDialogValueType = HeaderDialogValueType.TEXT var type: HeaderDialogValueType get() = HeaderDialogValueType.valueOf(_type) set(value) { _serializedType = value _type = value.name } constructor(type: HeaderDialogValueType) : this() { this.type = type } @AfterDeserialize private fun afterDeserialize() { _type = _serializedType.name } }
内容的提问来源于stack exchange,提问作者Sk1X1
相关产品推荐
相关产品推荐

