如何使用 Jackson 通过元素属性将相同的 xml 元素反序列化为不同的 类? (多态反序列化)

How deserialize same xml element to different classes by element attribute with Jackson? (polymorphic deserialization)

我有一个 xml 结构的文件:

<actions shop_id="100500">

    <action type="refunds"> 
        <!-- properties collection for refunds -->
    </action>

    <action type="sales"> 
        <!-- another properties collection for sales -->
    </action>
    
    <action type="distributions"> 
        <!-- one more properties collection for distributions -->
    </action>

</actions>

如何根据操作类型将操作反序列化为不同的 类?

例如:将<action type="refunds">映射到Refunds.class,将<action type="sales">映射到Sales.class

你要的叫多态反序列化
您需要延长 RefundsSalesDistributions classes 来自一个共同的基础 class(让我们称它为 Action)。 将具体属性放入这些subclasses 并根据需要用 @JacksonXmlProperty(...) 注释它们。

public class Refunds extends Action {
    
    @JacksonXmlProperty(localName = "a", isAttribute = false)
    private int a;

    // getters and setters (omitted here for brevity)
}


public class Sales extends Action {

    @JacksonXmlProperty(localName = "b", isAttribute = false)
    private int b;

    // getters and setters (omitted here for brevity)
}


public class Distributions extends Action {

    @JacksonXmlProperty(localName = "c", isAttribute = false)
    private int c;

    // getters and setters (omitted here for brevity)
}

棘手的部分是实现基础 class。 我推荐阅读文章 "Inheritance in Jackson", 特别是它的部分“2.2。Per-Class注释”。
您需要向 Jackson 提供有关映射的足够信息 在你的 subclasses 和 type 属性 之间。 (并且不要被历史注释名称激怒 尽管您正在处理 XML,但以 Json... 开头。)

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(name = "refunds", value = Refunds.class),
    @JsonSubTypes.Type(name = "sales", value = Sales.class),
    @JsonSubTypes.Type(name = "distributions", value = Distributions.class)
})
public abstract class Action {

    @JacksonXmlProperty(isAttribute = true)
    private String type;
    
    // no getter/setter needed for type
}

最后你需要一个根 class 来代表 全部 <actions>...</actions> 内容。 它的 List<Action> 属性 将得到一个混合物 RefundsSalesDistributions 个对象。

@JacksonXmlRootElement(localName = "actions")
public class Actions {

    @JacksonXmlProperty(localName = "shop_id", isAttribute = true)
    private String shopId;

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "action", isAttribute = false)
    private List<Action> actions;

    // getters and setters (omitted here for brevity)
}

使用上面的 classes 和 Jackson 的 XmlMapper 你 能够像这样读写 XML 内容。

<actions shop_id="100500">
  <action type="refunds">
    <a>1</a>
  </action>
  <action type="sales">
    <b>2</b>
  </action>
  <action type="distributions">
    <c>3</c>
  </action>
</actions>