使用Jackson的JSON数据专场

时间:2014-12-26 02:23:47

标签: java json serialization jackson

我有一个具有特殊属性的数据结构。数据结构代表整天的股票定价数据。 [所以基本上是OLHC]在我目前的序列化例程和构建器中,我目前支持一个" all"属性。这是构建器中的一种方法,它将所有OHLC价格设置为单一价格。

有没有办法设置它而不必拥有所有的属性名称?

  • 在序列化时,它应进行比较并使用所有
  • 在反序列化时,它应该重定向到构建器中的all方法。

杰克逊有可能吗?

示例:

数据结构如下:

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的属性。如果那个条件不成立,那么我们就不会将所有"全部"财产。

1 个答案:

答案 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。