json 如何多态序列化实现密封接口的Kotlin枚举?

hvvq6cgz  于 2023-10-21  发布在  Kotlin
关注(0)|答案(1)|浏览(125)

我有以下密封接口(简化示例):

sealed interface Validation { val result: Int }

...它由几个枚举实现-每个枚举用于一个特定的应用程序。举例来说:

@Serializable(with = BoxedSerializer) // one of my attempts, see below
enum class AccountValidation(override val result: Int): Validation {
  UNKNOWN(10),
  BLOCKED(20),
  OK(30)
}

@Serializable(with = BoxedSerializer) // one of my attempts, see below
enum class PasswordValidation(override val result: Int): Validation {
  SHORT(10),
  WEAK(20),
  OK(30)
}

我想在可序列化的API类型中多态地使用这个枚举,如下所示:

@Serializable
data class ValidationResult(
  val userName: String,
  val validation: Validation
)

我在JVM上使用Kotlin1.7.21和Kotlin序列化1.4.1。开箱即用,这种设置不起作用,因为枚举被序列化为基本类型,没有type字段用于多态序列化。我尝试了其他几种尝试:

  • 通过代理类进行序列化,正如官方文档中所描述的,似乎不适用于枚举--我最终得到了一个堆栈溢出,可能是由于错误的递归。
  • 自定义序列化为described here会导致内部编译器错误。
  • 在泛型 Package 类中替代序列化(参见下面的示例代码):这也会因内部编译器错误而失败。
@Serializable
@SerialName("Validation")
data class ValidationBox<T : Validation>(val code: T)

class BoxedSerializer<T : Validation>(private val validationSerializer: KSerializer<T>) : KSerializer<T> {
    private val boxSerializer = ValidationBox.serializer(validationSerializer)
    override val descriptor: SerialDescriptor = boxSerializer.descriptor

    override fun serialize(encoder: Encoder, value: T) {
        val boxed = ValidationBox(value)
        encoder.encodeSerializableValue(boxSerializer, boxed)
    }

    override fun deserialize(decoder: Decoder): T {
        val boxed: ValidationBox<T> = decoder.decodeSerializableValue(boxSerializer)
        return boxed.code
    }
}

@Test
fun `polymorphically serialize and deserialize`() {
    val validation: Validation = AccountValidation.BLOCKED
    val validationJson = Json.encodeToString(validation)
    val validationDeserialized = Json.decodeFromString<Validation>(validationJson)
    assertEquals(validation, validationDeserialized)
}

我想得到的输出(JSON示例):

{
  "userName": "myUserName",
  "validation": {"PasswordValidation": "WEAK"}
}

或(更接近标准)

{
  "userName": "myUserName",
  "validation": {
      "type": "PasswordValidation",
      "value": "WEAK"
    }
}

半自定义或(如果需要)全自定义序列化程序是什么样子的?
谢谢你的帮助!

y1aodyip

y1aodyip1#

我也遇到了同样的问题,所以我使用了自定义序列化:

@JsonSerialize(using = EnumTypeSerializer::class)
@JsonDeserialize(using = EnumTypeDeserializer::class)
sealed class { enum1, enum2 }

object Serializer : JsonSerializer<EnumType>() {
override fun serialize(value: EnumType, jsonGenerator: JsonGenerator, serializers: SerializerProvider) {
    val name = when(value) {
        is EnumType.FIRST-> value.name
        is EnumType.SECOND-> value.name
    }
    jsonGenerator.writeString(name)
}

object NotificationGroupTypeDeserializer : JsonDeserializer<EnumType>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext?): EnumType{
    return EnumType.fromString(parser.valueAsString)
}

}

相关问题