我有一个具有特殊属性的数据结构。数据结构代表整天的股票定价数据。 [所以基本上是OLHC]在我目前的序列化例程和构建器中,我目前支持一个" all"属性。这是构建器中的一种方法,它将所有OHLC价格设置为单一价格。
有没有办法设置它而不必拥有所有的属性名称?
杰克逊有可能吗?
示例:
数据结构如下:
EODPrice
- Open
- Low
- Close
- High
让我们说我们有json:" {all: 5.00}
"它会反序列化为Open:5.00,low:5.00,close:5.00,high:5.00。如果我们要序列化,我会想要改变行为,这样如果我们有Open == Low == Close == High,那么我们创建一个名为all的属性。如果那个条件不成立,那么我们就不会将所有"全部"财产。
答案 0 :(得分:2)
通过使用Jackson documentation中可以阅读的注释@JsonFilter
,绝对可以实现序列化部分。
反序列化是使用@JsonCreator
标准杰克逊。
过滤器可以应用于类,方法和字段,您可以编写自己的自定义过滤器来处理开放,低,近,高的问题。
查看this tutorial以获得精彩的介绍。
对于代码示例,请看一下。首先,使用EODPrice
注释声明您的@JsonFilter
。
@JsonIgnoreProperties(ignoreUnknown = true) // required to skip the "all" attribute in the JSON
@JsonFilter("allFilter") // Specify the filter
public class EODPrice {
private final BigDecimal close;
private final BigDecimal high;
private final BigDecimal low;
private final BigDecimal open;
// Builder method, does not include "all"
@JsonCreator
public EODPrice(
@JsonProperty("open") final BigDecimal open,
@JsonProperty("low") final BigDecimal low,
@JsonProperty("close") final BigDecimal close,
@JsonProperty("high") final BigDecimal high) {
this.open = open;
this.low = low;
this.close = close;
this.high = high;
}
// This is not part of the JSON but puts the business logic in the POJO
@JsonIgnore
public boolean allFieldsEqual() {
return open.equals(low) && open.equals(close) && open.equals(high);
}
public BigDecimal getAll() {
if (allFieldsEqual()) {
return open;
}
return BigDecimal.ZERO;
}
public BigDecimal getClose() {
return close;
}
public BigDecimal getHigh() {
return high;
}
public BigDecimal getLow() {
return low;
}
public BigDecimal getOpen() {
return open;
}
}
过滤器可能如下所示:
private PropertyFilter allFilter = new SimpleBeanPropertyFilter() {
@Override
public void serializeAsField(
Object pojo,
JsonGenerator jgen,
SerializerProvider provider,
PropertyWriter writer) throws Exception {
// If it is not the "all" property, go on with normal serialization
if (!writer.getName().equals("all")) {
writer.serializeAsField(pojo, jgen, provider);
return;
}
// Else, check the special all-rule
final EODPrice eodPrice = (EODPrice) pojo;
if (eodPrice.allFieldsEqual()) {
// Only serialize if all fields are equal
writer.serializeAsField(pojo, jgen, provider);
}
}
@Override
protected boolean include(BeanPropertyWriter writer) {
return true;
}
@Override
protected boolean include(PropertyWriter writer) {
return true;
}
};
最后,设置映射器。此测试用例说明过滤器启动:
@Test
public void testJsonRoundtrip() throws IOException {
final FilterProvider filters = new SimpleFilterProvider().addFilter("allFilter", allFilter);
final EODPrice eodPriceWithAll = new EODPrice(BigDecimal.ONE, BigDecimal.ONE, BigDecimal.ONE, BigDecimal.ONE);
final EODPrice eodPriceWithoutAll = new EODPrice(BigDecimal.TEN, BigDecimal.ONE, BigDecimal.ONE, BigDecimal.ONE);
final ObjectMapper mapper = new ObjectMapper();
mapper.setFilters(filters);
// First, test serialization
final String eodWithAllAsStr = mapper.writeValueAsString(eodPriceWithAll);
final String eodWithoutAllAsStr = mapper.writeValueAsString(eodPriceWithoutAll);
Assert.assertTrue(eodWithAllAsStr.contains("all"));
Assert.assertFalse(eodWithoutAllAsStr.contains("all"));
// Then, test deserialization
final EODPrice eodPriceWithAll2 = mapper.readValue(eodWithAllAsStr, EODPrice.class);
final EODPrice eodPriceWithoutAll2 = mapper.readValue(eodWithoutAllAsStr, EODPrice.class);
Assert.assertTrue(eodPriceWithAll2.allFieldsEqual());
Assert.assertFalse(eodPriceWithoutAll2.allFieldsEqual());
}
编辑:将OP反序列化的更新添加到POJO后。此外,业务逻辑从过滤器移动到POJO。