如何序列化/反序列化“泼溅”的复杂类型?

时间:2015-05-11 12:33:44

标签: java xml jackson

我正在连接外部XML API,我正在尝试使用Jackson XmlMapper类将其解析为POJO。 XML的一部分如下所示:

<invoice>
    <some>element</some>
    <some_other>element</some_other>
    <currency>USD</currency>
    <cost>10.42</cost>
    <breakdown>
        <item id="1">
            <description>blah blah</description>
            <cost>4.21</cost>
        </item>
    </breakdown>
</invoice>

我想解析单个currency对象中的costMoney元素。

更糟糕的是,内部item仅指定成本并“重复使用”货币代码。我可以使用杰克逊以一种聪明的方式解析它们吗?

1 个答案:

答案 0 :(得分:4)

  

我想在单个Money对象中解析货币和成本要素。

根据提供的XML,您可以通过为发票创建值对象并使用@JsonUnwrapped,将currencycost元素解析为单个Money对象。

为发票创建值对象

如果您不想为发票创建对象,则可以将XmlMapper配置为忽略未知属性,并将整个响应反序列化为Money对象。在我看来,为您的发票创建一个单独的类是一种更清晰的方法。

创建Invoice对象的目的是封装响应的所有元素。目前您可能只需要currencycost,但稍后您可能需要访问breakdown。该对象可以这样构造:

public class Invoice {
    private final String some;
    private final String some_other;
    @JsonUnwrapped
    private final Money money;
    private final List<Item> breakdown;

    @JsonCreator
    public Invoice(@JsonProperty("some") String some,
                   @JsonProperty("some_other") String some_other,
                   @JsonProperty("money") Money money,
                   @JacksonXmlProperty(localName = "item") List<Item> breakdown) {
        this.some = some;
        this.some_other = some_other;
        this.money = money;
        this.breakdown = breakdown;
    }

    public String getSome() {
        return some;
    }

    public String getSome_other() {
        return some_other;
    }

    public Money getMoney() {
        return money;
    }

    public List<Item> getBreakdown() {
        return breakdown;
    }
}

请注意,Money属性已使用@JsonUnwrapped进行注释。这可以在字段上,在构造函数内部或在setter上,它将“展开”Money对象并在与Invoice相同的级别上反序列化其成员。像这样构建您的类以将货币和成本反序列化为单个对象:

public class Money {
    private final String currency;
    private final Double cost;

    @JsonCreator
    public Money(@JsonProperty("currency") String currency,
                 @JsonProperty("cost") Double cost) {
        this.currency = currency;
        this.cost = cost;
    }

    public String getCurrency() {
        return currency;
    }

    public Double getCost() {
        return cost;
    }
}
  

内部项目仅指定成本并“重复使用”货币代码。

如果可能,将Money和“item”模型分开

对于两个不同的模型重用Money对象不太理想,因为有一个abject来表示每个视图。例如,Moneycurrency的{​​{1}}对象以及costItemid的{​​{1}}对象。如果你的项目可以做到这一点,我会为“item”创建一个这样的对象:

description

重复使用cost作为“项目”值

如果您没有自由创建新对象并需要重用public class Item { @JacksonXmlProperty(isAttribute = true) public final String id; public final String description; public final Double cost; @JsonCreator public Item(@JsonProperty("id") String id, @JsonProperty("description") String description, @JsonProperty("cost") Double cost) { this.id = id; this.description = description; this.cost = cost; } public String getId() { return id; } public String getDescription() { return description; } public Double getCost() { return cost; } } ,则可以将Money配置为忽略未知属性并将所有属性放在{{1}上对象。

配置Money以忽略未知属性

我建议像这样扩展XmlMapper

Money

将所有可能的属性添加到XmlMapper

这将在元素存在时填充属性。例如,当反序列化“项目”时:XmlMapperpublic class CustomXmlMapper extends XmlMapper { public CustomXmlMapper() { configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } } Money将被填充,id将为空。

description