如何serialize/deserialize"splashed"复杂类型?
How to serialize/deserialize "splashed" complex type?
我正在连接到外部 XML API,我正在尝试使用 Jackson XmlMapper
class 将其解析为 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
对象中解析 currency
和 cost
元素。
更糟糕的是,内部 item
仅指定成本和 "reuse" 货币代码。我可以使用 Jackson 以某种智能方式解析它们吗?
I want to parse the currency and cost elements in a single Money object.
鉴于提供的 XML,您可以通过为发票创建值对象并利用@JsonUnwrapped
.
为发票创建值对象
如果您不想为发票创建对象,您可以改为配置 XmlMapper
以忽略未知属性,并将整个响应反序列化到 Money
对象中。在我看来,为您的发票创建单独的 class 是一种更简洁的方法。
创建 Invoice
对象的目的是封装响应的所有元素。现在您可能只需要 currency
和 cost
,但稍后您可能想要访问 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 上,它将 "unwrap" Money
对象并在与 Invoice
相同的级别反序列化其成员.像这样构造您的 class 以将货币和成本反序列化为单个对象:
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
和 "item" 模型
为两个不同的模型重用 Money
对象不如用一个 abject 来表示每个视图那么理想。例如,currency
和 cost
的 Money
对象以及 id
、description
和 cost
的 Item
对象.如果这在您的项目中可行,我会为 "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;
}
}
为 "item" 值重复使用 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;
}
}
我正在连接到外部 XML API,我正在尝试使用 Jackson XmlMapper
class 将其解析为 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
对象中解析 currency
和 cost
元素。
更糟糕的是,内部 item
仅指定成本和 "reuse" 货币代码。我可以使用 Jackson 以某种智能方式解析它们吗?
I want to parse the currency and cost elements in a single Money object.
鉴于提供的 XML,您可以通过为发票创建值对象并利用@JsonUnwrapped
.
为发票创建值对象
如果您不想为发票创建对象,您可以改为配置 XmlMapper
以忽略未知属性,并将整个响应反序列化到 Money
对象中。在我看来,为您的发票创建单独的 class 是一种更简洁的方法。
创建 Invoice
对象的目的是封装响应的所有元素。现在您可能只需要 currency
和 cost
,但稍后您可能想要访问 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 上,它将 "unwrap" Money
对象并在与 Invoice
相同的级别反序列化其成员.像这样构造您的 class 以将货币和成本反序列化为单个对象:
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
和 "item" 模型
为两个不同的模型重用 Money
对象不如用一个 abject 来表示每个视图那么理想。例如,currency
和 cost
的 Money
对象以及 id
、description
和 cost
的 Item
对象.如果这在您的项目中可行,我会为 "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;
}
}
为 "item" 值重复使用 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;
}
}