Elegant mapping from POJOs to vertx.io's JsonObject?
I just submitted a patch to Vert.x that defines two new convenience functions for converting between JsonObject and Java object instances without the inefficiency of going through an intermediate JSON string representation. This will be in version 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)
Internally this uses ObjectMapper#convertValue(...)
, see Tim Putnam's answer for caveats of this approach. The code is here.
Not sure if I've understood you correctly, but it sounds like you're trying to find a simple way of converting POJOs to JsonObject?
So, we have lots of pojos that we send over the EventBus
as JsonObject
s
I've found the easiest way is to use the vert.x
Json
class which has loads of helper methods to convert to / from Json
Strings
JsonObject jsonObject = new JsonObject(Json.encode(myPojo));
Sometimes you need to add some custom (de)serializers, but we always stick with Jackson
- that is what Vert.x
is using so they work out of the box.
What we actually do, is provide an interface like the following:
public JsonObjectSerializable {
public JsonObject toJson();
}
And all our pojos that need to be sent over the EventBus
have to implement this interface.
Then our EventBus
sending code looks something like (simplified):
public <T extends JsonObjectSerializable> Response<T> dispatch(T eventPayload);
Also, as we generally don't unit test Pojos, adding this interface
encourages the developers to unit test their conversion.
Hope this helps,
Will
I believe Jackson's ObjectMapper.convertValue(..)
functions don't convert via String, and Vert.x is using Jackson for managing JsonObject anyway.
JsonObject
just has an underlying map representing the values, accessible via JsonObject.getMap()
, and a Jackson serializer/deserializer on the public ObjectMapper
instance in io.vertx.core.json.Json.
To switch between JsonObject
and a data model expressed in Pojos serializable with Jackson, you can do:
JsonObject myVertxMsg = ...
MyPojo pojo = Json.mapper.convertValue ( myVertxMsg.getMap(), MyPojo.class );
I would guess this is more efficient than going via a String (but its just a guess), and I hate the idea of altering the data class just to suit the environment, so it depends on the context - form vs performance.
To convert from Pojo to JsonObject
, convert to a map with Jackson and then use the constructor on JsonObject
:
JsonObject myobj = new JsonObject ( Json.mapper.convertValue ( pojo, Map.class ));
If you have implied nested JsonObjects or JsonArray objects in your definition, they will get instantiated as Maps and Lists by default. JsonObject will internally re-wrap these when you access fields specifying those types (e.g. with getJsonArray(..).
Because JsonObject is freeform and you're converting to a static type, you may get some unwanted UnrecognizedPropertyException to deal with. It may be useful to create your own ObjectMapper, add the vertx JsonObjectSerializer and JsonArraySerializer, and then make configuration changes to suit (such as
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
in Jackson).