Как добавить дополнительные поля в объект во время сериализации Джексона json?

Мне нужно добавить новое свойство к объекту при сериализации в JSON. Значение свойства вычисляется во время выполнения и не существует в объекте. Также один и тот же объект может использоваться для создания разных JSON с разными полями set ot (вроде базового класса с подклассами, но я не хочу создавать их только для генерации JSON).

Каков наилучший способ сделать это, что не связано с созданием пользовательского класса сериализатора, который позаботится о сериализации всего набора полей объекта? Или, может быть, можно наследовать некоторый "базовый" сериализатор, и просто взять его вывод и добавить к нему какое-то новое поле?

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

Ответ 1

Не можете ли вы добавить метод в класс значений? Обратите внимание, что это не должно быть публичным или использовать соглашение об именовании получателя; вы можете сделать что-то вроде:

public class MyStuff {
   // ... the usual fields, getters and/or setters

   @JsonProperty("sum") // or whatever name you need in JSON
   private int calculateSumForJSON() {
        return 42; // calculate somehow
   }
}

В противном случае вы можете преобразовать POJO в значение дерева JSON:

JsonNode tree = mapper.valueToTree(value);

а затем измените его, добавив свойства и т.д.

Ответ 2

Один из вариантов - добавить поле для этого свойства и установить его на объект перед записью в JSON. Второй вариант, если свойство можно вычислить из других свойств объекта, вы можете просто добавить для него геттер, например:

public String getFullName() {
  return getFirstName() + " " + getLastName();
}

И даже если нет соответствующего поля, Джексон будет автоматически вызывать этот getter при записи JSON, и он будет отображаться как fullName на выходе JSON. Если это не сработает, третий вариант состоит в том, чтобы преобразовать объект в карту и затем манипулировать им, но вам нужно:

ObjectMapper mapper //.....
MyObject o //.....
long specialValue //.....
Map<String, Object> map = mapper.convertValue(o, new TypeReference<Map<String, Object>>() { });
map.put("specialValue", specialValue);

Вы сомневаетесь, что не упоминаете unmarshalling, но если вам нужно это сделать, тогда первый вариант будет работать нормально, но второй второй потребует некоторой настройки.

А что касается написания разных полей одного и того же объекта, это звучит как задание для @JsonView