如何反序列化其他抽象的抽象子类型?

How to deserialize an abstract subtype of an other abstract?

提问人:Marco 提问时间:11/7/2023 更新时间:11/7/2023 访问量:21

问:

没有为此目的在网络上找到任何东西。 我有一个通用的抽象类

@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXISTING_PROPERTY,
        property = "elementType",
        visible = true
)
@JsonSubTypes({
        @JsonSubTypes.Type(name = "ENUM1", value = Abstract1.class),
        @JsonSubTypes.Type(name = "ENUM2", value = Abstract2.class)
})
public abstract class Element {
    protected String id;
    protected ElementType elementType;
}

其中 ElementType 为

public enum ElementType {
    ENUM1, ENUM2
}

然后我有 2 个抽象类。我只发布一个,另一个是相同的,除了传递的 property1 值:

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXISTING_PROPERTY,
        property = "property1",
        visible = true
)
@JsonSubTypes({
        @JsonSubTypes.Type(name = "value1", value = Concrete1.class),
        @JsonSubTypes.Type(name = "value2", value = Concrete2.class)
})
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public abstract class Abstract1 extends Element {
    protected String property1;

    protected Abstract1(...) {
        super(id, ElementType.ENUM1);
        ...
    }
}

Concrete1 是:

@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
public class Concrete1 extends Abstract1 {
    public Concrete1(...) {
        super(id, "property string");
    }
}

因此,我尝试反序列化json:

{
    "id": "an id",
    "elementType": "ENUM1",
    "property1": "value1"
}

@Test
    public void concrete1Test() throws IOException {
        String json = "...";
        Element element = mapper.readValue(json, Element.class);
        Assert.assertTrue(element instanceof Concrete1);  <---- fail
    }

断言失败,因为最后一个元素以 Concrete2 的形式出现。这就像它正在选择第一个可用于反序列化的具体类。 我已经调查并发现,也许我应该为 Concrete1 和 2 的特定反序列化注册模块。他们必须井井有条。我注册了它们

@Test
    public void concrete1Test() throws IOException {
        ...
        mapper.registerModule(new SimpleModule("Concrete1Module", Version.unknownVersion())
                .addDeserializer(Concrete1.class, new Concrete1Deserializer())
                .addDeserializer(Concrete2.class, new Concrete2Deserializer()));
        Element element = mapper.readValue(json, Element.class);
        Assert.assertTrue(element instanceof Concrete1);
    }

但它仍然在回馈 Concrete2。

事实是,我正在尝试将一个元素反序列化,我将在我的控制器中将其作为正文请求,到一个 Concrete1 类,知道

Concrete1 extends (Abstract1 extends Element)

所以必须从 Element 返回到 Concrete1,通过 Abstract1。这是一件可行的事情吗?我错过了什么吗?

Java 多态性 抽象类 JSON 反序列化

评论

1赞 Jorn 11/7/2023
我不认为支持多个级别。您可能应该在 上声明所有子类型。您可以通过使用相同的配置序列化某些子类并查看生成的 JSON 来检查这一点。JsonSubTypesElement
0赞 Marco 11/8/2023
不幸的是,@Jorn我发现多级反序列化不是一回事。github.com/FasterXML/jackson-databind/issues/1188 你是对的。必须考虑另一种模式..谢谢

答: 暂无答案