A library to perform generic seralization and deserialization of QObjects from and to JSON and CBOR.
With this small library, you are able to serialize any C++ datatype to JSON or CBOR and back. This is done with help of Qt's meta system.
The library was recently update to 4.0.0. Have a look at the Porting section to learn how to migrate your project from 3.* to 4.0.0. Don't be afraid, as for most existing projects, only class names will have changed.
There are multiple ways to install the Qt module, sorted by preference:
qt5-jsonserializer
brew tap Skycoder42/qt-modules
qtjsonserializer
source /usr/local/opt/qtjsonserializer/bashrc.sh
before you can use the module./path/to/MaintenanceTool --addRepository <url>
with one of the following urls (Alternatively you can add it via the GUI, as stated in the previously linked GUI):
Qt > Qt 5.13 > Skycoder42 Qt modules
)Qt JsonSerializer
git clone
or download from the releases. If you choose the second option, you have to manually create a folder named .git
in the projects root directory, otherwise the build will fail.qmake
make
(If you want the tests/examples/etc. run make all
)make doxygen
to generate the documentationmake -j1 run-tests
to build and run all testsmake install
By default, a bunch of list, map, etc. converters are registered for standard Qt types via the qtJsonSerializerRegisterTypes
method. This however needs many generated functions and will increase the size of the generated binary drasticly. If you don't need those converters, run qmake CONFIG+=no_register_json_converters
instead of a parameterless qmake. The mentioned function will then be generated as noop method and no converters are registerd.
Please be aware that in this mode it is not possible to serialize e.g. QList<int>
unless you manually register the corresponding converters via QtJsonSerializer::JsonSerializer::registerListConverters<int>();
!
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! The following chapters show an example and explain a few important details regarding the functionality and limits of the implementation.
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.
You can serialize (and deserialize) the object with:
For the serialization, the created json would look like this:
In order for the serializer to properly work, there are a few things you have to know and do:
Q_INVOKABLE MyClass(QObject*);
QObject*
and deriving classesQ_GADGET
(as value or plain pointer only!)QList<T>
, QLinkedList<T>
, QVector<T>
, QStack<T>
, QQueue<T>
, QSet<T>
, with T beeing any type that is serializable as wellQMap<QString, T>
, QHash<QString, T>
, QMultiMap<QString, T>
, QMultiHash<QString, T>
, with T beeing any type that is serializable as well (string as key type is required)Q_ENUM
and Q_FLAG
types, as integer or as stringQJson...
typesQPair<T1, T2>
and std::pair<T1, T2>
, of any types that are serializable as wellstd::tuple<TArgs...>
, of any types that are serializable as wellstd::optional<T>
, of any type that is serializable as wellstd::variant<TArgs...>
, of any types that are serializable as wellstd::chrono::*
, for the basic times (hours, minutes, seconds, milliseconds, microseconds, nanoseconds)QList<int>
) are supported out of the box, for custom types (like QList<TestObject*>
) you will have to register converters. This goes forSerializerBase::registerBasicConverters<T>()
SerializerBase::registerListConverters<T>()
SerializerBase::registerSetConverters<T>()
SerializerBase::registerMapConverters<T>()
SerializerBase::registerPairConverters<T1, T2>()
SerializerBase::registerTupleConverters<TArgs...>()
SerializerBase::registerOptionalConverters<T>()
SerializerBase::registerVariantConverters<TArgs...>()
SerializerBase::registerPointerConverters<T>()
Q_JSON_POLYMORPHIC(true)
(or Q_CLASSINFO("polymorphic", "true")
) to its definitionsetProperty("__qt_json_serializer_polymorphic", true);
objectName
property of QObjects is not serialized (See keepObjectName)null
can only be converted to QObjects. For other types the conversion fails (See allowDefaultNull)While the default Qt containers, like QList
, QVector
and QMap
are all supported by default, custom containers need to be registered. For this, two steps need to happen:
Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE
QtJsonSerializer::SequentialWriter::registerWriter<Container, Type>()
Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE
QtJsonSerializer::AssociativeWriter::registerWriter<Container, Key, Value>()
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.
Most changes to the library have been of additive nature. The following list summarizes the most important changes:
The next sections will talk about specific changes and how to adjust your project. Also, if you have any questions or need help porting your project, I am always happy to help. Just create a new Issue asking for help, and it shall be given.
One big part of the 4.0.0 release was to move all types into a namespace and get rid of the QJson
prefix. The following table shows how types have been renamed. If you do not want to change all usages in your code, simply use using
declarations for the types, i.e. using QJsonSerializer = QtJsonSerializer::JsonSerializer;
.
Old name | New name |
---|---|
QJsonSerializerException | QtJsonSerializer::Exception |
QJsonDeserializationException | QtJsonSerializer::DeserializationException |
QJsonSerializationException | QtJsonSerializer::SerializationException |
QJsonSerializer | QtJsonSerializer::JsonSerializer (split into that class and the base class QtJsonSerializer::SerializerBase) |
QJsonTypeConverter | QtJsonSerializer::TypeConverter |
With the new system, typedefs
are no longer a problem, as now, an advanced type registration system is used to get types instead of parsing class names. Thus, all related methods have been removed. Furthermore, the old system of converting various datatypes from and to a non-generic QVariant
representation via QMetaType
has been superseeded by the QtJsonSerializer::TypeExtracor
system. For most usecases this changes nothing, as the QtJsonSerializer::SerializerBase::register*
methods still exist. However, if you made use of the old system in custom converters, you should consider migrating to using either the QtJsonSerializer::MetaWriter
mechanism for containers, or the QtJsonSerializer::TypeExtracor
for other types. Check the documentation on how to use these classes.
One additional advantage of the new system is, that now theoretically any sequential or associative container can be supported by the serializer without the need of a custom converter. Alls that is needed is a simple registration of a custom container class within the QtJsonSerializer::MetaWriter
classes as well as the type declaration (See Support for alternative Containers). The following shows a simple example for std::vector
The biggest feature however is support for de/serialization of CBOR data. Usage is the same as for JSON, simply use QtJsonSerializer::CborSerializer
instead of the QtJsonSerializer::JsonSerializer
class. Nothing more to say here - simply try it out!
If you previously had your own QJsonTypeConverter
(now called QtJsonSerializer::TypeConverter
), the changes are slightly more complex. The primary change was, that all these converter now operate on CBOR data, not JSON, as CBOR can be easily converted to JSON, but not the other way around. Check the QtJsonSerializer::TypeConverter documentation for more details on how to use these new converters.