gson 在使用kotlinx.serialization时,如何为接口注册全局类型适配器,而不注解每个类?

t98cgbkg  于 2022-11-06  发布在  Kotlin
关注(0)|答案(1)|浏览(186)

Gson允许我执行GsonBuilder().registerTypeAdapter(MyInterface::class.java, MyConcreteClassAdapter()),但我无法对kotlinx.serialization执行相同操作
我只想公开接口(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)
    }
}
gv8xihay

gv8xihay1#

要处理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())
}

然后使用ValueInterface字段将@file:UseSerializers(ValueInterfaceAsLong::class)注解添加到所有声明了可序列化类的文件中。

相关问题