QtJsonSerializer  4.0.0
A library to perform generic seralization and deserialization of QObjects
Classes | Public Types | Public Member Functions | Static Public Attributes | List of all members
QtJsonSerializer::TypeConverter Class Referenceabstract

An interface to create custom serializer type converters. More...

#include <typeconverter.h>

Classes

class  SerializationHelper
 Helper class passed to the type converter by the serializer. Do not implement yourself. More...
 

Public Types

enum  Priority : int {
  ExtremlyLow = -0x00FFFFFF, VeryLow = -0x0000FFFF, Low = -0x000000FF, Standard = 0x00000000,
  High = 0x000000FF, VeryHigh = 0x0000FFFF, ExtremlyHigh = 0x00FFFFFF
}
 Sample values for a priority value (default converters are mostly Standard and are guaranteed to be between Low and High)
 
enum  DeserializationCapabilityResult : int { Positive = 1, Guessed = 2, Negative = -1, WrongTag = -2 }
 The possible results of canDeserialize(), used internally only. More...
 

Public Member Functions

 TypeConverter ()
 Constructor.
 
virtual ~TypeConverter ()
 Destructor.
 
virtual QByteArray name () const =0
 The name of the converter. Used for debugging purpose.
 
int priority () const
 Returns the priority of this converter. More...
 
void setPriority (int priority)
 Sets the priority of this converter. More...
 
const SerializationHelperhelper () const
 Returns the helper associated with this converter. More...
 
virtual bool canConvert (int metaTypeId) const =0
 Returns true, if this implementation can convert the given type. More...
 
virtual QList< QCborTag > allowedCborTags (int metaTypeId) const
 Returns a list of allowed tags for the given type. More...
 
virtual QList< QCborValue::Type > allowedCborTypes (int metaTypeId, QCborTag tag) const =0
 Returns a list of allowed types for the given type and tag. More...
 
virtual int guessType (QCborTag tag, QCborValue::Type dataType) const
 Returns a type guessed from the tag and data, that is supported by the converter. More...
 
virtual QCborValue serialize (int propertyType, const QVariant &value) const =0
 Called by the serializer to serializer your given type to CBOR. More...
 
virtual QVariant deserializeCbor (int propertyType, const QCborValue &value, QObject *parent) const =0
 Called by the serializer to deserializer your given type from CBOR. More...
 
virtual QVariant deserializeJson (int propertyType, const QCborValue &value, QObject *parent) const
 Called by the serializer to deserializer your given type from JSON. More...
 

Static Public Attributes

static constexpr auto NoTag = static_cast<QCborTag>(std::numeric_limits<std::underlying_type_t<QCborTag>>::max())
 A placeholder tag to be used if no tag is expected/allowed/given.
 

Detailed Description

An interface to create custom serializer type converters.

If you have a custom class, that cannot be serialized with the converters the library has built in, you will need to create a custom type converter in order to handle your type. Implement this interface for your custom type, and add it to a serializer instance by calling SerializerBase::addJsonTypeConverter.

Attention
Most types are already covered by the converters internally used by the library. To find out if you custom type is already supported by what the library provides, either try it out out or check your class against the list found in the Usage Hints. You don't need a custom converter for most types.

Example

To understand how it works, here is a small example for a custom type converter. First, the definition of the custom class.

Note
A class like this could be easily defined as Q_GADGET, and thus would not need a custom converter. It is only done without the gadget to demonstrate how a converter could look like.

Setup

class Foo
{
public:
Foo(int salt, QObject *object);
// destructor, other methods, etc...
private:
int salt;
QObject *object;
};
Q_DECLARE_METATYPE(Foo) // important

This class is neither a gadget nor an object, and thus be default not serializable. For this example, we want to get the following json out of the serializer for this type:

{
"salt": <number>
"object": <whatever QObject* serializes to>
}

In case of a CBOR serialization, it should be equivalent, but tagged with our custom CBOR tag:

