| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790 |
- #include "serializerbase.h"
- #include "serializerbase_p.h"
- #include "exceptioncontext_p.h"
- #include <optional>
- #include <variant>
- #include <cmath>
- #include <QtCore/QDateTime>
- #include <QtCore/QCoreApplication>
- #include <QtCore/QScopeGuard>
- #include "typeconverters/bitarrayconverter_p.h"
- #include "typeconverters/bytearrayconverter_p.h"
- #include "typeconverters/cborconverter_p.h"
- #include "typeconverters/datetimeconverter_p.h"
- #include "typeconverters/enumconverter_p.h"
- #include "typeconverters/gadgetconverter_p.h"
- #include "typeconverters/geomconverter_p.h"
- #include "typeconverters/legacygeomconverter_p.h"
- #include "typeconverters/listconverter_p.h"
- #include "typeconverters/localeconverter_p.h"
- #include "typeconverters/mapconverter_p.h"
- #include "typeconverters/multimapconverter_p.h"
- #include "typeconverters/objectconverter_p.h"
- #include "typeconverters/pairconverter_p.h"
- #include "typeconverters/smartpointerconverter_p.h"
- #include "typeconverters/stdchronodurationconverter_p.h"
- #include "typeconverters/stdoptionalconverter_p.h"
- #include "typeconverters/stdtupleconverter_p.h"
- #include "typeconverters/stdvariantconverter_p.h"
- #include "typeconverters/versionnumberconverter_p.h"
- using namespace QtJsonSerializer;
- using namespace QtJsonSerializer::TypeConverters;
- #ifndef NO_REGISTER_JSON_CONVERTERS
- namespace {
- void qtJsonSerializerRegisterTypes() {
- QtJsonSerializer::registerTypes();
- }
- }
- Q_COREAPP_STARTUP_FUNCTION(qtJsonSerializerRegisterTypes);
- #endif
- Q_LOGGING_CATEGORY(QtJsonSerializer::logSerializer, "qt.jsonserializer.serializer")
- Q_LOGGING_CATEGORY(QtJsonSerializer::logSerializerExtractor, "qt.jsonserializer.serializer.extractor")
- namespace {
- class LogTag {
- public:
- inline LogTag(QCborTag tag) : tag{tag} {}
- inline operator QCborTag() const { return tag; }
- private:
- QCborTag tag;
- };
- QDebug operator<<(QDebug debug, LogTag tag) {
- if (tag != TypeConverter::NoTag)
- debug << ", CBOR-Tag" << static_cast<QCborTag>(tag);
- return debug;
- }
- }
- SerializerBase::SerializerBase(QObject *parent) :
- SerializerBase{*new SerializerBasePrivate{}, parent}
- {}
- SerializerBase::SerializerBase(SerializerBasePrivate &dd, QObject *parent) :
- QObject{dd, parent}
- {}
- void SerializerBase::registerExtractor(int metaTypeId, const QSharedPointer<TypeExtractor> &extractor)
- {
- SerializerBasePrivate::extractors.add(metaTypeId, extractor);
- qCDebug(logSerializerExtractor) << "Added extractor for type:" << QMetaTypeName(metaTypeId);
- }
- bool SerializerBase::allowDefaultNull() const
- {
- Q_D(const SerializerBase);
- return d->allowNull;
- }
- bool SerializerBase::keepObjectName() const
- {
- Q_D(const SerializerBase);
- return d->keepObjectName;
- }
- bool SerializerBase::enumAsString() const
- {
- Q_D(const SerializerBase);
- return d->enumAsString;
- }
- bool SerializerBase::versionAsString() const
- {
- Q_D(const SerializerBase);
- return d->versionAsString;
- }
- bool SerializerBase::dateAsTimeStamp() const
- {
- Q_D(const SerializerBase);
- return d->dateAsTimeStamp;
- }
- bool SerializerBase::useBcp47Locale() const
- {
- Q_D(const SerializerBase);
- return d->useBcp47Locale;
- }
- SerializerBase::ValidationFlags SerializerBase::validationFlags() const
- {
- Q_D(const SerializerBase);
- return d->validationFlags;
- }
- SerializerBase::Polymorphing SerializerBase::polymorphing() const
- {
- Q_D(const SerializerBase);
- return d->polymorphing;
- }
- SerializerBase::MultiMapMode SerializerBase::multiMapMode() const
- {
- Q_D(const SerializerBase);
- return d->multiMapMode;
- }
- bool SerializerBase::ignoresStoredAttribute() const
- {
- Q_D(const SerializerBase);
- return d->ignoreStoredAttribute;
- }
- void SerializerBase::addJsonTypeConverterFactory(TypeConverterFactory *factory)
- {
- QWriteLocker _{&SerializerBasePrivate::typeConverterFactoryLock};
- SerializerBasePrivate::typeConverterFactories.append(factory);
- qCDebug(logSerializer) << "Added new global converter factory:" << factory;
- }
- void SerializerBase::addJsonTypeConverter(const QSharedPointer<TypeConverter> &converter)
- {
- Q_D(SerializerBase);
- Q_ASSERT_X(converter, Q_FUNC_INFO, "converter must not be null!");
- converter->setHelper(this);
- d->typeConverters.insertSorted(converter);
- d->serCache.clear();
- d->deserCache.clear();
- qCDebug(logSerializer) << "Added new local converter:" << converter->name();
- }
- void SerializerBase::setAllowDefaultNull(bool allowDefaultNull)
- {
- Q_D(SerializerBase);
- if(d->allowNull == allowDefaultNull)
- return;
- d->allowNull = allowDefaultNull;
- emit allowDefaultNullChanged(d->allowNull, {});
- }
- void SerializerBase::setKeepObjectName(bool keepObjectName)
- {
- Q_D(SerializerBase);
- if(d->keepObjectName == keepObjectName)
- return;
- d->keepObjectName = keepObjectName;
- emit keepObjectNameChanged(d->keepObjectName, {});
- }
- void SerializerBase::setEnumAsString(bool enumAsString)
- {
- Q_D(SerializerBase);
- if(d->enumAsString == enumAsString)
- return;
- d->enumAsString = enumAsString;
- emit enumAsStringChanged(d->enumAsString, {});
- }
- void SerializerBase::setVersionAsString(bool versionAsString)
- {
- Q_D(SerializerBase);
- if(d->versionAsString == versionAsString)
- return;
- d->versionAsString = versionAsString;
- emit versionAsStringChanged(d->versionAsString, {});
- }
- void SerializerBase::setDateAsTimeStamp(bool dateAsTimeStamp)
- {
- Q_D(SerializerBase);
- if(d->dateAsTimeStamp == dateAsTimeStamp)
- return;
- d->dateAsTimeStamp = dateAsTimeStamp;
- emit dateAsTimeStampChanged(d->dateAsTimeStamp, {});
- }
- void SerializerBase::setUseBcp47Locale(bool useBcp47Locale)
- {
- Q_D(SerializerBase);
- if(d->useBcp47Locale == useBcp47Locale)
- return;
- d->useBcp47Locale = useBcp47Locale;
- emit useBcp47LocaleChanged(d->useBcp47Locale, {});
- }
- void SerializerBase::setValidationFlags(ValidationFlags validationFlags)
- {
- Q_D(SerializerBase);
- if(d->validationFlags == validationFlags)
- return;
- d->validationFlags = validationFlags;
- emit validationFlagsChanged(d->validationFlags, {});
- }
- void SerializerBase::setPolymorphing(SerializerBase::Polymorphing polymorphing)
- {
- Q_D(SerializerBase);
- if(d->polymorphing == polymorphing)
- return;
- d->polymorphing = polymorphing;
- emit polymorphingChanged(d->polymorphing, {});
- }
- void SerializerBase::setMultiMapMode(SerializerBase::MultiMapMode multiMapMode)
- {
- Q_D(SerializerBase);
- if(d->multiMapMode == multiMapMode)
- return;
- d->multiMapMode = multiMapMode;
- emit multiMapModeChanged(d->multiMapMode, {});
- }
- void SerializerBase::setIgnoreStoredAttribute(bool ignoreStoredAttribute)
- {
- Q_D(SerializerBase);
- if(d->ignoreStoredAttribute == ignoreStoredAttribute)
- return;
- d->ignoreStoredAttribute = ignoreStoredAttribute;
- emit ignoreStoredAttributeChanged(d->ignoreStoredAttribute, {});
- }
- QVariant SerializerBase::getProperty(const char *name) const
- {
- return property(name);
- }
- QSharedPointer<const TypeExtractor> SerializerBase::extractor(int metaTypeId) const
- {
- const auto extractor = SerializerBasePrivate::extractors.get(metaTypeId);
- if (extractor)
- qCDebug(logSerializerExtractor) << "Found extractor for type:" << QMetaTypeName(metaTypeId);
- else
- qCDebug(logSerializerExtractor) << "Unable to find extractor for type:" << QMetaTypeName(metaTypeId);
- return extractor;
- }
- QCborValue SerializerBase::serializeSubtype(const QMetaProperty &property, const QVariant &value) const
- {
- Q_D(const SerializerBase);
- ExceptionContext ctx(property);
- auto logGuard = qScopeGuard([](){
- qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
- << "done";
- });
- if (property.isEnumType()) {
- const auto enumId = d->getEnumId(property.enumerator(), true);
- qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
- << "Serializing subtype property" << property.name()
- << "of enum type" << QMetaTypeName(enumId);
- return serializeVariant(enumId, value);
- } else {
- qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
- << "Serializing subtype property" << property.name()
- << "of type" << QMetaTypeName(property.userType());
- return serializeVariant(property.userType(), value);
- }
- }
- QCborValue SerializerBase::serializeSubtype(int propertyType, const QVariant &value, const QByteArray &traceHint) const
- {
- ExceptionContext ctx(propertyType, traceHint);
- auto logGuard = qScopeGuard([](){
- qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
- << "done";
- });
- qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
- << "Serializing subtype property" << traceHint
- << "of type" << QMetaTypeName(propertyType);
- return serializeVariant(propertyType, value);
- }
- QVariant SerializerBase::deserializeSubtype(const QMetaProperty &property, const QCborValue &value, QObject *parent) const
- {
- Q_D(const SerializerBase);
- ExceptionContext ctx(property);
- auto logGuard = qScopeGuard([](){
- qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
- << "done";
- });
- if (property.isEnumType()) {
- const auto enumId = d->getEnumId(property.enumerator(), false);
- qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
- << "Deserializing subtype property" << property.name()
- << "of enum type" << QMetaTypeName(enumId);
- return deserializeVariant(enumId, value, parent, true);
- } else {
- qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
- << "Deserializing subtype property" << property.name()
- << "of type" << QMetaTypeName(property.userType());
- return deserializeVariant(property.userType(), value, parent);
- }
- }
- QVariant SerializerBase::deserializeSubtype(int propertyType, const QCborValue &value, QObject *parent, const QByteArray &traceHint) const
- {
- ExceptionContext ctx(propertyType, traceHint);
- auto logGuard = qScopeGuard([](){
- qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
- << "done";
- });
- qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
- << "Deserializing subtype property" << traceHint
- << "of type" << QMetaTypeName(propertyType);
- return deserializeVariant(propertyType, value, parent);
- }
- QCborValue SerializerBase::serializeVariant(int propertyType, const QVariant &value) const
- {
- Q_D(const SerializerBase);
- // first: find a converter and convert to cbor
- auto converter = d->findSerConverter(propertyType);
- QCborValue res;
- if (converter)
- res = converter->serialize(propertyType, value);
- else
- res = d->serializeValue(propertyType, value);
- // second: check if an override tag is given, and if yes, override the normal tag
- if (const auto mTag = typeTag(propertyType); mTag != TypeConverter::NoTag)
- return {mTag, res.isTag() ? res.taggedValue() : res};
- else
- return res;
- }
- QVariant SerializerBase::deserializeVariant(int propertyType, const QCborValue &value, QObject *parent, bool skipConversion) const
- {
- Q_D(const SerializerBase);
- // first: find a converter and convert the data to QVariant
- auto converter = d->findDeserConverter(propertyType,
- value.isTag() ? value.tag() : TypeConverter::NoTag,
- value.isTag() ? value.taggedValue().type() : value.type());
- QVariant variant;
- if (converter) {
- if (jsonMode())
- variant = converter->deserializeJson(propertyType, value, parent);
- else
- variant = converter->deserializeCbor(propertyType, value, parent);
- } else {
- if (jsonMode())
- variant = d->deserializeJsonValue(propertyType, value);
- else
- variant = d->deserializeCborValue(propertyType, value);
- }
- // second: if the type was given, enforce a conversion to that type (expect if skipped)
- if(!skipConversion && propertyType != QMetaType::UnknownType) {
- auto vType = variant.typeName();
- // exclude special values that can convert from null, but should not do so
- auto allowConvert = true;
- switch (propertyType) {
- case QMetaType::QString:
- case QMetaType::QByteArray:
- if (value.isNull())
- allowConvert = false;
- break;
- default:
- break;
- }
- #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- if(allowConvert && variant.canConvert(propertyType) && variant.convert(propertyType))
- #else
- if(allowConvert && variant.canConvert(QMetaType(propertyType)) && variant.convert(QMetaType(propertyType)))
- #endif
- return variant;
- else if (d->allowNull && value.isNull())
- #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- return QVariant{propertyType, nullptr};
- #else
- return QVariant{QMetaType(propertyType), nullptr};
- #endif
- else {
- qDebug() << variant << value << value.isNull() << d->allowNull;
- throw DeserializationException(
- QByteArray("Failed to convert deserialized variant of type ")
- + (vType ? vType : "<unknown>") + QByteArray(" to property type ")
- + QMetaTypeName(propertyType)
- + QByteArray(". Make shure to register converters with the "
- "QJsonSerializer::register* methods"));
- }
- } else
- return variant;
- }
- // ------------- private implementation -------------
- SerializerBasePrivate::ThreadSafeStore<TypeExtractor> SerializerBasePrivate::extractors;
- QReadWriteLock SerializerBasePrivate::typeConverterFactoryLock;
- QList<TypeConverterFactory*> SerializerBasePrivate::typeConverterFactories {
- new TypeConverterStandardFactory<BitArrayConverter>{},
- new TypeConverterStandardFactory<BytearrayConverter>{},
- new TypeConverterStandardFactory<CborConverter>{},
- new TypeConverterStandardFactory<DateTimeConverter>{},
- new TypeConverterStandardFactory<EnumConverter>{},
- new TypeConverterStandardFactory<GadgetConverter>{},
- new TypeConverterStandardFactory<GeomConverter>{},
- new TypeConverterStandardFactory<ListConverter>{},
- new TypeConverterStandardFactory<LocaleConverter>{},
- new TypeConverterStandardFactory<MapConverter>{},
- new TypeConverterStandardFactory<MultiMapConverter>{},
- new TypeConverterStandardFactory<ObjectConverter>{},
- new TypeConverterStandardFactory<PairConverter>{},
- new TypeConverterStandardFactory<SmartPointerConverter>{},
- new TypeConverterStandardFactory<StdChronoDurationConverter>{},
- new TypeConverterStandardFactory<StdOptionalConverter>{},
- new TypeConverterStandardFactory<StdTupleConverter>{},
- new TypeConverterStandardFactory<StdVariantConverter>{},
- new TypeConverterStandardFactory<VersionNumberConverter>{},
- new TypeConverterStandardFactory<LegacyGeomConverter>{}
- };
- QSharedPointer<TypeConverter> SerializerBasePrivate::findSerConverter(int propertyType) const
- {
- // first: update converters from factories
- updateConverterStore();
- // second: check if already cached
- if (auto converter = serCache.get(propertyType); converter) {
- qCDebug(logSerializer) << "Found cached serialization converter" << converter->name()
- << "for type:" << QMetaTypeName(propertyType);
- return converter;
- }
- // third: check if the list of explicit converters has a matching one
- QReadLocker cLocker{&typeConverters.lock};
- for (const auto &converter : qAsConst(typeConverters.store)) {
- if (converter && converter->canConvert(propertyType)) {
- qCDebug(logSerializer) << "Found and cached serialization converter" << converter->name()
- << "for type:" << QMetaTypeName(propertyType);
- // add converter to cache and return it
- serCache.add(propertyType, converter);
- return converter;
- }
- }
- // fourth: no converter found: return default converter
- qCDebug(logSerializer) << "Unable to find serialization converte for type:" << QMetaTypeName(propertyType)
- << "- falling back to default QVariant to CBOR conversion";
- return nullptr;
- }
- QSharedPointer<TypeConverter> SerializerBasePrivate::findDeserConverter(int &propertyType, QCborTag tag, QCborValue::Type type) const
- {
- Q_Q(const SerializerBase);
- // first: update converters from factories
- updateConverterStore();
- // second: if no property type is given, try out any types associated with the tag
- if (propertyType == QMetaType::UnknownType && tag != TypeConverter::NoTag) {
- const auto tList = q->typesForTag(tag);
- for (auto typeId : tList) {
- // if any of those types has a working converter, just use that one
- auto res = findDeserConverter(typeId, tag, type);
- if (res) {
- propertyType = typeId;
- return res;
- }
- }
- }
- // third: check if already cached
- if (auto converter = deserCache.get(propertyType);
- converter && converter->canDeserialize(propertyType, tag, type) > 0) {
- qCDebug(logSerializer) << "Found cached deserialization converter" << converter->name()
- << "for type" << QMetaTypeName(propertyType)
- << LogTag{tag}
- << "and CBOR-type" << type;
- return converter;
- }
- // fourth: check if the list of explicit converters has a matching one
- QReadLocker cLocker{&typeConverters.lock};
- auto throwWrongTag = false;
- std::optional<std::pair<QSharedPointer<TypeConverter>, int>> guessConverter;
- for (const auto &converter : qAsConst(typeConverters.store)) {
- if (converter) {
- auto testType = propertyType;
- switch (converter->canDeserialize(testType, tag, type)) {
- case TypeConverter::Negative:
- continue;
- case TypeConverter::WrongTag:
- throwWrongTag = true;
- continue;
- case TypeConverter::Guessed:
- if (!guessConverter)
- guessConverter = std::make_pair(converter, testType);
- continue;
- case TypeConverter::Positive:
- break;
- }
- // add converter to cache (only happens for positive cases)
- deserCache.add(propertyType, converter);
- qCDebug(logSerializer) << "Found and cached deserialization converter" << converter->name()
- << "for type" << QMetaTypeName(propertyType)
- << LogTag{tag}
- << "and CBOR-type" << type;
- return converter;
- }
- }
- cLocker.unlock();
- // fifth: if a guessed converter is available, use that one
- if (guessConverter) {
- // extract converter from info;
- auto &[converter, newType] = *guessConverter;
- // if valid, add to cache, set the type and return
- if (converter) {
- // add converter to list and cache
- propertyType = newType;
- deserCache.add(propertyType, converter);
- qCDebug(logSerializer) << "Found and cached deserialization converter" << converter->name()
- << "by guessing the data with CBOR-tag" << tag
- << "and CBOR-type" << type
- << "is of type" << QMetaTypeName(propertyType);
- return converter;
- }
- }
- // sixth: if a wrong tag mark was set, throw an expection
- if (throwWrongTag) {
- throw DeserializationException{QByteArray{"Found converter able to handle data of type "} +
- QMetaTypeName(propertyType) +
- ", but the given CBOR tag " +
- QByteArray::number(static_cast<quint64>(tag)) +
- " is not convertible to that type."};
- }
- // seventh: no converter found: return default converter
- qCDebug(logSerializer) << "Unable to find deserialization converte for type" << QMetaTypeName(propertyType)
- << LogTag{tag}
- << "and CBOR-type" << type
- << "- falling back to default CBOR to QVariant conversion";
- return nullptr;
- }
- void SerializerBasePrivate::updateConverterStore() const
- {
- Q_Q(const SerializerBase);
- QReadLocker fLocker{&typeConverterFactoryLock};
- if (typeConverterFactories.size() > typeConverters.factoryOffset.loadAcquire()) {
- QWriteLocker cLocker{&typeConverters.lock};
- auto max = typeConverterFactories.size();
- for (auto i = typeConverters.factoryOffset.loadAcquire(); i < max; ++i) {
- auto converter = typeConverterFactories[i]->createConverter();
- if (converter) {
- converter->setHelper(q);
- typeConverters.insertSorted(converter, cLocker);
- serCache.clear();
- deserCache.clear();
- qCDebug(logSerializer) << "Found and added new global converter:" << converter->name();
- }
- }
- typeConverters.factoryOffset.storeRelease(typeConverterFactories.size());
- }
- }
- int SerializerBasePrivate::getEnumId(QMetaEnum metaEnum, bool ser) const
- {
- QByteArray eName = metaEnum.name();
- if (const QByteArray scope = metaEnum.scope(); !scope.isEmpty())
- eName = scope + "::" + eName;
- #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- const auto eTypeId = QMetaType::type(eName);
- #else
- const auto eTypeId = QMetaType::fromName(eName).id();
- #endif
- if (eTypeId == QMetaType::UnknownType) {
- if (ser)
- throw SerializationException{"Unable to determine typeid of meta enum " + eName};
- else
- throw DeserializationException{"Unable to determine typeid of meta enum " + eName};
- } else
- return eTypeId;
- }
- QCborValue SerializerBasePrivate::serializeValue(int propertyType, const QVariant &value) const
- {
- Q_UNUSED(propertyType)
- return QCborValue::fromVariant(value);
- }
- QVariant SerializerBasePrivate::deserializeCborValue(int propertyType, const QCborValue &value) const
- {
- Q_Q(const SerializerBase);
- // perform strict validations
- if (validationFlags.testFlag(ValidationFlag::StrictBasicTypes)) {
- auto doThrow = false;
- QList<QCborTag> expectedTags;
- const auto testValue = value.isTag() ? value.taggedValue() : value;
- switch (propertyType) {
- case QMetaType::Bool:
- if (!testValue.isBool())
- doThrow = true;
- break;
- case QMetaType::Int:
- case QMetaType::UInt:
- case QMetaType::Long:
- case QMetaType::LongLong:
- case QMetaType::Short:
- case QMetaType::ULong:
- case QMetaType::ULongLong:
- case QMetaType::UShort:
- case QMetaType::SChar:
- case QMetaType::UChar:
- if (!testValue.isInteger())
- doThrow = true;
- break;
- case QMetaType::Float:
- case QMetaType::Double:
- if (!testValue.isDouble())
- doThrow = true;
- break;
- case QMetaType::Char:
- case QMetaType::QChar:
- case QMetaType::QString:
- expectedTags = {
- TypeConverter::NoTag,
- static_cast<QCborTag>(QCborKnownTags::Base64),
- static_cast<QCborTag>(QCborKnownTags::Base64url)
- };
- Q_FALLTHROUGH();
- case QMetaType::QColor:
- case QMetaType::QFont:
- if (!testValue.isString())
- doThrow = true;
- break;
- case QMetaType::QByteArray:
- expectedTags = {
- TypeConverter::NoTag,
- static_cast<QCborTag>(QCborKnownTags::ExpectedBase64),
- static_cast<QCborTag>(QCborKnownTags::ExpectedBase64url),
- static_cast<QCborTag>(QCborKnownTags::ExpectedBase16)
- };
- if (!testValue.isByteArray())
- doThrow = true;
- break;
- case QMetaType::Nullptr:
- if (!testValue.isNull())
- doThrow = true;
- break;
- case QMetaType::QUrl:
- if (!value.isUrl()) {
- if (testValue.isString())
- expectedTags = {static_cast<QCborTag>(QCborKnownTags::Url)};
- else
- doThrow = true;
- }
- break;
- case QMetaType::QUuid:
- if (!value.isUuid()) {
- if (testValue.isByteArray())
- expectedTags = {static_cast<QCborTag>(QCborKnownTags::Uuid)};
- else
- doThrow = true;
- }
- break;
- case QMetaType::QRegularExpression:
- if (!value.isRegularExpression()) {
- if (testValue.isString())
- expectedTags = {static_cast<QCborTag>(QCborKnownTags::RegularExpression)};
- else
- doThrow = true;
- }
- break;
- default:
- break;
- }
- if (const auto mTag = q->typeTag(propertyType);
- mTag != TypeConverter::NoTag &&
- mTag != value.tag())
- doThrow = true;
- else if (!expectedTags.isEmpty() &&
- !expectedTags.contains(value.tag()))
- doThrow = true;
- if (doThrow) {
- throw DeserializationException(QByteArray("Failed to deserialze CBOR-value to type ") +
- QMetaTypeName(propertyType) +
- QByteArray(" because the given CBOR-value failed strict validation"));
- }
- }
- return value.toVariant();
- }
- QVariant SerializerBasePrivate::deserializeJsonValue(int propertyType, const QCborValue &value) const
- {
- // perform strict validations
- if (validationFlags.testFlag(ValidationFlag::StrictBasicTypes)) {
- auto doThrow = false;
- switch (propertyType) {
- case QMetaType::Bool:
- if (!value.isBool())
- doThrow = true;
- break;
- case QMetaType::Int:
- case QMetaType::UInt:
- case QMetaType::Long:
- case QMetaType::LongLong:
- case QMetaType::Short:
- case QMetaType::ULong:
- case QMetaType::ULongLong:
- case QMetaType::UShort:
- case QMetaType::SChar:
- case QMetaType::UChar:
- if (value.isDouble()) {
- if (auto val = value.toDouble(); trunc(val) != val)
- doThrow = true;
- } else if (!value.isInteger())
- doThrow = true;
- break;
- case QMetaType::QChar:
- case QMetaType::QString:
- case QMetaType::Char:
- case QMetaType::QColor:
- case QMetaType::QUrl:
- case QMetaType::QFont:
- case QMetaType::QUuid:
- if (!value.isString())
- doThrow = true;
- break;
- case QMetaType::Nullptr:
- if (!value.isNull())
- doThrow = true;
- break;
- case QMetaType::Float:
- case QMetaType::Double:
- if (!value.isDouble())
- doThrow = true;
- break;
- default:
- break;
- }
- if (doThrow) {
- throw DeserializationException(QByteArray("Failed to deserialze JSON-value to type ") +
- QMetaTypeName(propertyType) +
- QByteArray("because the given JSON-value failed strict validation"));
- }
- }
- // special case: QRegularExpression, is missing a converter (and cannot be registered)
- if (propertyType == QMetaType::QRegularExpression &&
- value.isString())
- return QRegularExpression{value.toString()};
- else
- return value.toVariant();
- }
|