java - 如何序列化/反序列化 "splashed"复杂类型?

标签 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>

我想解析单个 Money 对象中的 currencycost 元素。

更糟糕的是,内部item仅指定成本并“重用”货币代码。我可以使用 Jackson 以某种智能方式解析它们吗?

最佳答案

I want to parse the currency and cost elements in a single Money object.

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

为发票创建值对象

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

创建Invoice的目的object 是封装响应的所有元素。现在您可能只需要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;
    }
}

the inner items only specify the cost and "reuse" the currency code.

分隔 Money和“项目”模型(如果可能)

重用Money与使用一个对象来表示每个 View 相比,两个不同模型的对象不太理想。例如,Money对象 currencycost ,以及 Item对象 id , description ,和cost 。如果这在您的项目中是可能的,我将为“item”创建一个像这样的对象:

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对于“项目”值

如果您没有自由创建新对象并且需要重用Money ,您可以配置您的XmlMapper忽略未知属性并将所有属性放在 Money 上对象。

配置XmlMapper忽略未知属性

我建议延长 XmlMapper像这样:

public class CustomXmlMapper extends XmlMapper {
    public CustomXmlMapper() {
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }
}

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

当元素存在时,这将填充属性。例如,当反序列化“item”时:id , description ,和cost将被填充并且 currency将为空。

public class Money {
    @JacksonXmlProperty(isAttribute = true)
    public final String id;
    public final String description;
    private final String currency;
    private final Double cost;

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

    public String getId() {
        return id;
    }

    public String getDescription() {
        return description;
    }

    public String getCurrency() {
        return currency;
    }

    public Double getCost() {
        return cost;
    }
}

关于java - 如何序列化/反序列化 "splashed"复杂类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30167770/

相关文章:

java - ClassNotFoundException - ResteasyBootstrap

java - 将代码块保存在变量中

java - 使用 jxl 修改现有的 excel

java - 从 persistence.xml 中的系统/文件获取用户和密码

基于 C 的 XML 解析器

java - jackson 接受否定日期

java - 如何不使用 jackson objectMapper 编写 Option.None (并读取它)?

Java 简单彩票程序

java - 使用 Java 查询 XML

java - 如何将多态json字符串转换为java bean类