Элегантное отображение из 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, чтобы ваши внутренние структуры сервера были довольно организованными и вряд ли будут узким местом производительности.
Когда и только когда эта стратегия становится узким местом производительности, вы достигли точки, чтобы разработать лучшее решение. Все, что до этого является преждевременной оптимизацией.
Мои два цента.