A while ago I wanted to implement save and load for an application.

The application model was a QObject derived class, with a bunch of sub (-sub) classes. As the UI was QML, everything was accessible through properties.

Instead of writing a save and load mechanism for every single class, I was able to write one generic save load mechanism.

This can be done using QObject introspection/reflection. So the class name, properties and member functions can be queried.

For example if you have this class derived from QObject:

class SomeQObject : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int id READ id WRITE setId NOTIFY idChanged)
public:
    int id() const;
    void setId();
signals:
    void idChanged();
};

To get the class name you do the following:

SomeQObject obj;
const QMetaObject* metaObj = obj->metaObject();
QString className = metaObj->className();

Then className is “SomeQObject”.

And to query for the properties you do the following:

for (int i = 0; i < metaObj->propertyCount(); ++i) {
    const char* propertyName = metaObj->property(i).name();
    QVariant value = obj.property(propertyName);
}

For querying QObject dynamic properties, the code looks a bit different:

for (const QByteArray& propertyName : obj->dynamicPropertyNames()) {
    QVariant value = obj->property(propertyName.data()));
}

Using QObject’s setProperty() function one can set the property as well.

Methods can be queried using

for (int i = 0; i < metaObj->methodCount(); ++i) {
    QMetaMethod method = metaObj->method(i);
}

I used this, to serialize and deserialize a QObject to a JSON text file. It’s pretty simple using Qt’s JSON support.

The code can be found here:

https://gitlab.com/vikingsoft/blog-qobject-serialize

This code works quite well for my needs, but is in no way finished. For example several types like QRect are not supported.

The nice thing is, that this library does not need to know anything about the objects that it’s handling. As long they are derived from QObject. And for the deserialization, only a tiny factory method is needed to create the object. Im my case I used simple lambda functions.

So absolutely no change is needed in the QObject derived classes themselves. And if a class changes, as for example a property is added, nothing needs to be done to handle that property as well. It’s done automatically.

One can continue to extend the app model. The save/load just keeps working.

But you are not limited to loading/saving with JSON. Using this JSON transformation, you could transfer the QObject tree over the network. Even transferring rather complex data would be a breeze.

And it’s not limited to using JSON. Using for example XML would be possible as well.