首页 > 解决方案 > 使用 Jackson JsonDeserializer 解码自定义对象

问题描述

我是 Kotlin 的新手(来自 Swift),我有一个非常简单的 json,我需要根据该 json 的字段将其解码为两个不同的 Kotlin 类。如果字段是"type": "Square"我想解码一个Square类,如果字段是"type": "Rectangle",,我想解码一个Rectangle类。

我需要解码的json是

{
  "type": "Square",
  "size": "1"
}

或者

{
  "type": "Rectangle",
  "width": 1,
  "length": 2
}

我的 .kt 类就是这样定义的。我写了一个自定义JsonDeserializer,但它似乎不能作为jp.readValueAs(Square::class.java)retuns null 工作。

@JsonDeserialize(using = Shape.Deserializer::class)
sealed class Shape {
    enum class Type {
        Rectangle,
        Square
    }

    abstract val type: Type

    data class Square(
        val size: Int
    ) : Shape() {
        override val type: Type = Type.Square
    }

    data class Rectangle(
        val width: Int,
        val length: Int
    ) : Shape() {
        override val type: Type = Type.Rectangle
    }

    class Deserializer: JsonDeserializer<Shape>() {
        override fun deserialize(jp: JsonParser, ctxt: DeserializationContext?): Shape {
            var node = jp.readValueAsTree<JsonNode>()
            return when(node.get("type").asText()) {
                Type.Square.name ->
                    jp.readValueAs(Square::class.java)
                Type.Rectangle.name ->
                    jp.readValueAs(Rectangle::class.java)
                else -> throw JsonMappingException("")
            }
        }
    }
}

我做错了什么?

干杯

标签: kotlinjackson

解决方案


回答我自己的问题:我认为可以type使用我的类上的注释来打开属性Shape,如下所示

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes(
    value = [
        JsonSubTypes.Type(value = Shape.Square::class, name = "Square"),
        JsonSubTypes.Type(value = Shape.Rectangle::class, name = "Rectangle")
    ]
)
sealed class Shape {
    enum class Type {
        Rectangle,
        Square
    }
    abstract val type: Type
    data class Square(
        val size: Int
    ) : Shape() {
        override val type: Type = Type.Square
    }

    data class Rectangle(
        val width: Int,
        val length: Int
    ) : Shape() {
        override val type: Type = Type.Rectangle
    }
}

推荐阅读