#java #jackson #deserialization #spring-social
#java #jackson #десериализация #spring-social
Вопрос:
Мне нужно выполнить некоторый код после каждой десериализации полей POJO. Могу ли я каким-либо образом сделать это с помощью какой-либо стратегии аннотации jackson (или другой)?
-
Один из способов реализовать это — создать пользовательский десериализатор для каждого типа поля, который будет реализовывать PostLogicDeserializerInterface или расширять некоторый PostLogicDeserializerAbstract. Но это приведет к появлению большого количества загромождающего кода, который будет трудно поддерживать (вместо простого использования @JsonProperty). Поэтому я думаю, что это не очень хорошая идея.
-
Я видел, что вы можете использовать @JsonDeserialize на уровне класса, но только для классов значений. Из документации:
При аннотировании классов значений конфигурация используется для экземпляров класса значений, но может быть переопределена более конкретными аннотациями (теми, которые прикрепляются к методам или полям).
Поэтому я думаю, что это тоже не сработает.
- Использование некоторой пользовательской логики в методах настройки POJOs — плохая практика! И с другой стороны, я думаю, что jackson использует отражение для установки полей в любом случае… Также не является хорошей стратегией.
Моя цель — определить процент полей, которые были установлены десериализатором. Мне нужно было бы иметь счетчик, который будет увеличиваться при каждой вызванной десериализации (заполненное поле). И как только десериализация всего класса (POJO) завершится, мне нужно будет выполнить некоторую логику с использованием отражения.
Способ, который я реализовал сейчас, заключается в
- как только я десериализирую POJO с помощью jackson mapper, я просматриваю каждое поле, используя отражение
- проверьте, было ли оно установлено, например, равно ли оно null или -1 для примитивных чисел (ранее начальных значений). (одним из недостатков этого подхода является то, что вы не можете проверить логическое значение, если оно было установлено)
- используйте отражение для какого-либо другого вида проверки (назовем это logic X)
- выполнить логику, которая зависит от процента заданных полей и логики X.
Я бы предпочел какую-нибудь стратегию jackson, поскольку мне не нужно было бы проверять POJO с отражением. Это скорее было бы сделано на месте (во время десериализации POJO).
Приветствия,
Деспот
Ответ №1:
На данный момент нет какой-либо конкретной функции для выполнения пост- или предварительной обработки; и этот вид приближается к границам того, что должна выполнять привязка данных. Если бы мне пришлось сделать это для определенных полей, я бы, вероятно, просто добавил это в setter, поскольку это просто сделать и работает; но требует одинаковой логики во всех соответствующих установщиках.
@JsonDeserialize также можно использовать для отдельных свойств (field, setter), чтобы вы могли создать пользовательский десериализатор: и поскольку вам нужна постобработка, вы могли бы просто найти «реальный» десериализатор (в идеале, JsonDeserializer
реализовав либо ContextualDeserializer
, либо ResolvableDeserializer
— здесь это может не иметь значения, но в общем случае это сделано здесь, чтобы избежать проблем с циклическими зависимостями), делегировать ему и изменить значение. Это предполагает, что значение, о котором вы заботитесь больше, чем поле.
Наконец, есть также способы изменять BeanDeserializer
экземпляры (путем регистрации BeanDeserializerModifier
) — вы могли бы подклассировать соответствующие компоненты (SettableBeanProperty, я думаю …), чтобы подключить дополнительную обработку, или даже заменить десериализатор для использования, сохраняя ссылку на исходный десериализатор по умолчанию.
Но, в конце концов, ваш случай звучит как нечто, с чем лучше всего справляется что-то другое: например, API проверки компонентов (jsr-303) кажется потенциально подходящим для логики последующей обработки. Поскольку она несколько ортогональна привязке данных, она могла бы быть превосходной альтернативой, поскольку она была бы независимой от привязки данных (jackson), многоразовой, все хорошее.
Комментарии:
1. Я не уверен, что с помощью Bean Validation API (jsr-303) возможно ли создавать логику при каждом вызове метода setter (обновлять поле экземпляра, например, счетчик) и по окончании десериализации выполнять какую-либо другую логику. Насколько я мог видеть, эта спецификация допускает (и предназначена) только для целей проверки. Есть другие предложения?
2. Правильно: не могу сделать это на наборах, поэтому, перечитав ваш вариант использования, это действительно не сработает. Я думаю, что BeanDeserializerModifier может тогда подойти — это требует немного сложного кода для изменения экземпляров SettableBeanProperty (которые выполняют фактическую работу для каждого поля), но было бы уместно добавить больше работы, поскольку вы знаете, о каком свойстве идет речь, значение устанавливается. Но вы могли бы повторно использовать существующий код для фактической привязки данных.
Ответ №2:
Другой способ — использовать @JsonCreator
для обозначения конструктора, который будет получать данные. Внутри конструктора у вас есть полный контроль над тем, как назначать их полям.