Serialize/Deserialize JSON Representations to Qt Objects (QObject’s) in C++
Calls to HTTP servers are very frequent nowadays, and JSON is frequently used when dealing with structured data. When I write applications in Java/Kotlin, I always use retrofit2 with gson integration, or similar approaches. It is very comfortable to be able to serialize/deserialize to Java objects automatically. I tried to find something similar for Qt, but I couldn’t find much. JSON support in Qt is good, but does not seem to be able to map QOject
‘s to QJSonObject
. I also could not find other C++ libraries doing this. Probably the difficulty of implementing reflection in C++ would make the implementation a bit convoluted. A good candidate I found is this: https://github.com/Loki-Astari/ThorsSerializer, which seems not to require much boilerplate code, not too verbose and no generated code.
However, Qt includes the meta object system (https://doc.qt.io/qt-5/metaobjects.html), and therefore I tried to use it to get the desired result. In a couple of hours I got to a pretty decent result: https://github.com/carlonluca/lqobjectserializer. It is far from perfect, but it seems to work. Have a look at the readme or the unit tests to know more. The draft is free to use: you can contribute, report bugs etc… For instance, a JSON object like this:
{"menu": { "header": "SVG Viewer", "items": [ {"id": "Open"}, {"id": "OpenNew", "label": "Open New"}, null, {"id": "ZoomIn", "label": "Zoom In"}, {"id": "ZoomOut", "label": "Zoom Out"}, {"id": "OriginalView", "label": "Original View"}, null, {"id": "Quality"}, {"id": "Pause"}, {"id": "Mute"}, null, {"id": "Find", "label": "Find..."}, {"id": "FindAgain", "label": "Find Again"}, {"id": "Copy"}, {"id": "CopyAgain", "label": "Copy Again"}, {"id": "CopySVG", "label": "Copy SVG"}, {"id": "ViewSVG", "label": "View SVG"}, {"id": "ViewSource", "label": "View Source"}, {"id": "SaveAs", "label": "Save As"}, null, {"id": "Help"}, {"id": "About", "label": "About Adobe CVG Viewer..."} ] }}
can be deserialized to a QObject
simply by defining the classes (macros here are inherited by my other project https://github.com/carlonluca/lqtutils, but this is not mandatory):
L_BEGIN_CLASS(Item) L_RW_PROP(QString, id, setId, QString()) L_RW_PROP(QString, label, setLabel, QString()) L_END_CLASS L_BEGIN_CLASS(Menu) L_RW_PROP(QString, header, setHeader) L_RW_PROP_ARRAY_WITH_ADDER(Item*, items, setItems) L_END_CLASS L_BEGIN_CLASS(MenuRoot) L_RW_PROP(Menu*, menu, setMenu, nullptr) L_END_CLASS
and by writing these few lines:
lqo::Deserializer<MenuRoot> deserializer; QScopedPointer<MenuRoot> g(deserializer.deserialize(jsonString));
Please leave a comment if you know of other tools in this context, serializing and deserializing JSON is very frequent.
Bye! 😉