A library to perform generic seralization and deserialization of QObjects.
With this small library, you are able to serialize any QObject or Q_GADGET class to JSON and back. This is done with help of Qt's meta system.
- Serialize QObjects, Q_GADGETS, lists, maps, etc. to JSON, in a generic matter
- ... and of course deserialize JSON back as well
- De/serialize any QVariant - as long as it contains only basic types or one of the above
- Works even with QJsonValue/Array/Object as properties
- Serializes Q_PROPERTY elements
- Enum de/serialization as integer or as string
- Deserialization: Additional JSON-values will be stored as dynamic properties for QObjects
- Supports polymorphism
- Fully Unit-Tested
- Thread-Safe
- Easily extensible
There are multiple ways to install the Qt module, sorted by preference:
- Package Managers: The library is available via:
- Arch-Linux: AUR-Repository:
qt5-jsonserializer
- Ubuntu: Launchpad-PPA:
- Artful: ppa:skycoder42/qt-modules, package
libqt5jsonserializer[3/-dev]
- Xenial: ppa:skycoder42/qt-modules-opt, package
qtjsonserializer
- Artful: ppa:skycoder42/qt-modules, package
- MacOs:
- Tap:
brew tap Skycoder42/qt-modules
- Package:
qtjsonserializer
- IMPORTANT: Due to limitations of homebrew, you must run
source /usr/local/opt/qtjsonserializer/bashrc.sh
before you can use the module.
- Tap:
- Arch-Linux: AUR-Repository:
- Simply add my repository to your Qt MaintenanceTool (Image-based How-To here: Add custom repository):
- Open the MaintenanceTool, located in your Qt install directory (e.g.
~/Qt/MaintenanceTool
) - Select
Add or remove components
and click on theSettings
button - Go to
Repositories
, scroll to the bottom, selectUser defined repositories
and pressAdd
- In the right column (selected by default), type:
- Press
Ok
, make shureAdd or remove components
is still selected, and continue the install (Next >
) - A new entry appears under all supported Qt Versions (e.g.
Qt > Qt 5.8 > Skycoder42 Qt modules
) - You can install either all of my modules, or select the one you need:
Qt Json Serializer
- Continue the setup and thats it! you can now use the module for all of your installed Kits for that Qt Version
- Open the MaintenanceTool, located in your Qt install directory (e.g.
- Download the compiled modules from the release page. Note: You will have to add the correct ones yourself and may need to adjust some paths to fit your installation!
- Build it yourself! Note: This requires perl to be installed. If you don't have/need cmake, you can ignore the related warnings. To automatically build and install to your Qt installation, run:
qmake
make qmake_all
make
make install
The serializer is provided as a Qt module. Thus, all you have to do is install the module, and then, in your project, add QT += jsonserializer
to your .pro
file!
Both serialization and desertialization are rather simple. Create an object, and then use the serializer as follows:
The following is an example for a serializable object. Note: The usage of MEMBER
Properties is not required, and simply done to make this example more readable.
class TestObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString stringProperty MEMBER stringProperty)
Q_PROPERTY(QList<int> simpeList MEMBER simpeList)
Q_PROPERTY(TestObject* childObject MEMBER childObject)
public:
Q_INVOKABLE TestObject(QObject *parent = nullptr);
QString stringProperty;
QList<int> simpeList;
TestObject* childObject;
}
You can serialize (and deserialize) the object with:
auto serializer = new QJsonSerializer(this);
try {
//serialize
auto object = new TestObject();
object->stringProperty = "test";
object->simpeList = {1, 2, 3};
object->childObject = new TestObject(object);
auto json = serializer->serialize(object);
qDebug() << json;
delete object;
//deserialize
object = serializer->deserialize<TestObject>(json);//optional: specify the parent
qDebug() << object->stringProperty
<< object->simpeList
<< object->childObject;
delete object;
} catch(QJsonSerializerException &e) {
qDebug() << e.what();
}
For the serialization, the created json would look like this:
{
"stringProperty": "test",
"simpeList": [1, 2, 3],
"childObject": {
"stringProperty": "",
"simpeList": [],
"childObject": null
}
}
In order for the serializer to properly work, there are a few things you have to know and do:
- Only Q_PROPERTY properties will be serialized, and of those only properties that are marked to be stored (see The Property System, STORED attribute)
- For deserialization of QObjects, they need an invokable constructor, that takes only a parent:
Q_INVOKABLE MyClass(QObject*);
- Only the following types can be serialized:
QObject*
and deriving classes- Classes/structs marked with
Q_GADGET
(as value types only!) QList
, of any type that is serializable as wellQMap<QString, T>
, with T beeing any type that is serializable as well (string as key type is required)- Simple types, that are supported by QJsonValue (See QJsonValue::fromVariant and QJsonValue::toVariant)
Q_ENUM
andQ_FLAG
types, as integer or as string- The string de/serialization of Q_ENUM and Q_FLAG types only works if used as a Q_PROPERTY. Integer will always work.
QJson...
typesQPair<T, T>
, of any types that are serializable as well- Standard QtCore types (e.g. QPoint, QSize, QVersionNumber, ...)
- Any type you add yourself by extending the serializer
- While simple types (i.e.
QList<int>
) are supported out of the box, for custom types (likeQList<TestObject*>
) you will have to register converters. This goes for- QList and QMap: use
QJsonSerializer::registerAllConverters<T>()
- QList only: use
QJsonSerializer::registerListConverters<T>()
- QMap only: use
QJsonSerializer::registerMapConverters<T>()
- QPair: use
QJsonSerializer::registerPairConverters<T1, T2>()
- QSharedPointer/QPointer: use
QJsonSerializer::registerPointerConverters<T>()
- QList and QMap: use
- Polymorphic QObjects are supported. This is done by the serializer via adding a special
@@class
json property. To make a class polymorphic you can:- Add
Q_CLASSINFO("polymorphic", "true")
to its definition - Globally force polyphormism (See QJsonSerializer::polymorphing in the doc)
- Set a dynamic property:
setProperty("__qt_json_serializer_polymorphic", true);
- Add
- By default, the
objectName
property of QObjects is not serialized (See keepObjectName) - By default, the JSON
null
can only be converted to QObjects. For other types the conversion fails (See allowDefaultNull)
Right now, only QList
and QMap
ar supported as containers. The reason is, that adding containers requires the registration of converters. Supporting all containers would explode the generated binary, which is why I only support the most common ones.
If you need the other containers, you have 2 options:
- Implement a custom
QJsonTypeConverter
(You will still have to register all the converters). - Create "converter" properties that are used for serialization only. This is the more simple version, but needs to be done for every occurance of that container, and adds some overhead.
The following example shows how to do that to use QVector
in code, but serialize as QList
:
struct MyGadget {
Q_GADGET
Q_PROPERTY(QList<int> myIntVector READ getMyIntList WRITE setMyIntList) //normal property name, as this one appears in json
//Important: Add "STORED false":
Q_PROPERTY(QVector<int> myIntVectorInternal READ getMyIntVector WRITE setMyIntVector STORED false) //will not be serialized
public:
QVector<int> getMyIntVector() const;
void setMyIntVector(const QVector<int> &vector) ;
private:
QList<int> getMyIntList() const {
return getMyIntVector().toList();
}
void setMyIntList(const QList<int> &list) {
setMyIntVector(QVector<int>::fromList(list));
}
};
The documentation is available on github pages. It was created using doxygen. The HTML-documentation and Qt-Help files are shipped together with the module for both the custom repository and the package on the release page. Please note that doxygen docs do not perfectly integrate with QtCreator/QtAssistant.