| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- #ifndef QTJSONSERIALIZER_SERIALIZERBASE_H
- #define QTJSONSERIALIZER_SERIALIZERBASE_H
- #include "qtjsonserializer_global.h"
- #include "exception.h"
- #include "metawriters.h"
- #include "qtjsonserializer_helpertypes.h"
- #include "typeconverter.h"
- #include "typeextractors.h"
- #include <tuple>
- #include <optional>
- #include <variant>
- #include <QtCore/qobject.h>
- #include <QtCore/qmetaobject.h>
- #include <QtCore/qcborvalue.h>
- #include <QtCore/qvariant.h>
- #include <QtCore/qsharedpointer.h>
- #include <QtCore/qpointer.h>
- #include <QtCore/qlist.h>
- #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- #include <QtCore/qlinkedlist.h>
- #endif
- #include <QtCore/qvector.h>
- #include <QtCore/qset.h>
- #include <QtCore/qqueue.h>
- #include <QtCore/qstack.h>
- #include <QtCore/qhash.h>
- #include <QtCore/qmap.h>
- namespace QtJsonSerializer {
- class SerializerBasePrivate;
- //! A base class for the CBOR/JSON serializers
- class Q_JSONSERIALIZER_EXPORT SerializerBase : public QObject, protected TypeConverter::SerializationHelper
- {
- Q_OBJECT
- //! Specifies whether null for value types is allowed or not
- Q_PROPERTY(bool allowDefaultNull READ allowDefaultNull WRITE setAllowDefaultNull NOTIFY allowDefaultNullChanged)
- //! Specifies whether the `objectName` property of QObjects should be serialized
- Q_PROPERTY(bool keepObjectName READ keepObjectName WRITE setKeepObjectName NOTIFY keepObjectNameChanged)
- //! Specifies whether enums should be serialized as integer or as string
- Q_PROPERTY(bool enumAsString READ enumAsString WRITE setEnumAsString NOTIFY enumAsStringChanged)
- //! Specifies whether enums should be serialized as array of integers or as string
- Q_PROPERTY(bool versionAsString READ versionAsString WRITE setVersionAsString NOTIFY versionAsStringChanged)
- //! Specifies whether datetimes should be serialized as datetime string or as unix timestamp
- Q_PROPERTY(bool dateAsTimeStamp READ dateAsTimeStamp WRITE setDateAsTimeStamp NOTIFY dateAsTimeStampChanged)
- //! Specifies whether serializing a QLocale should use the bcp47 format
- Q_PROPERTY(bool useBcp47Locale READ useBcp47Locale WRITE setUseBcp47Locale NOTIFY useBcp47LocaleChanged)
- //! Specifies how strictly the serializer should verify data when deserializing
- Q_PROPERTY(ValidationFlags validationFlags READ validationFlags WRITE setValidationFlags NOTIFY validationFlagsChanged)
- //! Specifies how the serializer should treat polymorphism for QObject classes
- Q_PROPERTY(Polymorphing polymorphing READ polymorphing WRITE setPolymorphing NOTIFY polymorphingChanged)
- //! Specifies how multi maps and sets should be serialized
- Q_PROPERTY(MultiMapMode multiMapMode READ multiMapMode WRITE setMultiMapMode NOTIFY multiMapModeChanged)
- //! Specifies whether the STORED attribute on properties has any effect
- Q_PROPERTY(bool ignoreStoredAttribute READ ignoresStoredAttribute WRITE setIgnoreStoredAttribute NOTIFY ignoreStoredAttributeChanged)
- public:
- //! Flags to specify how strict the serializer should validate when deserializing
- enum class ValidationFlag {
- StandardValidation = 0x00, //!< Do not perform extra validation, only make sure types are valid and compatible
- NoExtraProperties = 0x01, //!< Make sure the json does not contain any properties that are not in the type to deserialize it to
- AllProperties = 0x02, //!< Make sure all properties of the type have a value in the deserialized json data
- StrictBasicTypes = 0x04, //!< Make shure basic types (string, int, ...) are actually of those types, instead of accepting all that are convertible
- FullPropertyValidation = (NoExtraProperties | AllProperties), //!< Validate properties are exactly the same as declared
- FullValidation = (FullPropertyValidation | StrictBasicTypes), //!< Validate everything
- };
- Q_DECLARE_FLAGS(ValidationFlags, ValidationFlag)
- Q_FLAG(ValidationFlags)
- //! Enum to specify the modes of polymorphism
- enum class Polymorphing {
- Disabled, //!< Do not serialize polymorphic and ignore information about classes in json
- Enabled, //!< Use polymorphism where declared by the classes/json
- Forced //!< Treat every object polymorphic, and required the class information to be present in json
- };
- Q_ENUM(Polymorphing)
- //! Enum to specify how multi maps and sets should be serialized
- enum class MultiMapMode {
- Map, //!< Store them as json object, with each element beeing a json array containing the actual values
- List, //!< Store a list of pairs, where for each pair the first element is the key and the second the value
- DenseMap //!< Just like Map, but entries with just one value are stored as that value, instead of an array with one element
- };
- Q_ENUM(MultiMapMode)
- //! Registers a custom extractor for the given type
- template<typename TType, typename TExtractor>
- static void registerExtractor();
- //! @copybrief SerializerBase::registerExtractor
- static void registerExtractor(int metaTypeId, const QSharedPointer<TypeExtractor> &extractor);
- //! Registers a custom type for list converisons
- template<typename T>
- static inline void registerListConverters();
- //! Registers a custom type for set converisons
- template<typename T>
- static inline void registerSetConverters();
- //! Registers a custom type for map converisons
- template<typename TKey, typename TValue, bool mapTypes = true, bool hashTypes = true>
- static inline void registerMapConverters();
- //! Registers a custom type for QSharedPointer and QPointer converisons
- template<typename T>
- static inline void registerPointerConverters();
- //! Registers a custom type for list, set map and optional converisons. Also include pointer converters, if applicable
- template<typename T>
- static inline void registerBasicConverters();
- //! Registers two types for pair conversion
- template<typename T, typename U>
- static inline void registerPairConverters();
- //! Registers a number of types for std::tuple conversion
- template<typename... TArgs>
- static inline void registerTupleConverters();
- //! Registers a custom type for std::optional converisons
- template<typename T>
- static inline void registerOptionalConverters();
- //! Registers a custom type for std::variant converisons
- template<typename... TArgs>
- static inline void registerVariantConverters();
- //! Serializes a given variant to either CBOR or JSON, depending on the actual instance
- virtual std::variant<QCborValue, QJsonValue> serializeGeneric(const QVariant &value) const = 0;
- //! Deserializes CBOR or JSON, depending on the actual instance, to variant
- virtual QVariant deserializeGeneric(const std::variant<QCborValue, QJsonValue> &value, int metaTypeId, QObject *parent = nullptr) const = 0;
- //! @readAcFn{QJsonSerializer::allowDefaultNull}
- bool allowDefaultNull() const;
- //! @readAcFn{QJsonSerializer::keepObjectName}
- bool keepObjectName() const;
- //! @readAcFn{QJsonSerializer::enumAsString}
- bool enumAsString() const;
- //! @readAcFn{QJsonSerializer::versionAsString}
- bool versionAsString() const;
- //! @readAcFn{QJsonSerializer::dateAsTimeStamp}
- bool dateAsTimeStamp() const;
- //! @readAcFn{QJsonSerializer::useBcp47Locale}
- bool useBcp47Locale() const;
- //! @readAcFn{QJsonSerializer::validationFlags}
- ValidationFlags validationFlags() const;
- //! @readAcFn{QJsonSerializer::polymorphing}
- Polymorphing polymorphing() const;
- //! @readAcFn{QJsonSerializer::multiMapMode}
- MultiMapMode multiMapMode() const;
- //! @readAcFn{QJsonSerializer::ignoreStoredAttribute}
- bool ignoresStoredAttribute() const;
- //! Globally registers a converter factory to provide converters for all QJsonSerializer instances
- template <typename TConverter, int Priority = TypeConverter::Priority::Standard>
- static void addJsonTypeConverterFactory();
- //! @copybrief SerializerBase::addJsonTypeConverterFactory()
- static void addJsonTypeConverterFactory(TypeConverterFactory *factory);
- //! Adds a custom type converter to this serializer
- template <typename TConverter>
- void addJsonTypeConverter();
- //! @copybrief SerializerBase::addJsonTypeConverter()
- void addJsonTypeConverter(const QSharedPointer<TypeConverter> &converter);
- public Q_SLOTS:
- //! @writeAcFn{QJsonSerializer::allowDefaultNull}
- void setAllowDefaultNull(bool allowDefaultNull);
- //! @writeAcFn{QJsonSerializer::keepObjectName}
- void setKeepObjectName(bool keepObjectName);
- //! @writeAcFn{QJsonSerializer::enumAsString}
- void setEnumAsString(bool enumAsString);
- //! @writeAcFn{QJsonSerializer::versionAsString}
- void setVersionAsString(bool versionAsString);
- //! @writeAcFn{QJsonSerializer::dateAsTimeStamp}
- void setDateAsTimeStamp(bool dateAsTimeStamp);
- //! @writeAcFn{QJsonSerializer::useBcp47Locale}
- void setUseBcp47Locale(bool useBcp47Locale);
- //! @writeAcFn{QJsonSerializer::validationFlags}
- void setValidationFlags(ValidationFlags validationFlags);
- //! @writeAcFn{QJsonSerializer::polymorphing}
- void setPolymorphing(Polymorphing polymorphing);
- //! @writeAcFn{QJsonSerializer::multiMapMode}
- void setMultiMapMode(MultiMapMode multiMapMode);
- //! @writeAcFn{QJsonSerializer::ignoreStoredAttribute}
- void setIgnoreStoredAttribute(bool ignoreStoredAttribute);
- Q_SIGNALS:
- //! @notifyAcFn{QJsonSerializer::allowDefaultNull}
- void allowDefaultNullChanged(bool allowDefaultNull, QPrivateSignal);
- //! @notifyAcFn{QJsonSerializer::keepObjectName}
- void keepObjectNameChanged(bool keepObjectName, QPrivateSignal);
- //! @notifyAcFn{QJsonSerializer::enumAsString}
- void enumAsStringChanged(bool enumAsString, QPrivateSignal);
- //! @notifyAcFn{QJsonSerializer::versionAsString}
- void versionAsStringChanged(bool versionAsString, QPrivateSignal);
- //! @notifyAcFn{QJsonSerializer::dateAsTimeStamp}
- void dateAsTimeStampChanged(bool dateAsTimeStamp, QPrivateSignal);
- //! @notifyAcFn{QJsonSerializer::useBcp47Locale}
- void useBcp47LocaleChanged(bool useBcp47Locale, QPrivateSignal);
- //! @notifyAcFn{QJsonSerializer::validationFlags}
- void validationFlagsChanged(ValidationFlags validationFlags, QPrivateSignal);
- //! @notifyAcFn{QJsonSerializer::polymorphing}
- void polymorphingChanged(Polymorphing polymorphing, QPrivateSignal);
- //! @notifyAcFn{QJsonSerializer::multiMapMode}
- void multiMapModeChanged(MultiMapMode multiMapMode, QPrivateSignal);
- //! @notifyAcFn{QJsonSerializer::ignoreStoredAttribute}
- void ignoreStoredAttributeChanged(bool ignoreStoredAttribute, QPrivateSignal);
- protected:
- //! Default constructor
- explicit SerializerBase(QObject *parent = nullptr);
- //! @private
- explicit SerializerBase(SerializerBasePrivate &dd, QObject *parent);
- virtual QList<int> typesForTag(QCborTag tag) const = 0;
- // protected implementation -> internal use for the type converters
- QVariant getProperty(const char *name) const override;
- QSharedPointer<const TypeExtractor> extractor(int metaTypeId) const override;
- QCborValue serializeSubtype(const QMetaProperty &property, const QVariant &value) const override;
- QCborValue serializeSubtype(int propertyType, const QVariant &value, const QByteArray &traceHint) const override;
- QVariant deserializeSubtype(const QMetaProperty &property, const QCborValue &value, QObject *parent) const override;
- QVariant deserializeSubtype(int propertyType, const QCborValue &value, QObject *parent, const QByteArray &traceHint) const override;
- //! @private
- QCborValue serializeVariant(int propertyType, const QVariant &value) const;
- //! @private
- QVariant deserializeVariant(int propertyType, const QCborValue &value, QObject *parent, bool skipConversion = false) const;
- private:
- Q_DECLARE_PRIVATE(SerializerBase)
- static void registerInverseTypedefImpl(int typeId, const char *normalizedTypeName);
- };
- //! A macro the mark a class as polymorphic
- #define Q_JSON_POLYMORPHIC(x) \
- static_assert(std::is_same<decltype(x), bool>::value, "x must be bool"); \
- Q_CLASSINFO("polymorphic", #x)
- // ------------- Generic Implementation -------------
- template<typename TType, typename TExtractor>
- void SerializerBase::registerExtractor()
- {
- registerExtractor(qMetaTypeId<TType>(), QSharedPointer<TExtractor>::create());
- }
- template<typename T>
- void SerializerBase::registerListConverters()
- {
- MetaWriters::SequentialWriter::registerWriter<QList, T>();
- #if !defined(QT_NO_LINKED_LIST) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
- MetaWriters::SequentialWriter::registerWriter<QLinkedList, T>();
- #endif
- MetaWriters::SequentialWriter::registerWriter<QVector, T>();
- MetaWriters::SequentialWriter::registerWriter<QStack, T>();
- MetaWriters::SequentialWriter::registerWriter<QQueue, T>();
- }
- template<typename T>
- void SerializerBase::registerSetConverters()
- {
- MetaWriters::SequentialWriter::registerWriter<QSet, T>();
- }
- template<typename TKey, typename TValue, bool mapTypes, bool hashTypes>
- void SerializerBase::registerMapConverters()
- {
- if constexpr (mapTypes) {
- MetaWriters::AssociativeWriter::registerWriter<QMap, TKey, TValue>();
- MetaWriters::AssociativeWriter::registerWriter<QMultiMap, TKey, TValue>();
- }
- if constexpr (hashTypes) {
- MetaWriters::AssociativeWriter::registerWriter<QHash, TKey, TValue>();
- MetaWriters::AssociativeWriter::registerWriter<QMultiHash, TKey, TValue>();
- }
- }
- template<typename T>
- void SerializerBase::registerPointerConverters()
- {
- registerExtractor<QSharedPointer<T>, TypeExtractors::SmartPointerExtractor<QSharedPointer, T>>();
- if constexpr (std::is_base_of_v<QObject, T>)
- registerExtractor<QPointer<T>, TypeExtractors::SmartPointerExtractor<QPointer, T>>();
- }
- template<typename T>
- void SerializerBase::registerBasicConverters()
- {
- if constexpr (std::is_base_of_v<QObject, T>) {
- registerBasicConverters<T*>();
- registerPointerConverters<T>();
- registerBasicConverters<QSharedPointer<T>>();
- registerBasicConverters<QPointer<T>>();
- } else {
- registerListConverters<T>();
- registerSetConverters<T>();
- registerMapConverters<QString, T>();
- }
- }
- template<typename T1, typename T2>
- void SerializerBase::registerPairConverters()
- {
- registerExtractor<QPair<T1, T2>, TypeExtractors::PairExtractor<QPair, T1, T2>>();
- registerExtractor<std::pair<T1, T2>, TypeExtractors::PairExtractor<std::pair, T1, T2>>();
- }
- template<typename... TArgs>
- void SerializerBase::registerTupleConverters()
- {
- registerExtractor<std::tuple<TArgs...>, TypeExtractors::TupleExtractor<TArgs...>>();
- }
- template<typename T>
- void SerializerBase::registerOptionalConverters()
- {
- registerExtractor<std::optional<T>, TypeExtractors::OptionalExtractor<T>>();
- }
- template<typename... TArgs>
- void SerializerBase::registerVariantConverters()
- {
- registerExtractor<std::variant<TArgs...>, TypeExtractors::VariantExtractor<TArgs...>>();
- }
- template<typename TConverter, int Priority>
- void SerializerBase::addJsonTypeConverterFactory()
- {
- static_assert(std::is_base_of<TypeConverter, TConverter>::value, "T must implement QJsonTypeConverter");
- addJsonTypeConverterFactory(new TypeConverterStandardFactory<TConverter, Priority>{});
- }
- template<typename TConverter>
- void SerializerBase::addJsonTypeConverter()
- {
- static_assert(std::is_base_of<TypeConverter, TConverter>::value, "T must implement QJsonTypeConverter");
- addJsonTypeConverter(QSharedPointer<TConverter>::create());
- }
- }
- Q_DECLARE_OPERATORS_FOR_FLAGS(QtJsonSerializer::SerializerBase::ValidationFlags)
- Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QMultiMap)
- Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QMultiHash)
- //! @file serializerbase.h The SerializerBase header file
- #endif // QTJSONSERIALIZER_SERIALIZERBASE_H
|