接口/实现的串行器

时间:2019-12-23 09:38:07

标签: kotlin kotlinx.serialization

假设有一个接口和2个(或更多)实现:

interface IRunnable {
  fun run()
}

class Horse : IRunnable {
  override fun run() {    println("horse running")  }
}

class Dog : IRunnable {
  override fun run() {    println("dog running")  }
}

我想实现用于网络传输的最简洁的JSON,即,对于Horse,{"runnable":"H"}和对于Dog,{"runnable":"D"}

如果我无法修改接口和实现,我想将接口/实现序列化为JSON,根据Kotlin的文档,我必须编写custom serializer并使用{{ 1}}实现目标。

假设只有SerializersModuleHorse实现Dog,这就是我所做的:

IRunnable

但是当我尝试将class RunnableSerializer : KSerializer<IRunnable> { override val descriptor: SerialDescriptor get() = StringDescriptor.withName("runnable") override fun serialize(encoder: Encoder, obj: IRunnable) { val stringValue = when (obj) { is Horse -> { "H" } is Dog -> { "D" } else -> { null } } stringValue?.also { encoder.encodeString(it) } } override fun deserialize(decoder: Decoder): IRunnable { return decoder.decodeString().let { value -> when(value) { "H" -> Horse() "D" -> Dog() else -> throw RuntimeException("invalid $value") } } } } 转换为JSON时...

Horse

它输出错误:

class RunnableTest {

  private val logger = KotlinLogging.logger { }

  @ImplicitReflectionSerializer
  @Test
  fun testJson() {
    val module1 = serializersModuleOf(IRunnable::class, RunnableSerializer())

    Json(context = module1).stringify(IRunnable::class.serializer(), Horse()).also {
      logger.info("json = {}", it)
    }
  }
}

如何实现类似 在这种情况下是kotlinx.serialization.SerializationException: Can't locate argument-less serializer for class IRunnable. For generic classes, such as lists, please provide serializer explicitly. 还是{"runnable":"H"}

谢谢。

环境:

{"runnable":"D"}

已更新,完整的错误消息:

<kotlin.version>1.3.60</kotlin.version>
<serialization.version>0.14.0</serialization.version>

1 个答案:

答案 0 :(得分:3)

您要实现的目标称为多态序列化,which kotlinx.serialization supports。简而言之:它要求您将IRunnable的所有派生类型注册为SerialModule中的多态。对于您的代码,其外观应如下所示:

val serialModule = SerializersModule {
    polymorphic(IRunnable::class) {
        Horse::class with HorseSerializer
        Dog::class with DogSerializer
    }
}

当前,您仅注册IRunnable,该异常正确地表明了@Serializable无法初始化。您将如何初始化接口?你不能相反,您想知道要初始化的特定派生类型。这需要在JSON数据中嵌入类型信息,这就是多态序列化的作用。

此外,您不一定必须实现自定义序列化程序。根据您链接到的文档,您可以创建external serializers for library classes。以下内容可能就足够了,因为kotlinx.serialization编译器插件将尝试为您生成合适的序列化器,类似于您直接在类上添加@Serializer(forClass = Horse::class) object HorseSerializer {} @Serializer(forClass = Dog::class) object DogSerializer {} 的情况:

json_decode