static const QCborTag FooTag = static_cast<QCborTag>(4711);

The Converter class

To do this, we implement our custom type converter:

class FooConverter : public QtJsonSerializer::TypeConverter
{
public:
// required methods
bool canConvert(int metaTypeId) const override;
QList<QCborValue::Type> allowedCborTypes(int metaTypeId, QCborTag tag) const override;
QCborValue serialize(int propertyType, const QVariant &value) const override;
QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override;
// optional methods
QList<QCborTag> allowedCborTags(int metaTypeId) const override;
int guessType(QCborTag tag, QCborValue::Type dataType) const override;
QVariant deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const override;
};

There are 4 required methods to be implemented. In addition to that, there is also the TypeConverter::priority. It is not relevant for this example, but might be for your special case. For certain use cases, some of the three optional methods may also be required

The <tt>canConvert</tt> method

This method is called be the serializer to determine whether your converter can handle a specific type or not. In our case, all that needs to be done is to check if the passed type is our Foo type:

bool FooConverter::canConvert(int metaTypeId) const
{
return metaTypeId == qMetaTypeId<Foo>();
}

The <tt>allowedCborTypes</tt> method

This method is called be the serializer to determine which cbor or types your converter can deserialize. For the example, we serialize to a json object (or cbor map), and thus can only deserialize objects/maps as well.

QList<QCborValue::Type> FooConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const
{
Q_UNUSED(metaTypeId); // not used because we only support one type
Q_UNUSED(tag); // not used, as the type is the same for all tags (FooTag and no tag at all)
return {QCborValue::Map};
}

As you can see, we only need to provide the CBOR type. The json type is autmatically derived from the CBOR type, according to the CBOR specification.

The <tt>serialize</tt> method

This method contains the actual code to convert our c++ Foo object into a CBOR value. As CBOR can be converter to JSON automatically, and to ensure compability between the CBOR and JSON representation of data, only a conversion to CBOR is needed. The data is the converter to JSON if needed, using the standard CBOR rules.

The implementation is easy for the interger type salt, as CBOR has numbers. But for the object, we want the serializer to do the work for as. To do this, we make use of the SerializationHelper that is available via the helper() method.

QCborValue FooConverter::serialize(int propertyType, const QVariant &value) const
{
auto foo = value.value<Foo>(); // convert the QVariant parameter to our Foo type
QCborMap fooCbor; // create the cbor
fooCbor["salt"] = foo.salt;
fooCbor["object"] = helper()->serializeSubtype(QMetaType::QObjectStar, QVariant::fromValue(foo.object), "object");
return {FooTag, fooCbor}; // return data with tag. The tag is dropped for JSON
}

We pass 3 arguments to the SerializationHelper::serializeSubtype method. The first one is the type of what we want to get serialized. In this case, a pointer to QObject. The second is the actual value, converted to QVariant. The third parameter is a hint in case of an exception. It basically means: If something goes wrong it was somewhere in the "object" field of the Foo class.

Note
If you need to do error handling, i.e. fail in case of an error, do so by throwing a SerializationException

The <tt>deserializeCbor</tt> method

This method contains the actual code to convert a CBOR object into our c++ Foo object. Again, since JSON and CBOR are compatible, JSON data is simply converted to CBOR and then handled by this method. However, some types need special handline, which is why the deserializeJson() is provided as well. See The deserializeJson method for more details

This is easy for the interger type salt, as cbor has numbers. But for the object, we want the serializer to do the work for as. To do this, we make use of the SerializationHelper that is available via the helper() method.

QVariant FooConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const
{
Q_UNUSED(parent); // not used because we own the object
// Get the map from the value. Make sure to account for tagged values
auto cMap = (value.isTag() ? value.taggedValue() : value).toMap();
// check if salt is what you expect it to be
if (!cMap["salt"].isInteger())
throw DeserializationException("No cbor valued named salt with number type");
auto object = helper()->deserializeSubtype(QMetaType::QObjectStar, cMap["object"], nullptr, "object");
Foo foo(jsonFoo["salt"].toInteger(), object);
return QVariant::fromValue(foo);
}

We pass 4 arguments to the SerializationHelper::serializeSubtype method. The first one is the type of what we want to get deserialized. In this case, a pointer to QObject. The second is the actual cbor value. The third argument is parent for the QObject. In our case, the Foo class owns the object, and thus the object should not have a parent, and we pass nullptr. The fourth parameter is a hint in case of an exception. It basically means: If something goes wrong it was somewhere in the "object" field of the Foo class.

Note
If you need to do error handling, i.e. fail in case of an error, do so by throwing a DeserializationException

The <tt>allowedCborTags</tt> method

In some cases, you want your CBOR data to be tagged. The The serialize method section already shows how to tag data. For deserialization however, you may want to verify your data to make sure only data with a correct tag can be deserialized. Thats what the allowedCborTags method is for. For JSON deserialization, this method is ignored.

QList<QCborTag> FooConverter::allowedCborTags(int metaTypeId) const
{
Q_UNUSED(metaTypeId); // not used because we only support one type
return {NoTag, FooTag}; // only allow CBOR data with the FooTag tag or no tag at all
}
Note
Not having a tag is always allowed by default, even if your list does not contain the NoTag. To force failures in such cases, set the SerializerBase::ValidationFlag::StrictBasicTypes flag via SerializerBase::validationFlags.

The <tt>guessType</tt> method

If your converter supports certain tags, you might be able to guess the C++ type from the tag. This can be very useful, when deserializing data without knowing the C++ type to deserialize it to. Since JSON has no tags, this method is ignored for json deserialization.

int FooConverter::guessType(QCborTag tag, QCborValue::Type dataType) const
{
// make shure both tag and type match
if (tag == FooTag && dataType == QCborValue::Map)
return qMetaTypeId<Foo>(); // return Foo as guessed type
else
return QMetaType::UnknownType; // no guess for all other cases
}

The <tt>deserializeJson</tt> method

In some rare cases, important information is lost when converting from cbor to JSON. For example, if you use a QByteArray, it is converted to a base64url encoded string when converted to JSON. To deserialize such a value, extra information is needed, as the CBOR parser does not know the read data is a bytearray and not just a string.

You can use the deserializeJson() to handle such special cases:

QVariant FooConverter::deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const
{
if (value.isString())
// convert to bytearray
else
return deserializeCbor(propertyType, value, parent);
}
See also
QJsonSerializer::addJsonTypeConverter

Definition at line 39 of file typeconverter.h.

Member Enumeration Documentation

◆ DeserializationCapabilityResult

The possible results of canDeserialize(), used internally only.

Enumerator
Positive 

The converter can deserialize the given data.

Guessed 

The converter guessed a type for the given data.

Negative 

The converter cannot deserialize the given data.

WrongTag 

The converter could deserialize the given data, but the tag does not match.

Definition at line 58 of file typeconverter.h.

Member Function Documentation

◆ allowedCborTags()

QtJsonSerializer::TypeConverter::allowedCborTags ( int  metaTypeId) const
virtual

Returns a list of allowed tags for the given type.

Parameters
metaTypeIdThe id of the type to get tags for
Returns
A list of tags that are allowed for the given type

If your converter uses tags, use this method to return relevant tags. If the list does not contain NoTag, deserialization will fail if the data has either no tag (only for strict deserialization) or a tag not in this list. Adding NoTag to the list makes sure data without a tag is always allowed even for the strict mode.

See also
Example Example, TypeConverter::canConvert, TypeConverter::allowedCborTypes, TypeConverter::guessType

◆ allowedCborTypes()

QtJsonSerializer::TypeConverter::allowedCborTypes ( int  metaTypeId,
QCborTag  tag 
) const
pure virtual

Returns a list of allowed types for the given type and tag.

Parameters
metaTypeIdThe id of the type to get types for
tagThe CBOR tag of the data to get types for
Returns
A list of all supported cbor types for deserialization

The list should contain all types that are allowed for this specific type/tag combination. Your implementation must be able to deserialize any combination of the returned types and the given metaTypeId/tag. You can ignore the tag if you don't care about tags and the type if your converter only supports one type.

For JSON deserialization, the types are converter to JSON according to the table from QCborValue::toJsonValue

See also
Example Example, TypeConverter::canConvert, TypeConverter::allowedCborTags, TypeConverter::guessType, QCborValue::toJsonValue

◆ canConvert()

QtJsonSerializer::TypeConverter::canConvert ( int  metaTypeId) const
pure virtual

Returns true, if this implementation can convert the given type.

Parameters
metaTypeIdThe id of the type to be converted
Returns
true, if this converter can convert the given type, false otherwise

If you return true for this method, it is expected your implementation can successfully de/serialize any valid instance for the given type. If you can't, serialization will fail, and no other converter get's a chance to try

See also
Example Example, TypeConverter::allowedCborTypes

◆ deserializeCbor()

QtJsonSerializer::TypeConverter::deserializeCbor ( int  propertyType,
const QCborValue value,
QObject parent 
) const
pure virtual

Called by the serializer to deserializer your given type from CBOR.

Parameters
propertyTypeThe type of the data to deserialize
valueThe value to deserialize, as cbor value
parentA parent object, in case you create a QObject class you can pass it as parent
Returns
The deserialized data, wrapped as QVariant
Exceptions
DeserializationExceptionIn case something goes wrong, invalid data, etc.

This method contains your actual converter code to transform CBOR (or JSON) data to a C++ data type to the. Use the helper() and given inputs to perform that conversion.

See also
Example Example, TypeConverter::serialize, SerializationHelper

◆ deserializeJson()

QtJsonSerializer::TypeConverter::deserializeJson ( int  propertyType,
const QCborValue value,
QObject parent 
) const
virtual

Called by the serializer to deserializer your given type from JSON.

Parameters
propertyTypeThe type of the data to deserialize
valueThe value to deserialize, as cbor value
parentA parent object, in case you create a QObject class you can pass it as parent
Returns
The deserialized data, wrapped as QVariant
Exceptions
DeserializationExceptionIn case something goes wrong, invalid data, etc.

This method contains your actual converter code to transform CBOR (or JSON) data to a C++ data type to the. Use the helper() and given inputs to perform that conversion.

See also
Example Example, TypeConverter::serialize, SerializationHelper

◆ guessType()

QtJsonSerializer::TypeConverter::guessType ( QCborTag  tag,
QCborValue::Type  dataType 
) const
virtual

Returns a type guessed from the tag and data, that is supported by the converter.

Parameters
tagThe CBOR tag of the data to get the C++ type for
dataTypeThe CBOR data type of the data to get the C++ type for
Returns
A valid type id or QMetaType::UnknownType

If your converter supports tags, and you deserialize data without providing the C++ type to deserialize it to, this method is used to guess the C++ type from the tag and the data type.

If you support a combination of a tag and data type, and it matches a unique C++ type your converter supports, return the metaTypeId of that type. Otherwise return QMetaType::UnknownType to indicate your converter does not understand the data.

See also
Example Example, TypeConverter::canConvert, TypeConverter::allowedCborTags, TypeConverter::allowedCborTypes

◆ helper()

QtJsonSerializer::TypeConverter::helper ( ) const

Returns the helper associated with this converter.

Returns
The helper instance

The helper returned by this method is always valid, except from the constructor. It can be used to de/serialize subtypes and obtain other information useful for a converter from the serializer that is using the converter.

See also
TypeConverter::setHelper, TypeConverter::SerializationHelper

◆ priority()

QtJsonSerializer::TypeConverter::priority ( ) const

Returns the priority of this converter.

Returns
The priority of the converter

