Специальное поле в данных JSON с использованием Джексона

1

У меня есть структура данных, которая имеет специальное свойство. Структура данных представляет данные о ценах на акции за весь день. [Так что в основном OLHC] В моей текущей процедуре сериализации и построителе я в настоящее время поддерживаю свойство "все". Каков метод в построителе, который устанавливает все цены OHLC по одной цене.

Есть ли способ установить это без необходимости иметь имя свойства для всех?

  • При сериализации это должно сделать сравнение и использовать все
  • При десериализации она должна перенаправляться на весь метод в построителе.

Возможно ли это в Джексоне?

Пример:

Структура данных выглядит так:

EODPrice 

  - Open
  - Low
  - Close
  - High

Давайте скажем, что у нас есть json: " {all: 5.00} " Это будет десериализовать, чтобы открыть: 5.00, минимум: 5.00, закрытие: 5.00 и максимум: 5.00. Если бы мы сериализовались, я бы хотел изменить поведение, так что если у нас есть Open == Low == Close == High, мы бы создали одно свойство, называемое all. Если это условие было неверным, мы бы не сериализовали свойство "все" вообще.

  • 0
    Мне просто интересно, не могли бы вы предоставить более подробную информацию. Как вы ожидаете, что all свойства будут сериализованы / десериализованы? Какое сравнение вы упоминаете?
  • 0
    Я просто изменил описание, чтобы отразить его
Показать ещё 2 комментария
Теги:
serialization
jackson

1 ответ

2
Лучший ответ

Сериализационная часть, безусловно, возможна, используя аннотацию @JsonFilter которой вы можете прочитать в документации Джексона.

Deserialization является стандартным Джексоном с помощью @JsonCreator.

Фильтры могут применяться к классам, методам и полям, и вы можете написать собственный собственный фильтр, который обрабатывает проблему с открытыми, низкими, закрытыми и большими.

Проверьте этот учебник для отличного введения.

Для примера кода взгляните на это. Сначала объявите свою EODPrice с @JsonFilter аннотации @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());
}

EDIT: После обновления от десериализации OP добавляется обновление POJO. Кроме того, бизнес-логика перемещается из фильтра в POJO.

  • 0
    Это то, что я искал! Благодарю. Мне нужно будет прочитать об этом и проверить, прежде чем я смогу пометить это как ответ.
  • 0
    Единственное беспокойство по этому поводу заключается в следующем: поле all не существует в неизменяемом объекте. (Что будет сделано при сериализации)
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню