1 | // Copyright (C) 2023 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include <QtProtobuf/qprotobufjsonserializer.h> |
5 | |
6 | #include <QtProtobuf/private/protobuffieldpresencechecker_p.h> |
7 | #include <QtProtobuf/private/protobufscalarjsonserializers_p.h> |
8 | #include <QtProtobuf/private/qprotobufdeserializerbase_p.h> |
9 | #include <QtProtobuf/private/qprotobufjsonserializer_p.h> |
10 | #include <QtProtobuf/private/qprotobufregistration_p.h> |
11 | #include <QtProtobuf/private/qprotobufserializerbase_p.h> |
12 | #include <QtProtobuf/private/qtprotobufdefs_p.h> |
13 | #include <QtProtobuf/private/qtprotobufserializerhelpers_p.h> |
14 | |
15 | #include <QtCore/qcoreapplication.h> |
16 | #include <QtCore/qdatetime.h> |
17 | #include <QtCore/qhash.h> |
18 | #include <QtCore/qjsonarray.h> |
19 | #include <QtCore/qjsondocument.h> |
20 | #include <QtCore/qjsonobject.h> |
21 | #include <QtCore/qreadwritelock.h> |
22 | #include <QtCore/qtimezone.h> |
23 | #include <QtCore/qvariant.h> |
24 | |
25 | #include <cmath> |
26 | |
27 | QT_BEGIN_NAMESPACE |
28 | |
29 | /*! |
30 | \class QProtobufJsonSerializer |
31 | \inmodule QtProtobuf |
32 | \since 6.7 |
33 | \brief The QProtobufJsonSerializer class is an interface that represents |
34 | basic functions for serialization/deserialization of QProtobufMessage |
35 | objects to JSON. |
36 | |
37 | The QProtobufJsonSerializer class registers serializers/deserializers for |
38 | classes implementing a protobuf message, inheriting \l QProtobufMessage. These |
39 | classes are generated automatically, based on a \c{.proto} file, using the CMake |
40 | function \l qt_add_protobuf or by running |
41 | \l {The qtprotobufgen Tool} {qtprotobufgen} directly. |
42 | */ |
43 | |
44 | using namespace Qt::StringLiterals; |
45 | using namespace QtProtobufPrivate; |
46 | using namespace ProtobufScalarJsonSerializers; |
47 | |
48 | namespace { |
49 | |
50 | struct JsonHandlerRegistry |
51 | { |
52 | void registerHandler(QMetaType metaType, QtProtobufPrivate::CustomJsonSerializer serializer, |
53 | QtProtobufPrivate::CustomJsonDeserializer deserializer) |
54 | { |
55 | QWriteLocker locker(&m_lock); |
56 | m_registry[metaType] = { serializer, deserializer }; |
57 | } |
58 | |
59 | QtProtobufPrivate::CustomJsonSerializer findSerializer(QMetaType metaType) |
60 | { |
61 | QReadLocker locker(&m_lock); |
62 | const auto it = m_registry.constFind(key: metaType); |
63 | if (it != m_registry.constEnd()) |
64 | return it.value().first; |
65 | return nullptr; |
66 | } |
67 | |
68 | QtProtobufPrivate::CustomJsonDeserializer findDeserializer(QMetaType metaType) |
69 | { |
70 | QReadLocker locker(&m_lock); |
71 | const auto it = m_registry.constFind(key: metaType); |
72 | if (it != m_registry.constEnd()) |
73 | return it.value().second; |
74 | return nullptr; |
75 | } |
76 | |
77 | private: |
78 | using Handler = std::pair<QtProtobufPrivate::CustomJsonSerializer, |
79 | QtProtobufPrivate::CustomJsonDeserializer>; |
80 | QReadWriteLock m_lock; |
81 | QHash<QMetaType, Handler> m_registry; |
82 | }; |
83 | Q_GLOBAL_STATIC(JsonHandlerRegistry, jsonHandlersRegistry) |
84 | |
85 | inline QString convertJsonKeyToJsonName(QStringView name) |
86 | { |
87 | QString result; |
88 | result.reserve(asize: name.size()); |
89 | bool nextUpperCase = false; |
90 | for (const auto &c : name) { |
91 | if (c == QChar::fromLatin1(c: '_')) { |
92 | nextUpperCase = true; |
93 | continue; |
94 | } |
95 | result.append(c: nextUpperCase ? c.toUpper() : c); |
96 | nextUpperCase = false; |
97 | } |
98 | return result; |
99 | } |
100 | |
101 | } |
102 | |
103 | void QtProtobufPrivate::registerCustomJsonHandler(QMetaType metaType, |
104 | QtProtobufPrivate::CustomJsonSerializer |
105 | serializer, |
106 | QtProtobufPrivate::CustomJsonDeserializer |
107 | deserializer) |
108 | { |
109 | jsonHandlersRegistry->registerHandler(metaType, serializer, deserializer); |
110 | } |
111 | |
112 | QtProtobufPrivate::CustomJsonSerializer |
113 | QtProtobufPrivate::findCustomJsonSerializer(QMetaType metaType) |
114 | { |
115 | return jsonHandlersRegistry->findSerializer(metaType); |
116 | } |
117 | |
118 | QtProtobufPrivate::CustomJsonDeserializer |
119 | QtProtobufPrivate::findCustomJsonDeserializer(QMetaType metaType) |
120 | { |
121 | return jsonHandlersRegistry->findDeserializer(metaType); |
122 | } |
123 | |
124 | class QProtobufJsonSerializerImpl final : public QProtobufSerializerBase |
125 | { |
126 | public: |
127 | QProtobufJsonSerializerImpl() = default; |
128 | ~QProtobufJsonSerializerImpl(); |
129 | |
130 | const QJsonObject &result() const { return m_result; } |
131 | |
132 | void reset(); |
133 | |
134 | protected: |
135 | void serializeMessageField(const QProtobufMessage *message, |
136 | const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) override; |
137 | |
138 | private: |
139 | bool serializeEnum(QVariant &value, const QProtobufFieldInfo &fieldInfo) override; |
140 | bool serializeScalarField(const QVariant &value, const QProtobufFieldInfo &fieldInfo) override; |
141 | void serializeMessageFieldBegin() override; |
142 | void serializeMessageFieldEnd(const QProtobufMessage *message, |
143 | const QProtobufFieldInfo &fieldInfo) override; |
144 | |
145 | QJsonObject m_result; |
146 | QList<QJsonObject> m_state; |
147 | |
148 | Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerImpl) |
149 | }; |
150 | |
151 | class QProtobufJsonSerializerPrivate; |
152 | class QProtobufJsonDeserializerImpl final : public QProtobufDeserializerBase |
153 | { |
154 | public: |
155 | explicit QProtobufJsonDeserializerImpl(QProtobufJsonSerializerPrivate *parent); |
156 | ~QProtobufJsonDeserializerImpl(); |
157 | |
158 | void reset(QJsonObject obj); |
159 | |
160 | void setError(QAbstractProtobufSerializer::Error error, QAnyStringView errorString) override; |
161 | void setUnexpectedEndOfStreamError(); |
162 | void setInvalidFormatError(); |
163 | |
164 | protected: |
165 | bool deserializeMessageField(QProtobufMessage *message) override; |
166 | |
167 | private: |
168 | bool deserializeEnum(QVariant &value, |
169 | const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) override; |
170 | int nextFieldIndex(QProtobufMessage *message) override; |
171 | bool deserializeScalarField(QVariant &, const QtProtobufPrivate::QProtobufFieldInfo &) override; |
172 | |
173 | struct JsonDeserializerState |
174 | { |
175 | JsonDeserializerState(const QJsonObject &obj) : obj(obj) { } |
176 | |
177 | QJsonObject obj = {}; |
178 | int index = 0; |
179 | QJsonValue scalarValue = {QJsonValue::Undefined}; |
180 | }; |
181 | |
182 | QList<JsonDeserializerState> m_state; |
183 | QProtobufJsonSerializerPrivate *m_parent = nullptr; |
184 | }; |
185 | |
186 | class QProtobufJsonSerializerPrivate final |
187 | { |
188 | Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerPrivate) |
189 | public: |
190 | using Serializer = std::function<QJsonValue(const QVariant &)>; |
191 | using Deserializer = std::function<QVariant(const QJsonValue&, bool &ok)>; |
192 | |
193 | struct SerializationHandlers { |
194 | // serializer assigned to class |
195 | Serializer serializer; |
196 | // deserializer assigned to class |
197 | Deserializer deserializer; |
198 | ProtobufFieldPresenceChecker::Function isPresent; |
199 | }; |
200 | |
201 | template <typename T> |
202 | static SerializationHandlers createCommonHandler() |
203 | { |
204 | return { serializeCommon<T>, deserializeCommon<T>, |
205 | ProtobufFieldPresenceChecker::isPresent<T> }; |
206 | } |
207 | |
208 | template <typename L, typename T> |
209 | static SerializationHandlers createCommonListHandler() |
210 | { |
211 | return { serializeList<L>, deserializeList<L, T>, |
212 | ProtobufFieldPresenceChecker::isPresent<L> }; |
213 | } |
214 | |
215 | template<typename T, if_json_floating_point<T> = true> |
216 | static bool isPresent(const QVariant &value) |
217 | { |
218 | const T val = value.value<T>(); |
219 | return val != 0 || std::signbit(val); |
220 | } |
221 | |
222 | using SerializerRegistry = QHash<int/*metatypeid*/, SerializationHandlers>; |
223 | |
224 | QProtobufJsonSerializerPrivate(); |
225 | ~QProtobufJsonSerializerPrivate() = default; |
226 | |
227 | void clearError(); |
228 | |
229 | QAbstractProtobufSerializer::Error lastError = QAbstractProtobufSerializer::Error::None; |
230 | QString lastErrorString; |
231 | |
232 | static SerializerRegistry handlers; |
233 | |
234 | QProtobufJsonSerializerImpl serializer; |
235 | QProtobufJsonDeserializerImpl deserializer; |
236 | }; |
237 | |
238 | QProtobufJsonSerializerImpl::~QProtobufJsonSerializerImpl() = default; |
239 | |
240 | void QProtobufJsonSerializerImpl::reset() |
241 | { |
242 | m_result = {}; |
243 | m_state.clear(); |
244 | } |
245 | |
246 | void QProtobufJsonSerializerImpl::serializeMessageField(const QProtobufMessage *message, |
247 | const QtProtobufPrivate::QProtobufFieldInfo |
248 | &fieldInfo) |
249 | { |
250 | if (!message) |
251 | return; |
252 | |
253 | const auto *metaObject = QtProtobufSerializerHelpers::messageMetaObject(message); |
254 | |
255 | if (auto *serializer = QtProtobufPrivate::findCustomJsonSerializer(metaType: metaObject->metaType())) { |
256 | if (const QJsonValue value = serializer(message); !value.isUndefined()) { |
257 | if (fieldInfo.fieldFlags().testAnyFlags(flags: QtProtobufPrivate::FieldFlag::Repeated)) { |
258 | auto array = m_result.value(key: fieldInfo.jsonName().toString()).toArray(); |
259 | array.append(value); |
260 | m_result.insert(key: fieldInfo.jsonName().toString(), value: array); |
261 | } else { |
262 | m_result.insert(key: fieldInfo.jsonName().toString(), value); |
263 | } |
264 | } |
265 | } else { |
266 | QProtobufSerializerBase::serializeMessageField(message, fieldInfo); |
267 | } |
268 | } |
269 | |
270 | bool QProtobufJsonSerializerImpl::serializeEnum(QVariant &value, |
271 | const QProtobufFieldInfo &fieldInfo) |
272 | |
273 | { |
274 | const auto jsonName = fieldInfo.jsonName(); |
275 | if (fieldInfo.fieldFlags().testFlag(flag: QtProtobufPrivate::FieldFlag::Repeated)) { |
276 | if (!value.convert(type: QMetaType::fromType<QStringList>())) |
277 | return false; |
278 | if (!ProtobufFieldPresenceChecker::isPresent<QStringList>(value)) |
279 | return true; |
280 | m_result.insert(key: jsonName.toString(), value: serializeList<QStringList>(propertyValue: value)); |
281 | } else { |
282 | if (!value.convert(type: QMetaType::fromType<QString>())) |
283 | return false; |
284 | if (!ProtobufFieldPresenceChecker::isPresent<QString>(value) |
285 | && !isOneofOrOptionalField(flags: fieldInfo.fieldFlags())) { |
286 | return true; |
287 | } |
288 | m_result.insert(key: jsonName.toString(), value: serializeCommon<QString>(propertyValue: value)); |
289 | } |
290 | return true; |
291 | } |
292 | |
293 | bool QProtobufJsonSerializerImpl::serializeScalarField(const QVariant &value, |
294 | const QProtobufFieldInfo &fieldInfo) |
295 | { |
296 | const auto it = QProtobufJsonSerializerPrivate::handlers.constFind(key: value.userType()); |
297 | // Is not a protobuf scalar value type |
298 | if (it == QProtobufJsonSerializerPrivate::handlers.cend()) |
299 | return false; |
300 | |
301 | // Field is empty |
302 | if (!it->isPresent(value) && !isOneofOrOptionalField(flags: fieldInfo.fieldFlags())) |
303 | return true; |
304 | |
305 | // If serializer is not defined we should use the standard QJsonValue cast from variant |
306 | m_result.insert(key: fieldInfo.jsonName().toString(), |
307 | value: it->serializer ? it->serializer(value) : QJsonValue::fromVariant(variant: value)); |
308 | return true; |
309 | } |
310 | |
311 | void QProtobufJsonSerializerImpl::serializeMessageFieldBegin() |
312 | { |
313 | m_state.emplaceBack(args: std::move(m_result)); |
314 | m_result = {}; |
315 | } |
316 | |
317 | void QProtobufJsonSerializerImpl::serializeMessageFieldEnd(const QProtobufMessage *message, |
318 | const QProtobufFieldInfo &field) |
319 | { |
320 | QJsonObject store = m_state.takeLast(); |
321 | QString fieldName = field.jsonName().toString(); |
322 | if (field.fieldFlags().testFlag(flag: QtProtobufPrivate::FieldFlag::Repeated)) { |
323 | // Repeated fields are stored in array property |
324 | // "repeatedField": [{...}, {...}, ...] |
325 | QJsonArray array = store.value(key: fieldName).toArray(); |
326 | array.append(value: m_result); |
327 | store.insert(key: fieldName, value: array); |
328 | } else if (field.fieldFlags().testFlag(flag: QtProtobufPrivate::FieldFlag::Map)) { |
329 | // Maps are stored as fields in inner JSON object |
330 | // "mapField": { "key1": "value1", ... } |
331 | QJsonObject mapObject = store.value(key: fieldName).toObject(); |
332 | // We don't need to serialize key in general, since all JSON object fields should be |
333 | // represented as strings, and types that can be map keys have valid string converters. |
334 | mapObject.insert(key: message->property(propertyName: "key").toString(), value: m_result.value(key: "value"_L1)); |
335 | store.insert(key: fieldName, value: mapObject); |
336 | } else { |
337 | store.insert(key: fieldName, value: m_result); |
338 | } |
339 | m_result = store; |
340 | } |
341 | |
342 | QProtobufJsonDeserializerImpl::QProtobufJsonDeserializerImpl(QProtobufJsonSerializerPrivate *parent) |
343 | : m_parent(parent) |
344 | { |
345 | } |
346 | |
347 | QProtobufJsonDeserializerImpl::~QProtobufJsonDeserializerImpl() |
348 | = default; |
349 | |
350 | void QProtobufJsonDeserializerImpl::reset(QJsonObject obj) |
351 | { |
352 | clearCachedValue(); |
353 | m_state.clear(); |
354 | if (!obj.isEmpty()) |
355 | m_state.push_back(t: { obj }); |
356 | } |
357 | |
358 | void QProtobufJsonDeserializerImpl::setError(QAbstractProtobufSerializer::Error error, |
359 | QAnyStringView errorString) |
360 | { |
361 | m_parent->lastError = error; |
362 | m_parent->lastErrorString = errorString.toString(); |
363 | } |
364 | |
365 | bool QProtobufJsonDeserializerImpl::deserializeMessageField(QProtobufMessage *message) |
366 | { |
367 | if (!message) |
368 | return true; |
369 | |
370 | const auto &value = m_state.last().scalarValue; |
371 | if (!value.isUndefined()) { |
372 | const auto *metaObject = QtProtobufSerializerHelpers::messageMetaObject(message); |
373 | if (auto *deserializer = QtProtobufPrivate::findCustomJsonDeserializer(metaType: metaObject |
374 | ->metaType())) { |
375 | return deserializer(message, value); |
376 | } |
377 | setInvalidFormatError(); |
378 | return false; |
379 | } |
380 | return QProtobufDeserializerBase::deserializeMessageField(message); |
381 | } |
382 | |
383 | bool QProtobufJsonDeserializerImpl::deserializeEnum(QVariant &value, |
384 | const QtProtobufPrivate::QProtobufFieldInfo |
385 | &fieldInfo) |
386 | { |
387 | bool ok = false; |
388 | auto &state = m_state.last(); |
389 | if (fieldInfo.fieldFlags().testFlag(flag: QtProtobufPrivate::FieldFlag::Repeated)) { |
390 | value = deserializeList<QStringList, QString>(value: state.scalarValue, ok); |
391 | } else { |
392 | // It's allowed to pass single enum value as numeric value. |
393 | // Make the backward value conversion and deserialize enum as QtProtobuf::int64. |
394 | if (state.scalarValue.isString()) { |
395 | value = deserializeCommon<QString>(value: state.scalarValue, ok); |
396 | } else { |
397 | value = deserializeCommon<QtProtobuf::int64>(value: state.scalarValue, ok); |
398 | } |
399 | } |
400 | |
401 | return ok; |
402 | } |
403 | |
404 | int QProtobufJsonDeserializerImpl::nextFieldIndex(QProtobufMessage *message) |
405 | { |
406 | const auto *ordering = message->propertyOrdering(); |
407 | const int fieldCount = ordering->fieldCount(); |
408 | if (fieldCount == 0) |
409 | return -1; |
410 | |
411 | JsonDeserializerState &state = m_state.last(); |
412 | state.scalarValue = {}; |
413 | while (state.index < fieldCount) { |
414 | const auto jsonName = ordering->jsonName(index: state.index); |
415 | const auto keys = state.obj.keys(); |
416 | const auto it = std::find_if(first: keys.constBegin(), last: keys.constEnd(), |
417 | pred: [&jsonName](const auto &val) { |
418 | return jsonName == val |
419 | || jsonName == convertJsonKeyToJsonName(val); |
420 | }); |
421 | |
422 | if (it == keys.constEnd()) { |
423 | ++state.index; |
424 | continue; |
425 | } |
426 | |
427 | QtProtobufPrivate::FieldFlags flags = ordering->fieldFlags(index: state.index); |
428 | QJsonValue val = state.obj.value(key: *it); |
429 | if (val.isNull()) { |
430 | ++state.index; |
431 | continue; |
432 | } |
433 | |
434 | int index = state.index; |
435 | if (flags.testFlags(flags: { QtProtobufPrivate::FieldFlag::Message, |
436 | QtProtobufPrivate::FieldFlag::Repeated })) { |
437 | if (!val.isArray()) { |
438 | setInvalidFormatError(); |
439 | return -1; |
440 | } |
441 | |
442 | auto array = val.toArray(); |
443 | if (array.isEmpty()) { |
444 | ++state.index; |
445 | state.scalarValue = {}; |
446 | continue; |
447 | } |
448 | |
449 | auto nextValue = array.takeAt(i: 0); |
450 | if (nextValue.isNull()) { |
451 | setInvalidFormatError(); |
452 | return -1; |
453 | } |
454 | |
455 | state.obj.insert(key: *it, value: array); |
456 | if (nextValue.isObject()) { |
457 | m_state.push_back(t: { nextValue.toObject() }); |
458 | } else { |
459 | state.scalarValue = nextValue; |
460 | } |
461 | } else if (flags.testFlag(flag: QtProtobufPrivate::FieldFlag::Map)) { |
462 | if (!val.isObject()) { |
463 | setInvalidFormatError(); |
464 | return -1; |
465 | } |
466 | |
467 | auto mapObject = val.toObject(); |
468 | if (mapObject.isEmpty()) { |
469 | ++state.index; |
470 | continue; |
471 | } |
472 | |
473 | QString key = mapObject.begin().key(); |
474 | QJsonObject nextObject; |
475 | nextObject.insert(key: "key"_L1, value: key); |
476 | nextObject.insert(key: "value"_L1, value: mapObject.take(key)); |
477 | state.obj.insert(key: *it, value: mapObject); |
478 | m_state.push_back(t: { nextObject }); |
479 | } else if (flags.testFlag(flag: QtProtobufPrivate::FieldFlag::Message)) { |
480 | if (val.isArray() || val.isUndefined()) { |
481 | setInvalidFormatError(); |
482 | return -1; |
483 | } |
484 | |
485 | if (val.isObject()) { |
486 | ++state.index; |
487 | m_state.push_back(t: { val.toObject() }); |
488 | } else { |
489 | state.scalarValue = val; |
490 | ++state.index; |
491 | } |
492 | } else { |
493 | state.scalarValue = val; |
494 | ++state.index; |
495 | } |
496 | return index; |
497 | } |
498 | |
499 | m_state.pop_back(); |
500 | return -1; |
501 | } |
502 | |
503 | bool QProtobufJsonDeserializerImpl::deserializeScalarField(QVariant &value, |
504 | const QProtobufFieldInfo &) |
505 | { |
506 | auto handler = QProtobufJsonSerializerPrivate::handlers.constFind(key: value.userType()); |
507 | if (handler == QProtobufJsonSerializerPrivate::handlers.constEnd() |
508 | || !handler.value().deserializer) { |
509 | return false; |
510 | } |
511 | |
512 | bool ok = false; |
513 | value = handler.value().deserializer(m_state.last().scalarValue, ok); |
514 | if (!ok) |
515 | setInvalidFormatError(); |
516 | return true; |
517 | } |
518 | |
519 | void QProtobufJsonDeserializerImpl::setUnexpectedEndOfStreamError() |
520 | { |
521 | setError(error: QAbstractProtobufSerializer::Error::UnexpectedEndOfStream, |
522 | errorString: QCoreApplication::translate(context: "QtProtobuf", key: "JSON: Unexpected end of stream")); |
523 | } |
524 | |
525 | void QProtobufJsonDeserializerImpl::setInvalidFormatError() |
526 | { |
527 | setError(error: QAbstractProtobufSerializer::Error::InvalidFormat, |
528 | errorString: QCoreApplication::translate(context: "QtProtobuf", |
529 | key: "JSON: One or more fields have invalid format")); |
530 | } |
531 | |
532 | QProtobufJsonSerializerPrivate::SerializerRegistry QProtobufJsonSerializerPrivate::handlers = {}; |
533 | |
534 | QProtobufJsonSerializerPrivate::QProtobufJsonSerializerPrivate() : deserializer(this) |
535 | { |
536 | [[maybe_unused]] static bool initialized = []() -> bool { |
537 | handlers[qMetaTypeId<QtProtobuf::int32>()] = createCommonHandler<QtProtobuf::int32>(); |
538 | handlers[qMetaTypeId<QtProtobuf::sfixed32>()] = createCommonHandler<QtProtobuf::sfixed32>(); |
539 | handlers[qMetaTypeId<QtProtobuf::sint32>()] = createCommonHandler<QtProtobuf::sint32>(); |
540 | handlers[qMetaTypeId<QtProtobuf::uint32>()] = createCommonHandler<QtProtobuf::uint32>(); |
541 | handlers[qMetaTypeId<QtProtobuf::fixed32>()] = createCommonHandler<QtProtobuf::fixed32>(); |
542 | handlers[qMetaTypeId<QtProtobuf::sint64>()] = createCommonHandler<QtProtobuf::sint64>(); |
543 | handlers[qMetaTypeId<QtProtobuf::int64>()] = createCommonHandler<QtProtobuf::int64>(); |
544 | handlers[qMetaTypeId<QtProtobuf::sfixed64>()] = createCommonHandler<QtProtobuf::sfixed64>(); |
545 | handlers[qMetaTypeId<QtProtobuf::uint64>()] = createCommonHandler<QtProtobuf::uint64>(); |
546 | handlers[qMetaTypeId<QtProtobuf::fixed64>()] = createCommonHandler<QtProtobuf::fixed64>(); |
547 | handlers[qMetaTypeId<bool>()] = createCommonHandler<bool>(); |
548 | handlers[QMetaType::QString] = createCommonHandler<QString>(); |
549 | handlers[QMetaType::QByteArray] = createCommonHandler<QByteArray>(); |
550 | handlers[QMetaType::Float] = { .serializer: serializeCommon<float>, .deserializer: deserializeCommon<float>, |
551 | .isPresent: QProtobufJsonSerializerPrivate::isPresent<float> }; |
552 | handlers[QMetaType::Double] = { .serializer: serializeCommon<double>, .deserializer: deserializeCommon<double>, |
553 | .isPresent: isPresent<double> }; |
554 | |
555 | handlers[qMetaTypeId<QtProtobuf::boolList>()] = createCommonListHandler< |
556 | QtProtobuf::boolList, bool>(); |
557 | handlers[qMetaTypeId<QtProtobuf::int32List>()] = createCommonListHandler< |
558 | QtProtobuf::int32List, QtProtobuf::int32>(); |
559 | handlers[qMetaTypeId<QtProtobuf::int64List>()] = createCommonListHandler< |
560 | QtProtobuf::int64List, QtProtobuf::int64>(); |
561 | handlers[qMetaTypeId<QtProtobuf::sint32List>()] = createCommonListHandler< |
562 | QtProtobuf::sint32List, QtProtobuf::sint32>(); |
563 | handlers[qMetaTypeId<QtProtobuf::sint64List>()] = createCommonListHandler< |
564 | QtProtobuf::sint64List, QtProtobuf::sint64>(); |
565 | handlers[qMetaTypeId<QtProtobuf::uint32List>()] = createCommonListHandler< |
566 | QtProtobuf::uint32List, QtProtobuf::uint32>(); |
567 | handlers[qMetaTypeId<QtProtobuf::uint64List>()] = createCommonListHandler< |
568 | QtProtobuf::uint64List, QtProtobuf::uint64>(); |
569 | handlers[qMetaTypeId<QtProtobuf::fixed32List>()] = createCommonListHandler< |
570 | QtProtobuf::fixed32List, QtProtobuf::fixed32>(); |
571 | handlers[qMetaTypeId<QtProtobuf::fixed64List>()] = createCommonListHandler< |
572 | QtProtobuf::fixed64List, QtProtobuf::fixed64>(); |
573 | handlers[qMetaTypeId<QtProtobuf::sfixed32List>()] = createCommonListHandler< |
574 | QtProtobuf::sfixed32List, QtProtobuf::sfixed32>(); |
575 | handlers[qMetaTypeId<QtProtobuf::sfixed64List>()] = createCommonListHandler< |
576 | QtProtobuf::sfixed64List, QtProtobuf::sfixed64>(); |
577 | handlers[qMetaTypeId<QtProtobuf::floatList>()] = createCommonListHandler< |
578 | QtProtobuf::floatList, float>(); |
579 | handlers[qMetaTypeId<QtProtobuf::doubleList>()] = createCommonListHandler< |
580 | QtProtobuf::doubleList, double>(); |
581 | handlers[qMetaTypeId<QStringList>()] = createCommonListHandler<QStringList, QString>(); |
582 | handlers[qMetaTypeId<QByteArrayList>()] = createCommonListHandler<QByteArrayList, |
583 | QByteArray>(); |
584 | return true; |
585 | }(); |
586 | } |
587 | |
588 | void QProtobufJsonSerializerPrivate::clearError() |
589 | { |
590 | lastError = QAbstractProtobufSerializer::Error::None; |
591 | lastErrorString.clear(); |
592 | } |
593 | |
594 | QProtobufJsonSerializer::QProtobufJsonSerializer() : d_ptr(new QProtobufJsonSerializerPrivate) |
595 | { |
596 | } |
597 | |
598 | QProtobufJsonSerializer::~QProtobufJsonSerializer() = default; |
599 | |
600 | /*! |
601 | Returns the last deserialization error for the serializer instance. |
602 | \sa lastErrorString() |
603 | */ |
604 | QAbstractProtobufSerializer::Error QProtobufJsonSerializer::lastError() const |
605 | { |
606 | return d_ptr->lastError; |
607 | } |
608 | |
609 | /*! |
610 | Returns the last deserialization error string for the serializer instance. |
611 | \sa lastError() |
612 | */ |
613 | QString QProtobufJsonSerializer::lastErrorString() const |
614 | { |
615 | return d_ptr->lastErrorString; |
616 | } |
617 | |
618 | QByteArray QProtobufJsonSerializer::serializeMessage(const QProtobufMessage *message) const |
619 | { |
620 | d_ptr->clearError(); |
621 | d_ptr->serializer.reset(); |
622 | d_ptr->serializer.serializeMessage(message); |
623 | auto result = QJsonDocument(d_ptr->serializer.result()).toJson(format: QJsonDocument::Compact); |
624 | d_ptr->serializer.reset(); |
625 | return result; |
626 | } |
627 | |
628 | bool QProtobufJsonSerializer::deserializeMessage(QProtobufMessage *message, |
629 | QByteArrayView data) const |
630 | { |
631 | d_ptr->clearError(); |
632 | QJsonParseError err; |
633 | auto document = QJsonDocument::fromJson(json: data.toByteArray(), error: &err); |
634 | if (err.error != QJsonParseError::NoError) { |
635 | d_ptr->deserializer.setUnexpectedEndOfStreamError(); |
636 | return false; |
637 | } |
638 | |
639 | if (!document.isObject()) { |
640 | d_ptr->deserializer.setInvalidFormatError(); |
641 | return false; |
642 | } |
643 | |
644 | if (auto obj = document.object(); !obj.isEmpty()) { |
645 | d_ptr->deserializer.reset(obj); |
646 | bool result = d_ptr->deserializer.deserializeMessage(message); |
647 | d_ptr->deserializer.reset(obj: {}); |
648 | return result; |
649 | } |
650 | return true; |
651 | } |
652 | |
653 | bool ProtobufScalarJsonSerializers::validateJsonNumberString(const QString &input) |
654 | { |
655 | static const QRegularExpression NumberValidator("^-?\\d+$"_L1); |
656 | return NumberValidator.match(subject: input).hasMatch(); |
657 | } |
658 | |
659 | QT_END_NAMESPACE |
660 |
Definitions
- JsonHandlerRegistry
- registerHandler
- findSerializer
- findDeserializer
- jsonHandlersRegistry
- convertJsonKeyToJsonName
- registerCustomJsonHandler
- findCustomJsonSerializer
- findCustomJsonDeserializer
- QProtobufJsonSerializerImpl
- QProtobufJsonSerializerImpl
- result
- QProtobufJsonSerializerImpl
- QProtobufJsonDeserializerImpl
- JsonDeserializerState
- JsonDeserializerState
- QProtobufJsonSerializerPrivate
- QProtobufJsonSerializerPrivate
- SerializationHandlers
- createCommonHandler
- createCommonListHandler
- isPresent
- ~QProtobufJsonSerializerPrivate
- ~QProtobufJsonSerializerImpl
- reset
- serializeMessageField
- serializeEnum
- serializeScalarField
- serializeMessageFieldBegin
- serializeMessageFieldEnd
- QProtobufJsonDeserializerImpl
- ~QProtobufJsonDeserializerImpl
- reset
- setError
- deserializeMessageField
- deserializeEnum
- nextFieldIndex
- deserializeScalarField
- setUnexpectedEndOfStreamError
- setInvalidFormatError
- handlers
- QProtobufJsonSerializerPrivate
- clearError
- QProtobufJsonSerializer
- ~QProtobufJsonSerializer
- lastError
- lastErrorString
- serializeMessage
- deserializeMessage
Start learning QML with our Intro Training
Find out more