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
27QT_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
44using namespace Qt::StringLiterals;
45using namespace QtProtobufPrivate;
46using namespace ProtobufScalarJsonSerializers;
47
48namespace {
49
50struct 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
77private:
78 using Handler = std::pair<QtProtobufPrivate::CustomJsonSerializer,
79 QtProtobufPrivate::CustomJsonDeserializer>;
80 QReadWriteLock m_lock;
81 QHash<QMetaType, Handler> m_registry;
82};
83Q_GLOBAL_STATIC(JsonHandlerRegistry, jsonHandlersRegistry)
84
85inline 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
103void QtProtobufPrivate::registerCustomJsonHandler(QMetaType metaType,
104 QtProtobufPrivate::CustomJsonSerializer
105 serializer,
106 QtProtobufPrivate::CustomJsonDeserializer
107 deserializer)
108{
109 jsonHandlersRegistry->registerHandler(metaType, serializer, deserializer);
110}
111
112QtProtobufPrivate::CustomJsonSerializer
113QtProtobufPrivate::findCustomJsonSerializer(QMetaType metaType)
114{
115 return jsonHandlersRegistry->findSerializer(metaType);
116}
117
118QtProtobufPrivate::CustomJsonDeserializer
119QtProtobufPrivate::findCustomJsonDeserializer(QMetaType metaType)
120{
121 return jsonHandlersRegistry->findDeserializer(metaType);
122}
123
124class QProtobufJsonSerializerImpl final : public QProtobufSerializerBase
125{
126public:
127 QProtobufJsonSerializerImpl() = default;
128 ~QProtobufJsonSerializerImpl();
129
130 const QJsonObject &result() const { return m_result; }
131
132 void reset();
133
134protected:
135 void serializeMessageField(const QProtobufMessage *message,
136 const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) override;
137
138private:
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
151class QProtobufJsonSerializerPrivate;
152class QProtobufJsonDeserializerImpl final : public QProtobufDeserializerBase
153{
154public:
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
164protected:
165 bool deserializeMessageField(QProtobufMessage *message) override;
166
167private:
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
186class QProtobufJsonSerializerPrivate final
187{
188 Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerPrivate)
189public:
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
238QProtobufJsonSerializerImpl::~QProtobufJsonSerializerImpl() = default;
239
240void QProtobufJsonSerializerImpl::reset()
241{
242 m_result = {};
243 m_state.clear();
244}
245
246void 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
270bool 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
293bool 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
311void QProtobufJsonSerializerImpl::serializeMessageFieldBegin()
312{
313 m_state.emplaceBack(args: std::move(m_result));
314 m_result = {};
315}
316
317void 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
342QProtobufJsonDeserializerImpl::QProtobufJsonDeserializerImpl(QProtobufJsonSerializerPrivate *parent)
343 : m_parent(parent)
344{
345}
346
347QProtobufJsonDeserializerImpl::~QProtobufJsonDeserializerImpl()
348 = default;
349
350void QProtobufJsonDeserializerImpl::reset(QJsonObject obj)
351{
352 clearCachedValue();
353 m_state.clear();
354 if (!obj.isEmpty())
355 m_state.push_back(t: { obj });
356}
357
358void QProtobufJsonDeserializerImpl::setError(QAbstractProtobufSerializer::Error error,
359 QAnyStringView errorString)
360{
361 m_parent->lastError = error;
362 m_parent->lastErrorString = errorString.toString();
363}
364
365bool 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
383bool 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
404int 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
503bool 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
519void QProtobufJsonDeserializerImpl::setUnexpectedEndOfStreamError()
520{
521 setError(error: QAbstractProtobufSerializer::Error::UnexpectedEndOfStream,
522 errorString: QCoreApplication::translate(context: "QtProtobuf", key: "JSON: Unexpected end of stream"));
523}
524
525void 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
532QProtobufJsonSerializerPrivate::SerializerRegistry QProtobufJsonSerializerPrivate::handlers = {};
533
534QProtobufJsonSerializerPrivate::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
588void QProtobufJsonSerializerPrivate::clearError()
589{
590 lastError = QAbstractProtobufSerializer::Error::None;
591 lastErrorString.clear();
592}
593
594QProtobufJsonSerializer::QProtobufJsonSerializer() : d_ptr(new QProtobufJsonSerializerPrivate)
595{
596}
597
598QProtobufJsonSerializer::~QProtobufJsonSerializer() = default;
599
600/*!
601 Returns the last deserialization error for the serializer instance.
602 \sa lastErrorString()
603*/
604QAbstractProtobufSerializer::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*/
613QString QProtobufJsonSerializer::lastErrorString() const
614{
615 return d_ptr->lastErrorString;
616}
617
618QByteArray 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
628bool 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
653bool ProtobufScalarJsonSerializers::validateJsonNumberString(const QString &input)
654{
655 static const QRegularExpression NumberValidator("^-?\\d+$"_L1);
656 return NumberValidator.match(subject: input).hasMatch();
657}
658
659QT_END_NAMESPACE
660

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtgrpc/src/protobuf/qprotobufjsonserializer.cpp