Gson
会让我做GsonBuilder().registerTypeAdapter(MyInterface::class.java, MyConcreteClassAdapter())
,但我无法对kotlinx.serialization
进行相同的操作
我只想公开接口(ValueInterface
),所以我可以隐藏实现和序列化细节。但是,该接口是许多类的字段,如Box
,我不想通过用@Serializable(with = SomeDeserializer::class)
ValueInterface
字段来泄露序列化细节。注意ValueObject
有它自己的自定义序列化。
下面的代码被kotlinx.serialization.SerializationException: Class 'ValueObject' is not registered for polymorphic serialization in the scope of 'ValueInterface'. Mark the base class as 'sealed' or register the serializer explicitly.
打断。
但是,当我将Box
值类型更改为ValueObject
而不是ValueInterface
时,它可以工作。
我需要改变什么,使它像Gson
一样工作,并能够有ValueInterface
类型的字段?
package kxs
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encodeToString
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import org.junit.Assert
import org.junit.Test
class KXSTest {
@Test
fun test(){
val actualStr = Json.encodeToString(Box("name1",ValueInterface.create(42)))
Assert.assertEquals("""{"name":"name1","value":42}""",actualStr)
val actualObj: Box = Json.decodeFromString("""{"name":"name2","value":43}""")
Assert.assertEquals(Box("name2",ValueInterface.create(43)),actualObj)
}
}
// public stuff
interface ValueInterface {
fun value() : Long
companion object {
fun create(long: Long) =
ValueObject(long)
}
}
@Serializable
data class Box(val name: String, val value: ValueInterface)
//internal details not meant to be exposed
@Serializable(with = ValueObjectAsLong::class)
data class ValueObject(val value: Long): ValueInterface {
init {
require(value > 0)
}
override fun value(): Long = value
}
object ValueObjectAsLong : KSerializer<ValueObject> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ValueObjectAsLong",PrimitiveKind.LONG)
override fun deserialize(decoder: Decoder): ValueObject {
return ValueObject(decoder.decodeLong())
}
override fun serialize(encoder: Encoder, value: ValueObject) {
encoder.encodeLong(value.value)
}
}
要处理ValueInterface
字段的序列化,只需将@Serializable(with = ValueObjectAsLong::class)
注释从ValueObject
类移动到ValueInterface
。用无参数的@Serializable
注释接口是不可能的,但是如果为with
参数提供一个值,它编译得很好:
@Serializable(with = ValueObjectAsLong::class)
interface ValueInterface { /*...*/ }
如果你需要序列化第三方接口,这就有点棘手了。首先,您需要为接口定义序列化器,而不是它的实现类:
object ValueInterfaceAsLong : KSerializer<ValueInterface> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ValueInterfaceAsLong", PrimitiveKind.LONG)
override fun serialize(encoder: Encoder, value: ValueInterface) = encoder.encodeLong(value.value())
override fun deserialize(decoder: Decoder) : ValueInterface = ValueObject(decoder.decodeLong())
}
然后将@file:UseSerializers(ValueInterfaceAsLong::class)
注释添加到所有使用ValueInterface
字段声明可序列化类的文件中。