Gson — как сериализовать / десериализовать поле на основе значения другого поля?

#java #gson

#java #gson

Вопрос:

У нас довольно большой класс:

 class Foo {
    // ... many fields
    @Expose
    @JsonAdapter(DateAdapter.class)
    Date start;

    @Expose
    String startTimeZone;
    // ... more fields
}
  

Теперь локально значения start сохраняются как UTC, а информация о часовом поясе хранится отдельно в startTimeZone . Однако при отправке данных на сервер нам необходимо преобразовать начало в startTimeZone и отформатировать его в строку «ГГГГ-мм-дд ЧЧ: мм: сс».

У нас есть этот класс DateAdpater

 public class DateAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {

    @Override
    public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        return DateUtils.parseServerDateTime(json.getAsString);
    }

    @Override
    public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(DateUtils.formatServerDateTime(src));
    }
}
  

Однако в DateAdapter у нас нет доступа к полю startTimeZone, поэтому мы не можем использовать его для форматирования / синтаксического анализа.

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

Комментарии:

1. Может быть, вы могли бы создать пользовательский адаптер для всего класса, вызвать context.serialize() внутри него сериализацию всего остального и обработать startTimeZone по-другому?

2. @Pateman Спасибо за подсказку, я не знал, что это возможно. Кажется идеальным решением. Я попробую в понедельник. Если вы опубликуете свой комментарий в качестве ответа, я с радостью приму его, если это сработает.

3. @Pateman К сожалению, ваша идея не работает. Вызов context.serialize() внутри serialize приводит к бесконечному циклу и, в конечном итоге, к переполнению стека. Возможно, это будет работать с искусственным родительским классом, но мой класс является RealmObject, и они не допускают наследования :-/

4. Итак, вы не можете создать класс, поле которого является ссылкой на класс, который вы пытаетесь сериализовать? Что-то вроде class Foo { private <your_class> instance; } ?

5. @Pateman Ты имеешь в виду как оболочку? Возможно, это сработало бы, но тогда мне пришлось бы изменить весь код, чтобы использовать не класс, а оболочку … например, вместо foo.getStart() это должно быть wrapper.getFoo().getStart() …