serializerbase.cpp~RFc998f2.TMP 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. #include "serializerbase.h"
  2. #include "serializerbase_p.h"
  3. #include "exceptioncontext_p.h"
  4. #include <optional>
  5. #include <variant>
  6. #include <cmath>
  7. #include <QtCore/QDateTime>
  8. #include <QtCore/QCoreApplication>
  9. #include <QtCore/QScopeGuard>
  10. #include "typeconverters/bitarrayconverter_p.h"
  11. #include "typeconverters/bytearrayconverter_p.h"
  12. #include "typeconverters/cborconverter_p.h"
  13. #include "typeconverters/datetimeconverter_p.h"
  14. #include "typeconverters/enumconverter_p.h"
  15. #include "typeconverters/gadgetconverter_p.h"
  16. #include "typeconverters/geomconverter_p.h"
  17. #include "typeconverters/legacygeomconverter_p.h"
  18. #include "typeconverters/listconverter_p.h"
  19. #include "typeconverters/localeconverter_p.h"
  20. #include "typeconverters/mapconverter_p.h"
  21. #include "typeconverters/multimapconverter_p.h"
  22. #include "typeconverters/objectconverter_p.h"
  23. #include "typeconverters/pairconverter_p.h"
  24. #include "typeconverters/smartpointerconverter_p.h"
  25. #include "typeconverters/stdchronodurationconverter_p.h"
  26. #include "typeconverters/stdoptionalconverter_p.h"
  27. #include "typeconverters/stdtupleconverter_p.h"
  28. #include "typeconverters/stdvariantconverter_p.h"
  29. #include "typeconverters/versionnumberconverter_p.h"
  30. using namespace QtJsonSerializer;
  31. using namespace QtJsonSerializer::TypeConverters;
  32. #ifndef NO_REGISTER_JSON_CONVERTERS
  33. namespace {
  34. void qtJsonSerializerRegisterTypes() {
  35. QtJsonSerializer::registerTypes();
  36. }
  37. }
  38. Q_COREAPP_STARTUP_FUNCTION(qtJsonSerializerRegisterTypes);
  39. #endif
  40. Q_LOGGING_CATEGORY(QtJsonSerializer::logSerializer, "qt.jsonserializer.serializer")
  41. Q_LOGGING_CATEGORY(QtJsonSerializer::logSerializerExtractor, "qt.jsonserializer.serializer.extractor")
  42. namespace {
  43. class LogTag {
  44. public:
  45. inline LogTag(QCborTag tag) : tag{tag} {}
  46. inline operator QCborTag() const { return tag; }
  47. private:
  48. QCborTag tag;
  49. };
  50. QDebug operator<<(QDebug debug, LogTag tag) {
  51. if (tag != TypeConverter::NoTag)
  52. debug << ", CBOR-Tag" << static_cast<QCborTag>(tag);
  53. return debug;
  54. }
  55. }
  56. SerializerBase::SerializerBase(QObject *parent) :
  57. SerializerBase{*new SerializerBasePrivate{}, parent}
  58. {}
  59. SerializerBase::SerializerBase(SerializerBasePrivate &dd, QObject *parent) :
  60. QObject{dd, parent}
  61. {}
  62. void SerializerBase::registerExtractor(int metaTypeId, const QSharedPointer<TypeExtractor> &extractor)
  63. {
  64. SerializerBasePrivate::extractors.add(metaTypeId, extractor);
  65. qCDebug(logSerializerExtractor) << "Added extractor for type:" << QMetaTypeName(metaTypeId);
  66. }
  67. bool SerializerBase::allowDefaultNull() const
  68. {
  69. Q_D(const SerializerBase);
  70. return d->allowNull;
  71. }
  72. bool SerializerBase::keepObjectName() const
  73. {
  74. Q_D(const SerializerBase);
  75. return d->keepObjectName;
  76. }
  77. bool SerializerBase::enumAsString() const
  78. {
  79. Q_D(const SerializerBase);
  80. return d->enumAsString;
  81. }
  82. bool SerializerBase::versionAsString() const
  83. {
  84. Q_D(const SerializerBase);
  85. return d->versionAsString;
  86. }
  87. bool SerializerBase::dateAsTimeStamp() const
  88. {
  89. Q_D(const SerializerBase);
  90. return d->dateAsTimeStamp;
  91. }
  92. bool SerializerBase::useBcp47Locale() const
  93. {
  94. Q_D(const SerializerBase);
  95. return d->useBcp47Locale;
  96. }
  97. SerializerBase::ValidationFlags SerializerBase::validationFlags() const
  98. {
  99. Q_D(const SerializerBase);
  100. return d->validationFlags;
  101. }
  102. SerializerBase::Polymorphing SerializerBase::polymorphing() const
  103. {
  104. Q_D(const SerializerBase);
  105. return d->polymorphing;
  106. }
  107. SerializerBase::MultiMapMode SerializerBase::multiMapMode() const
  108. {
  109. Q_D(const SerializerBase);
  110. return d->multiMapMode;
  111. }
  112. bool SerializerBase::ignoresStoredAttribute() const
  113. {
  114. Q_D(const SerializerBase);
  115. return d->ignoreStoredAttribute;
  116. }
  117. void SerializerBase::addJsonTypeConverterFactory(TypeConverterFactory *factory)
  118. {
  119. QWriteLocker _{&SerializerBasePrivate::typeConverterFactoryLock};
  120. SerializerBasePrivate::typeConverterFactories.append(factory);
  121. qCDebug(logSerializer) << "Added new global converter factory:" << factory;
  122. }
  123. void SerializerBase::addJsonTypeConverter(const QSharedPointer<TypeConverter> &converter)
  124. {
  125. Q_D(SerializerBase);
  126. Q_ASSERT_X(converter, Q_FUNC_INFO, "converter must not be null!");
  127. converter->setHelper(this);
  128. d->typeConverters.insertSorted(converter);
  129. d->serCache.clear();
  130. d->deserCache.clear();
  131. qCDebug(logSerializer) << "Added new local converter:" << converter->name();
  132. }
  133. void SerializerBase::setAllowDefaultNull(bool allowDefaultNull)
  134. {
  135. Q_D(SerializerBase);
  136. if(d->allowNull == allowDefaultNull)
  137. return;
  138. d->allowNull = allowDefaultNull;
  139. emit allowDefaultNullChanged(d->allowNull, {});
  140. }
  141. void SerializerBase::setKeepObjectName(bool keepObjectName)
  142. {
  143. Q_D(SerializerBase);
  144. if(d->keepObjectName == keepObjectName)
  145. return;
  146. d->keepObjectName = keepObjectName;
  147. emit keepObjectNameChanged(d->keepObjectName, {});
  148. }
  149. void SerializerBase::setEnumAsString(bool enumAsString)
  150. {
  151. Q_D(SerializerBase);
  152. if(d->enumAsString == enumAsString)
  153. return;
  154. d->enumAsString = enumAsString;
  155. emit enumAsStringChanged(d->enumAsString, {});
  156. }
  157. void SerializerBase::setVersionAsString(bool versionAsString)
  158. {
  159. Q_D(SerializerBase);
  160. if(d->versionAsString == versionAsString)
  161. return;
  162. d->versionAsString = versionAsString;
  163. emit versionAsStringChanged(d->versionAsString, {});
  164. }
  165. void SerializerBase::setDateAsTimeStamp(bool dateAsTimeStamp)
  166. {
  167. Q_D(SerializerBase);
  168. if(d->dateAsTimeStamp == dateAsTimeStamp)
  169. return;
  170. d->dateAsTimeStamp = dateAsTimeStamp;
  171. emit dateAsTimeStampChanged(d->dateAsTimeStamp, {});
  172. }
  173. void SerializerBase::setUseBcp47Locale(bool useBcp47Locale)
  174. {
  175. Q_D(SerializerBase);
  176. if(d->useBcp47Locale == useBcp47Locale)
  177. return;
  178. d->useBcp47Locale = useBcp47Locale;
  179. emit useBcp47LocaleChanged(d->useBcp47Locale, {});
  180. }
  181. void SerializerBase::setValidationFlags(ValidationFlags validationFlags)
  182. {
  183. Q_D(SerializerBase);
  184. if(d->validationFlags == validationFlags)
  185. return;
  186. d->validationFlags = validationFlags;
  187. emit validationFlagsChanged(d->validationFlags, {});
  188. }
  189. void SerializerBase::setPolymorphing(SerializerBase::Polymorphing polymorphing)
  190. {
  191. Q_D(SerializerBase);
  192. if(d->polymorphing == polymorphing)
  193. return;
  194. d->polymorphing = polymorphing;
  195. emit polymorphingChanged(d->polymorphing, {});
  196. }
  197. void SerializerBase::setMultiMapMode(SerializerBase::MultiMapMode multiMapMode)
  198. {
  199. Q_D(SerializerBase);
  200. if(d->multiMapMode == multiMapMode)
  201. return;
  202. d->multiMapMode = multiMapMode;
  203. emit multiMapModeChanged(d->multiMapMode, {});
  204. }
  205. void SerializerBase::setIgnoreStoredAttribute(bool ignoreStoredAttribute)
  206. {
  207. Q_D(SerializerBase);
  208. if(d->ignoreStoredAttribute == ignoreStoredAttribute)
  209. return;
  210. d->ignoreStoredAttribute = ignoreStoredAttribute;
  211. emit ignoreStoredAttributeChanged(d->ignoreStoredAttribute, {});
  212. }
  213. QVariant SerializerBase::getProperty(const char *name) const
  214. {
  215. return property(name);
  216. }
  217. QSharedPointer<const TypeExtractor> SerializerBase::extractor(int metaTypeId) const
  218. {
  219. const auto extractor = SerializerBasePrivate::extractors.get(metaTypeId);
  220. if (extractor)
  221. qCDebug(logSerializerExtractor) << "Found extractor for type:" << QMetaTypeName(metaTypeId);
  222. else
  223. qCDebug(logSerializerExtractor) << "Unable to find extractor for type:" << QMetaTypeName(metaTypeId);
  224. return extractor;
  225. }
  226. QCborValue SerializerBase::serializeSubtype(const QMetaProperty &property, const QVariant &value) const
  227. {
  228. Q_D(const SerializerBase);
  229. ExceptionContext ctx(property);
  230. auto logGuard = qScopeGuard([](){
  231. qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
  232. << "done";
  233. });
  234. if (property.isEnumType()) {
  235. const auto enumId = d->getEnumId(property.enumerator(), true);
  236. qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
  237. << "Serializing subtype property" << property.name()
  238. << "of enum type" << QMetaTypeName(enumId);
  239. return serializeVariant(enumId, value);
  240. } else {
  241. qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
  242. << "Serializing subtype property" << property.name()
  243. << "of type" << QMetaTypeName(property.userType());
  244. return serializeVariant(property.userType(), value);
  245. }
  246. }
  247. QCborValue SerializerBase::serializeSubtype(int propertyType, const QVariant &value, const QByteArray &traceHint) const
  248. {
  249. ExceptionContext ctx(propertyType, traceHint);
  250. auto logGuard = qScopeGuard([](){
  251. qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
  252. << "done";
  253. });
  254. qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
  255. << "Serializing subtype property" << traceHint
  256. << "of type" << QMetaTypeName(propertyType);
  257. return serializeVariant(propertyType, value);
  258. }
  259. QVariant SerializerBase::deserializeSubtype(const QMetaProperty &property, const QCborValue &value, QObject *parent) const
  260. {
  261. Q_D(const SerializerBase);
  262. ExceptionContext ctx(property);
  263. auto logGuard = qScopeGuard([](){
  264. qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
  265. << "done";
  266. });
  267. if (property.isEnumType()) {
  268. const auto enumId = d->getEnumId(property.enumerator(), false);
  269. qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
  270. << "Deserializing subtype property" << property.name()
  271. << "of enum type" << QMetaTypeName(enumId);
  272. return deserializeVariant(enumId, value, parent, true);
  273. } else {
  274. qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
  275. << "Deserializing subtype property" << property.name()
  276. << "of type" << QMetaTypeName(property.userType());
  277. return deserializeVariant(property.userType(), value, parent);
  278. }
  279. }
  280. QVariant SerializerBase::deserializeSubtype(int propertyType, const QCborValue &value, QObject *parent, const QByteArray &traceHint) const
  281. {
  282. ExceptionContext ctx(propertyType, traceHint);
  283. auto logGuard = qScopeGuard([](){
  284. qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
  285. << "done";
  286. });
  287. qCDebug(logSerializer) << QByteArray{">"}.repeated(ExceptionContext::currentDepth()).constData()
  288. << "Deserializing subtype property" << traceHint
  289. << "of type" << QMetaTypeName(propertyType);
  290. return deserializeVariant(propertyType, value, parent);
  291. }
  292. QCborValue SerializerBase::serializeVariant(int propertyType, const QVariant &value) const
  293. {
  294. Q_D(const SerializerBase);
  295. // first: find a converter and convert to cbor
  296. auto converter = d->findSerConverter(propertyType);
  297. QCborValue res;
  298. if (converter)
  299. res = converter->serialize(propertyType, value);
  300. else
  301. res = d->serializeValue(propertyType, value);
  302. // second: check if an override tag is given, and if yes, override the normal tag
  303. if (const auto mTag = typeTag(propertyType); mTag != TypeConverter::NoTag)
  304. return {mTag, res.isTag() ? res.taggedValue() : res};
  305. else
  306. return res;
  307. }
  308. QVariant SerializerBase::deserializeVariant(int propertyType, const QCborValue &value, QObject *parent, bool skipConversion) const
  309. {
  310. Q_D(const SerializerBase);
  311. // first: find a converter and convert the data to QVariant
  312. auto converter = d->findDeserConverter(propertyType,
  313. value.isTag() ? value.tag() : TypeConverter::NoTag,
  314. value.isTag() ? value.taggedValue().type() : value.type());
  315. QVariant variant;
  316. if (converter) {
  317. if (jsonMode())
  318. variant = converter->deserializeJson(propertyType, value, parent);
  319. else
  320. variant = converter->deserializeCbor(propertyType, value, parent);
  321. } else {
  322. if (jsonMode())
  323. variant = d->deserializeJsonValue(propertyType, value);
  324. else
  325. variant = d->deserializeCborValue(propertyType, value);
  326. }
  327. // second: if the type was given, enforce a conversion to that type (expect if skipped)
  328. if(!skipConversion && propertyType != QMetaType::UnknownType) {
  329. auto vType = variant.typeName();
  330. // exclude special values that can convert from null, but should not do so
  331. auto allowConvert = true;
  332. switch (propertyType) {
  333. case QMetaType::QString:
  334. case QMetaType::QByteArray:
  335. if (value.isNull())
  336. allowConvert = false;
  337. break;
  338. default:
  339. break;
  340. }
  341. #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  342. if(allowConvert && variant.canConvert(propertyType) && variant.convert(propertyType))
  343. #else
  344. if(allowConvert && variant.canConvert(QMetaType(propertyType)) && variant.convert(QMetaType(propertyType)))
  345. #endif
  346. return variant;
  347. else if(d->allowNull && value.isNull())
  348. #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  349. return QVariant{propertyType, nullptr};
  350. #else
  351. return QVariant{QMetaType(propertyType), nullptr};
  352. #endif
  353. else {
  354. throw DeserializationException(QByteArray("Failed to convert deserialized variant of type ") +
  355. (vType ? vType : "<unknown>") +
  356. QByteArray(" to property type ") +
  357. QMetaTypeName(propertyType) +
  358. QByteArray(". Make shure to register converters with the QJsonSerializer::register* methods"));
  359. }
  360. } else
  361. return variant;
  362. }
  363. // ------------- private implementation -------------
  364. SerializerBasePrivate::ThreadSafeStore<TypeExtractor> SerializerBasePrivate::extractors;
  365. QReadWriteLock SerializerBasePrivate::typeConverterFactoryLock;
  366. QList<TypeConverterFactory*> SerializerBasePrivate::typeConverterFactories {
  367. new TypeConverterStandardFactory<BitArrayConverter>{},
  368. new TypeConverterStandardFactory<BytearrayConverter>{},
  369. new TypeConverterStandardFactory<CborConverter>{},
  370. new TypeConverterStandardFactory<DateTimeConverter>{},
  371. new TypeConverterStandardFactory<EnumConverter>{},
  372. new TypeConverterStandardFactory<GadgetConverter>{},
  373. new TypeConverterStandardFactory<GeomConverter>{},
  374. new TypeConverterStandardFactory<ListConverter>{},
  375. new TypeConverterStandardFactory<LocaleConverter>{},
  376. new TypeConverterStandardFactory<MapConverter>{},
  377. new TypeConverterStandardFactory<MultiMapConverter>{},
  378. new TypeConverterStandardFactory<ObjectConverter>{},
  379. new TypeConverterStandardFactory<PairConverter>{},
  380. new TypeConverterStandardFactory<SmartPointerConverter>{},
  381. new TypeConverterStandardFactory<StdChronoDurationConverter>{},
  382. new TypeConverterStandardFactory<StdOptionalConverter>{},
  383. new TypeConverterStandardFactory<StdTupleConverter>{},
  384. new TypeConverterStandardFactory<StdVariantConverter>{},
  385. new TypeConverterStandardFactory<VersionNumberConverter>{},
  386. new TypeConverterStandardFactory<LegacyGeomConverter>{}
  387. };
  388. QSharedPointer<TypeConverter> SerializerBasePrivate::findSerConverter(int propertyType) const
  389. {
  390. // first: update converters from factories
  391. updateConverterStore();
  392. // second: check if already cached
  393. if (auto converter = serCache.get(propertyType); converter) {
  394. qCDebug(logSerializer) << "Found cached serialization converter" << converter->name()
  395. << "for type:" << QMetaTypeName(propertyType);
  396. return converter;
  397. }
  398. // third: check if the list of explicit converters has a matching one
  399. QReadLocker cLocker{&typeConverters.lock};
  400. for (const auto &converter : qAsConst(typeConverters.store)) {
  401. if (converter && converter->canConvert(propertyType)) {
  402. qCDebug(logSerializer) << "Found and cached serialization converter" << converter->name()
  403. << "for type:" << QMetaTypeName(propertyType);
  404. // add converter to cache and return it
  405. serCache.add(propertyType, converter);
  406. return converter;
  407. }
  408. }
  409. // fourth: no converter found: return default converter
  410. qCDebug(logSerializer) << "Unable to find serialization converte for type:" << QMetaTypeName(propertyType)
  411. << "- falling back to default QVariant to CBOR conversion";
  412. return nullptr;
  413. }
  414. QSharedPointer<TypeConverter> SerializerBasePrivate::findDeserConverter(int &propertyType, QCborTag tag, QCborValue::Type type) const
  415. {
  416. Q_Q(const SerializerBase);
  417. // first: update converters from factories
  418. updateConverterStore();
  419. // second: if no property type is given, try out any types associated with the tag
  420. if (propertyType == QMetaType::UnknownType && tag != TypeConverter::NoTag) {
  421. const auto tList = q->typesForTag(tag);
  422. for (auto typeId : tList) {
  423. // if any of those types has a working converter, just use that one
  424. auto res = findDeserConverter(typeId, tag, type);
  425. if (res) {
  426. propertyType = typeId;
  427. return res;
  428. }
  429. }
  430. }
  431. // third: check if already cached
  432. if (auto converter = deserCache.get(propertyType);
  433. converter && converter->canDeserialize(propertyType, tag, type) > 0) {
  434. qCDebug(logSerializer) << "Found cached deserialization converter" << converter->name()
  435. << "for type" << QMetaTypeName(propertyType)
  436. << LogTag{tag}
  437. << "and CBOR-type" << type;
  438. return converter;
  439. }
  440. // fourth: check if the list of explicit converters has a matching one
  441. QReadLocker cLocker{&typeConverters.lock};
  442. auto throwWrongTag = false;
  443. std::optional<std::pair<QSharedPointer<TypeConverter>, int>> guessConverter;
  444. for (const auto &converter : qAsConst(typeConverters.store)) {
  445. if (converter) {
  446. auto testType = propertyType;
  447. switch (converter->canDeserialize(testType, tag, type)) {
  448. case TypeConverter::Negative:
  449. continue;
  450. case TypeConverter::WrongTag:
  451. throwWrongTag = true;
  452. continue;
  453. case TypeConverter::Guessed:
  454. if (!guessConverter)
  455. guessConverter = std::make_pair(converter, testType);
  456. continue;
  457. case TypeConverter::Positive:
  458. break;
  459. }
  460. // add converter to cache (only happens for positive cases)
  461. deserCache.add(propertyType, converter);
  462. qCDebug(logSerializer) << "Found and cached deserialization converter" << converter->name()
  463. << "for type" << QMetaTypeName(propertyType)
  464. << LogTag{tag}
  465. << "and CBOR-type" << type;
  466. return converter;
  467. }
  468. }
  469. cLocker.unlock();
  470. // fifth: if a guessed converter is available, use that one
  471. if (guessConverter) {
  472. // extract converter from info;
  473. auto &[converter, newType] = *guessConverter;
  474. // if valid, add to cache, set the type and return
  475. if (converter) {
  476. // add converter to list and cache
  477. propertyType = newType;
  478. deserCache.add(propertyType, converter);
  479. qCDebug(logSerializer) << "Found and cached deserialization converter" << converter->name()
  480. << "by guessing the data with CBOR-tag" << tag
  481. << "and CBOR-type" << type
  482. << "is of type" << QMetaTypeName(propertyType);
  483. return converter;
  484. }
  485. }
  486. // sixth: if a wrong tag mark was set, throw an expection
  487. if (throwWrongTag) {
  488. throw DeserializationException{QByteArray{"Found converter able to handle data of type "} +
  489. QMetaTypeName(propertyType) +
  490. ", but the given CBOR tag " +
  491. QByteArray::number(static_cast<quint64>(tag)) +
  492. " is not convertible to that type."};
  493. }
  494. // seventh: no converter found: return default converter
  495. qCDebug(logSerializer) << "Unable to find deserialization converte for type" << QMetaTypeName(propertyType)
  496. << LogTag{tag}
  497. << "and CBOR-type" << type
  498. << "- falling back to default CBOR to QVariant conversion";
  499. return nullptr;
  500. }
  501. void SerializerBasePrivate::updateConverterStore() const
  502. {
  503. Q_Q(const SerializerBase);
  504. QReadLocker fLocker{&typeConverterFactoryLock};
  505. if (typeConverterFactories.size() > typeConverters.factoryOffset.loadAcquire()) {
  506. QWriteLocker cLocker{&typeConverters.lock};
  507. auto max = typeConverterFactories.size();
  508. for (auto i = typeConverters.factoryOffset.loadAcquire(); i < max; ++i) {
  509. auto converter = typeConverterFactories[i]->createConverter();
  510. if (converter) {
  511. converter->setHelper(q);
  512. typeConverters.insertSorted(converter, cLocker);
  513. serCache.clear();
  514. deserCache.clear();
  515. qCDebug(logSerializer) << "Found and added new global converter:" << converter->name();
  516. }
  517. }
  518. typeConverters.factoryOffset.storeRelease(typeConverterFactories.size());
  519. }
  520. }
  521. int SerializerBasePrivate::getEnumId(QMetaEnum metaEnum, bool ser) const
  522. {
  523. QByteArray eName = metaEnum.name();
  524. if (const QByteArray scope = metaEnum.scope(); !scope.isEmpty())
  525. eName = scope + "::" + eName;
  526. #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  527. const auto eTypeId = QMetaType::type(eName);
  528. #else
  529. const auto eTypeId = QMetaType::fromName(eName).id();
  530. #endif
  531. if (eTypeId == QMetaType::UnknownType) {
  532. if (ser)
  533. throw SerializationException{"Unable to determine typeid of meta enum " + eName};
  534. else
  535. throw DeserializationException{"Unable to determine typeid of meta enum " + eName};
  536. } else
  537. return eTypeId;
  538. }
  539. QCborValue SerializerBasePrivate::serializeValue(int propertyType, const QVariant &value) const
  540. {
  541. Q_UNUSED(propertyType)
  542. return QCborValue::fromVariant(value);
  543. }
  544. QVariant SerializerBasePrivate::deserializeCborValue(int propertyType, const QCborValue &value) const
  545. {
  546. Q_Q(const SerializerBase);
  547. // perform strict validations
  548. if (validationFlags.testFlag(ValidationFlag::StrictBasicTypes)) {
  549. auto doThrow = false;
  550. QList<QCborTag> expectedTags;
  551. const auto testValue = value.isTag() ? value.taggedValue() : value;
  552. switch (propertyType) {
  553. case QMetaType::Bool:
  554. if (!testValue.isBool())
  555. doThrow = true;
  556. break;
  557. case QMetaType::Int:
  558. case QMetaType::UInt:
  559. case QMetaType::Long:
  560. case QMetaType::LongLong:
  561. case QMetaType::Short:
  562. case QMetaType::ULong:
  563. case QMetaType::ULongLong:
  564. case QMetaType::UShort:
  565. case QMetaType::SChar:
  566. case QMetaType::UChar:
  567. if (!testValue.isInteger())
  568. doThrow = true;
  569. break;
  570. case QMetaType::Float:
  571. case QMetaType::Double:
  572. if (!testValue.isDouble())
  573. doThrow = true;
  574. break;
  575. case QMetaType::Char:
  576. case QMetaType::QChar:
  577. case QMetaType::QString:
  578. expectedTags = {
  579. TypeConverter::NoTag,
  580. static_cast<QCborTag>(QCborKnownTags::Base64),
  581. static_cast<QCborTag>(QCborKnownTags::Base64url)
  582. };
  583. Q_FALLTHROUGH();
  584. case QMetaType::QColor:
  585. case QMetaType::QFont:
  586. if (!testValue.isString())
  587. doThrow = true;
  588. break;
  589. case QMetaType::QByteArray:
  590. expectedTags = {
  591. TypeConverter::NoTag,
  592. static_cast<QCborTag>(QCborKnownTags::ExpectedBase64),
  593. static_cast<QCborTag>(QCborKnownTags::ExpectedBase64url),
  594. static_cast<QCborTag>(QCborKnownTags::ExpectedBase16)
  595. };
  596. if (!testValue.isByteArray())
  597. doThrow = true;
  598. break;
  599. case QMetaType::Nullptr:
  600. if (!testValue.isNull())
  601. doThrow = true;
  602. break;
  603. case QMetaType::QUrl:
  604. if (!value.isUrl()) {
  605. if (testValue.isString())
  606. expectedTags = {static_cast<QCborTag>(QCborKnownTags::Url)};
  607. else
  608. doThrow = true;
  609. }
  610. break;
  611. case QMetaType::QUuid:
  612. if (!value.isUuid()) {
  613. if (testValue.isByteArray())
  614. expectedTags = {static_cast<QCborTag>(QCborKnownTags::Uuid)};
  615. else
  616. doThrow = true;
  617. }
  618. break;
  619. case QMetaType::QRegularExpression:
  620. if (!value.isRegularExpression()) {
  621. if (testValue.isString())
  622. expectedTags = {static_cast<QCborTag>(QCborKnownTags::RegularExpression)};
  623. else
  624. doThrow = true;
  625. }
  626. break;
  627. default:
  628. break;
  629. }
  630. if (const auto mTag = q->typeTag(propertyType);
  631. mTag != TypeConverter::NoTag &&
  632. mTag != value.tag())
  633. doThrow = true;
  634. else if (!expectedTags.isEmpty() &&
  635. !expectedTags.contains(value.tag()))
  636. doThrow = true;
  637. if (doThrow) {
  638. throw DeserializationException(QByteArray("Failed to deserialze CBOR-value to type ") +
  639. QMetaTypeName(propertyType) +
  640. QByteArray(" because the given CBOR-value failed strict validation"));
  641. }
  642. }
  643. return value.toVariant();
  644. }
  645. QVariant SerializerBasePrivate::deserializeJsonValue(int propertyType, const QCborValue &value) const
  646. {
  647. // perform strict validations
  648. if (validationFlags.testFlag(ValidationFlag::StrictBasicTypes)) {
  649. auto doThrow = false;
  650. switch (propertyType) {
  651. case QMetaType::Bool:
  652. if (!value.isBool())
  653. doThrow = true;
  654. break;
  655. case QMetaType::Int:
  656. case QMetaType::UInt:
  657. case QMetaType::Long:
  658. case QMetaType::LongLong:
  659. case QMetaType::Short:
  660. case QMetaType::ULong:
  661. case QMetaType::ULongLong:
  662. case QMetaType::UShort:
  663. case QMetaType::SChar:
  664. case QMetaType::UChar:
  665. if (value.isDouble()) {
  666. if (auto val = value.toDouble(); trunc(val) != val)
  667. doThrow = true;
  668. } else if (!value.isInteger())
  669. doThrow = true;
  670. break;
  671. case QMetaType::QChar:
  672. case QMetaType::QString:
  673. case QMetaType::Char:
  674. case QMetaType::QColor:
  675. case QMetaType::QUrl:
  676. case QMetaType::QFont:
  677. case QMetaType::QUuid:
  678. if (!value.isString())
  679. doThrow = true;
  680. break;
  681. case QMetaType::Nullptr:
  682. if (!value.isNull())
  683. doThrow = true;
  684. break;
  685. case QMetaType::Float:
  686. case QMetaType::Double:
  687. if (!value.isDouble())
  688. doThrow = true;
  689. break;
  690. default:
  691. break;
  692. }
  693. if (doThrow) {
  694. throw DeserializationException(QByteArray("Failed to deserialze JSON-value to type ") +
  695. QMetaTypeName(propertyType) +
  696. QByteArray("because the given JSON-value failed strict validation"));
  697. }
  698. }
  699. // special case: QRegularExpression, is missing a converter (and cannot be registered)
  700. if (propertyType == QMetaType::QRegularExpression &&
  701. value.isString())
  702. return QRegularExpression{value.toString()};
  703. else
  704. return value.toVariant();
  705. }