The priority is important for cases where multiple converters can handle the same type. The converter with the highest priority wins. The default value is 0, and so are all converters internally used by the library. The property can be set either by your implementation (i.e. in the constructor), or dynamically before adding the converter to a serializer.

See also
QJsonTypeConverter::Priority, QJsonTypeConverter::setPriority

◆ serialize()

QtJsonSerializer::TypeConverter::serialize ( int  propertyType,
const QVariant value 
) const
pure virtual

Called by the serializer to serializer your given type to CBOR.

Parameters
propertyTypeThe type of the data to serialize
valueThe value to serialize, wrapped as QVariant
Returns
A CBOR value with the serialized data of value
Exceptions
SerializationExceptionIn case something goes wrong, invalid data, etc.

This method contains your actual converter code to transform a C++ data type to the CBOR representation. Use the helper() and given inputs to perform that conversion.

See also
Example Example, TypeConverter::deserialize, SerializationHelper

◆ setPriority()

QtJsonSerializer::TypeConverter::setPriority ( int  priority)

Sets the priority of this converter.

Parameters
priorityThe priority of the converter

The priority is important for cases where multiple converters can handle the same type. The converter with the highest priority wins. The default value is 0, and so are all converters internally used by the library. The property can be set either by your implementation (i.e. in the constructor), or dynamically before adding the converter to a serializer.

See also
QJsonTypeConverter::Priority, QJsonTypeConverter::priority

The documentation for this class was generated from the following files:
QCborValue::isString
bool isString() const const
QVariant::fromValue
QVariant fromValue(const T &value)
QCborValue::isTag
bool isTag() const const
QVariant::value
T value() const const
QtJsonSerializer::TypeConverter::deserializeCbor
virtual QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const =0
Called by the serializer to deserializer your given type from CBOR.
QtJsonSerializer::TypeConverter::allowedCborTags
virtual QList< QCborTag > allowedCborTags(int metaTypeId) const
Returns a list of allowed tags for the given type.
QList
QCborValue::taggedValue
QCborValue taggedValue(const QCborValue &defaultValue) const const
QtJsonSerializer::TypeConverter::SerializationHelper::serializeSubtype
virtual QCborValue serializeSubtype(const QMetaProperty &property, const QVariant &value) const =0
Serialize a subvalue, represented by a meta property.
QtJsonSerializer::TypeConverter::NoTag
static constexpr auto NoTag
A placeholder tag to be used if no tag is expected/allowed/given.
Definition: typeconverter.h:44
QCborValue
QtJsonSerializer::TypeConverter::serialize
virtual QCborValue serialize(int propertyType, const QVariant &value) const =0
Called by the serializer to serializer your given type to CBOR.
QtJsonSerializer::TypeConverter::allowedCborTypes
virtual QList< QCborValue::Type > allowedCborTypes(int metaTypeId, QCborTag tag) const =0
Returns a list of allowed types for the given type and tag.
QtJsonSerializer::TypeConverter::deserializeJson
virtual QVariant deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const
Called by the serializer to deserializer your given type from JSON.
QtJsonSerializer::TypeConverter::SerializationHelper::deserializeSubtype
virtual QVariant deserializeSubtype(const QMetaProperty &property, const QCborValue &value, QObject *parent) const =0
Deserialize a subvalue, represented by a meta property.
QtJsonSerializer::TypeConverter::canConvert
virtual bool canConvert(int metaTypeId) const =0
Returns true, if this implementation can convert the given type.
QtJsonSerializer::TypeConverter
An interface to create custom serializer type converters.
Definition: typeconverter.h:39
QCborMap
QVariant
QObject
QtJsonSerializer::TypeConverter::guessType
virtual int guessType(QCborTag tag, QCborValue::Type dataType) const
Returns a type guessed from the tag and data, that is supported by the converter.
QtJsonSerializer::TypeConverter::helper
const SerializationHelper * helper() const
Returns the helper associated with this converter.