Элегантное отображение из POJO в vertx.io JsonObject?

В настоящее время я работаю над приложением vertx.io и хотел бы использовать mongo api для хранения данных. В настоящее время у меня довольно неуклюжая абстракция поверх классов 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 или некоторую подобную библиотеку с поддержкой аннотаций для обработки загрузки объекта с целью манипулирования данными в моем коде, а затем с помощью функции serialize и unserialize как 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?

Ответ 1

Я только что отправил патч в 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(...), см. комментарий Тима Путнэма для предостережений этого подхода. Код здесь.

Ответ 2

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

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

Я нашел самый простой способ использовать класс 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);

Кроме того, как мы обычно не делаем unit test Pojos, добавление этого interface поощряет разработчиков к unit test их преобразованию.

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

Воля

Ответ 3

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

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

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

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

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

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

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

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

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

Ответ 4

Попробуйте следующее:

io.vertx.core.json.Json.mapper.convertValue(json.getMap(), cls)

Ответ 5

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

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

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

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