Элегантное сопоставление POJO с JsonObject от vertx.io?

В настоящее время я работаю над приложением vertx.io и хочу использовать API Mongo для хранения данных. В настоящее время у меня есть довольно неуклюжая абстракция поверх стандартных классов JsonObject, где все методы get и set заменены такими вещами, как:

this.backingObject.get(KEY_FOR_THIS_PROPERTY);

Это все хорошо и хорошо на данный момент, но это не будет особенно хорошо масштабироваться. это также кажется грязным, особенно при использовании вложенных массивов или объектов. Например, если я хочу иметь возможность заполнять поля только тогда, когда известны фактические данные, я должен проверить, существует ли массив, и не создает ли он его и не сохраняет ли в объекте. Затем я могу добавить элемент в список. Например:

if (this.backingObject.getJsonArray(KEY_LIST) == null) {
    this.backingObject.put(KEY_LIST, new JsonArray());
}
this.backingObject.getJsonArray(KEY_LIST).add(p.getBackingObject());

Я думал о возможных решениях, но ни одно из них мне особенно не нравится. А именно, я мог использовать Gson или другую подобную библиотеку с поддержкой аннотаций для обработки загрузки объекта в целях управления данными в моем коде, а затем использовать функции сериализации и десериализации как Gson, так и Vertx для конвертировать между форматами (vertx to load data -> json string -> gson to parse json into pojos -> make changes -> serialize to json string -> parse with vertx and save), но это действительно грубый и неэффективный рабочий процесс. Я также, вероятно, мог бы придумать какую-то абстрактную оболочку, которая расширяет/реализует библиотеку vertx json, но передает всю функциональность gson, но это также кажется большой работой.

Есть ли хороший способ добиться более удобной и удобной сериализации с помощью vertx?


person grdaneault    schedule 17.08.2015    source источник


Ответы (6)


Я только что представил исправление для Vert.x, которое определяет две новые удобные функции для преобразования между экземплярами объектов JsonObject и Java без неэффективного прохождения через промежуточное строковое представление JSON. Это будет в версии 3.4.

// Create a JsonObject from the fields of a Java object.
// Faster than calling `new JsonObject(Json.encode(obj))`.
public static JsonObject mapFrom(Object obj)

// Instantiate a Java object from a JsonObject.
// Faster than calling `Json.decodeValue(Json.encode(jsonObject), type)`.
public <T> T mapTo(Class<T> type)

Внутри это использует ObjectMapper#convertValue(...), см. Ответ Тима Патнэма для предостережений этого подхода. Код здесь.

person Luke Hutchison    schedule 02.02.2017
comment
Хорошо знать. Кажется, официально принято на vertx.io/docs/apidocs/ io/vertx/core/json/JsonObject.html - person MarkHu; 14.07.2017

Я считаю, что функции ObjectMapper.convertValue(..) Джексона не преобразуются через String, и Vert.x все равно использует Джексона для управления JsonObject.

JsonObject просто имеет базовую карту, представляющую значения, доступные через JsonObject.getMap(), и сериализатор/десериализатор Джексона в общедоступном экземпляре ObjectMapper в io.vertx.core.json.Json.

Чтобы переключиться между JsonObject и моделью данных, выраженной в Pojos, сериализуемом с помощью Jackson, вы можете сделать:

JsonObject myVertxMsg = ... MyPojo pojo = Json.mapper.convertValue ( myVertxMsg.getMap(), MyPojo.class );

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

Чтобы преобразовать Pojo в JsonObject, преобразуйте его в карту с помощью Jackson, а затем используйте конструктор для JsonObject:

