如何注册一个接口的全局类型适配器,没有注释每个类,而使用kotlinx.serialization?



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字段声明可序列化类的文件中。

最新更新