JsonObject myobj = new JsonObject ( Json.mapper.convertValue ( pojo, Map.class ));

  • Если вы указали в своем определении вложенные объекты JsonObjects или JsonArray, по умолчанию они будут созданы как карты и списки. JsonObject будет внутренне перепаковывать их при доступе к полям, указывающим эти типы (например, с помощью getJsonArray(..).

  • Поскольку JsonObject имеет произвольную форму и вы конвертируете его в статический тип, вы можете столкнуться с нежелательным UnrecognizedPropertyException. Может быть полезно создать свой собственный ObjectMapper, добавить вершины JsonObjectSerializer и JsonArraySerializer, а затем внести соответствующие изменения в конфигурацию (например, DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES в Джексоне).

person Tim Putnam    schedule 16.06.2016

Не уверен, правильно ли я вас понял, но похоже, что вы пытаетесь найти простой способ преобразования POJO в JsonObject?

Итак, у нас есть много pojos, которые мы отправляем через EventBus как JsonObject.

Я нашел самый простой способ - использовать класс vert.x Json, который имеет множество вспомогательных методов для преобразования в/из Json Strings

JsonObject jsonObject = new JsonObject(Json.encode(myPojo));

Иногда вам нужно добавить некоторые пользовательские (де)сериализаторы, но мы всегда придерживаемся Jackson — это то, что использует Vert.x, поэтому они работают из коробки.

Что мы на самом деле делаем, так это предоставляем интерфейс, подобный следующему:

public JsonObjectSerializable {
    public JsonObject toJson();
}

И все наши pojos, которые нужно отправить через EventBus, должны реализовать этот интерфейс.

Тогда наш код отправки EventBus выглядит примерно так (упрощенно):

public <T extends JsonObjectSerializable> Response<T> dispatch(T eventPayload);

Кроме того, поскольку мы обычно не проводим модульное тестирование Pojos, добавление этого interface поощряет разработчиков к модульному тестированию своей конверсии.

Надеюсь это поможет,

Буду

person Will    schedule 19.08.2015
comment
Это уже то, что предложил @Grdaneault, сказав: «(vertx для загрузки данных —> строка json —> gson для синтаксического анализа json в pojos —> внести изменения —> сериализовать в строку json —> выполнить синтаксический анализ с помощью vertx и сохранить)', и вы только что заменили Gson на Jackson. - person tmarwen; 19.08.2015
comment
Да. Я думаю, это кажется довольно разумным, но все еще кажется грязным преобразовывать в строку в качестве посредника. Я думаю, что на данный момент резервный объект - это путь. Возможно, я смогу подключить что-то с отражением, чтобы автоматически отображать, по крайней мере, примитивные поля. Я просто не хотел бы изобретать велосипед, если что-то уже есть - person grdaneault; 20.08.2015
comment
@Grdaneault Я понимаю. Хотя мне любопытно, почему вам не нравится использовать String. - person Will; 20.08.2015
comment
Я уверен, что алгоритмы создания и синтаксического анализа строк были оптимизированы их соответствующими владельцами, но по-прежнему кажется, что преобразование всех данных в строку только для того, чтобы вернуть их обратно, потребовало бы больших накладных расходов. Хотя кажется, что это может быть самый простой способ - person grdaneault; 20.08.2015
comment
Это выглядит очень неэффективно: он сериализует объект myPojo в JSON, затем десериализует (при вызове конструктора JsonObject), затем повторно сериализует (после сериализации JsonObject для отправки по сети). - person Luke Hutchison; 22.01.2017
comment
Хм? Как мы десериализуем строку в POJO? - person Alexander Mills; 28.01.2019

Попробуй это:

io.vertx.core.json.Json.mapper.convertValue(json.getMap(), cls)
person fengbugou    schedule 03.01.2017

Я думаю, что использование Gson, как вы описали, является лучшим решением в настоящее время.

Хотя я согласен с тем, что если бы уровень протокола был включен в Vert.x, это действительно было бы первым призом, использование Gson обеспечивает хорошую организацию внутренних компонентов вашего сервера и вряд ли станет узким местом в производительности.

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

Мои два цента.

person Daniel Gerson    schedule 17.11.2017

Можешь попробовать:

new JsonObject().mapFrom(object)
person imaya    schedule 29.11.2019