Browse Source

Complete json serialization

- Add extra interfaces begin/end to have possibility prepend/append
  values to serialized maps and lists
- Implement map and list serialization
- Implement json serialization tests
TODO: Map tests probably failing on windows because of descent
      ordering
Alexey Edelev 4 years ago
parent
commit
2aabfc4846

+ 43 - 0
src/protobuf/qabstractprotobufserializer.h

@@ -142,6 +142,16 @@ public:
      */
     virtual void deserializeObject(QObject *object, const QProtobufMetaObject &metaObject, QProtobufSelfcheckIterator &it) const = 0;
 
+    /*!
+     * \brief serializeListBegin Method called at the begining of object list serialization
+     * \param[in] metaProperty Information about property to be serialized
+     * \return Raw serialized data represented as byte array
+     */
+    virtual QByteArray serializeListBegin(const QProtobufMetaProperty &metaProperty) const {
+        Q_UNUSED(metaProperty);
+        return {};
+    }
+
     /*!
      * \brief serializeListObject Method called to serialize \a object as a part of list property
      * \param[in] object Pointer to object that will be serialized
@@ -151,6 +161,18 @@ public:
      */
     virtual QByteArray serializeListObject(const QObject *object, const QProtobufMetaObject &metaObject, const QProtobufMetaProperty &metaProperty) const = 0;
 
+    /*!
+     * \brief serializeListEnd Method called at the end of object list serialization
+     * \param[in] buffer Buffer at and of list serialization
+     * \param[in] metaProperty Information about property to be serialized
+     * \return Raw serialized data represented as byte array
+     */
+    virtual QByteArray serializeListEnd(QByteArray &buffer, const QProtobufMetaProperty &metaProperty) const {
+        Q_UNUSED(metaProperty);
+        Q_UNUSED(buffer);
+        return {};
+    }
+
     /*!
      * \brief deserializeListObject Deserializes an \a object from byte stream as part of list property
      * \param[out] object Pointer to pre-allocated object, that will be appended to list property
@@ -160,6 +182,16 @@ public:
      */
     virtual void deserializeListObject(QObject *object, const QProtobufMetaObject &metaObject, QProtobufSelfcheckIterator &it) const = 0;
 
+    /*!
+     * \brief serializeMapEnd Method called at the begining of map serialization
+     * \param[in] metaProperty Information about property to be serialized
+     * \return Raw serialized data represented as byte array
+     */
+    virtual QByteArray serializeMapBegin(const QProtobufMetaProperty &metaProperty) const {
+        Q_UNUSED(metaProperty);
+        return {};
+    }
+
     /*!
      * \brief serializeMapPair Serializes QMap pair of \a key and \a value to raw data buffer
      * \param[in] key Map key
@@ -171,6 +203,17 @@ public:
      */
     virtual QByteArray serializeMapPair(const QVariant &key, const QVariant &value, const QProtobufMetaProperty &metaProperty) const = 0;
 
+    /*!
+     * \brief serializeMapEnd Method called at the end of map serialization
+     * \param[in] buffer Buffer at and of list serialization
+     * \param[in] metaProperty Information about property to be serialized
+     * \return Raw serialized data represented as byte array
+     */
+    virtual QByteArray serializeMapEnd(QByteArray &buffer, const QProtobufMetaProperty &metaProperty) const {
+        Q_UNUSED(metaProperty);
+        return {};
+    }
+
     /*!
      * \brief deserializeMapPair Deserializes QMap pair of \a key and \a value from raw data
      * \param[out] key Buffer that will be used to store deserialized key. When passed to function, QVariant

+ 6 - 4
src/protobuf/qabstractprotobufserializer_p.h

@@ -94,10 +94,7 @@ void serializeList(const QtProtobuf::QAbstractProtobufSerializer *serializer, co
 
     qProtoDebug() << __func__ << "listValue.count" << list.count();
 
-    if (list.count() <= 0) {
-        return;
-    }
-
+    buffer.append(serializer->serializeListBegin(metaProperty));
     for (auto &value : list) {
         if (!value) {
             qProtoWarning() << "Null pointer in list";
@@ -105,6 +102,7 @@ void serializeList(const QtProtobuf::QAbstractProtobufSerializer *serializer, co
         }
         buffer.append(serializer->serializeListObject(value.data(), V::protobufMetaObject, metaProperty));
     }
+    buffer.append(serializer->serializeListEnd(buffer, metaProperty));
 }
 
 /*!
@@ -116,9 +114,11 @@ template<typename K, typename V,
 void serializeMap(const QtProtobuf::QAbstractProtobufSerializer *serializer, const QVariant &value, const QtProtobuf::QProtobufMetaProperty &metaProperty, QByteArray &buffer) {
     Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "Serializer is null");
     QMap<K,V> mapValue = value.value<QMap<K,V>>();
+    buffer.append(serializer->serializeMapBegin(metaProperty));
     for (auto it = mapValue.constBegin(); it != mapValue.constEnd(); it++) {
         buffer.append(serializer->serializeMapPair(QVariant::fromValue<K>(it.key()), QVariant::fromValue<V>(it.value()), metaProperty));
     }
+    buffer.append(serializer->serializeMapEnd(buffer, metaProperty));
 }
 
 /*!
@@ -130,6 +130,7 @@ template<typename K, typename V,
 void serializeMap(const QtProtobuf::QAbstractProtobufSerializer *serializer, const QVariant &value, const QtProtobuf::QProtobufMetaProperty &metaProperty, QByteArray &buffer) {
     Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "Serializer is null");
     QMap<K, QSharedPointer<V>> mapValue = value.value<QMap<K, QSharedPointer<V>>>();
+    buffer.append(serializer->serializeMapBegin(metaProperty));
     for (auto it = mapValue.constBegin(); it != mapValue.constEnd(); it++) {
         if (it.value().isNull()) {
             qProtoWarning() << __func__ << "Trying to serialize map value that contains nullptr";
@@ -137,6 +138,7 @@ void serializeMap(const QtProtobuf::QAbstractProtobufSerializer *serializer, con
         }
         buffer.append(serializer->serializeMapPair(QVariant::fromValue<K>(it.key()), QVariant::fromValue<V *>(it.value().data()), metaProperty));
     }
+    buffer.append(serializer->serializeMapEnd(buffer, metaProperty));
 }
 
 /*!

+ 35 - 12
src/protobuf/qprotobufjsonserializer.cpp

@@ -53,7 +53,7 @@ public:
         if (!ok) {
             return QByteArray("NaN");
         }
-        return QString::number(value, 'g').toUtf8();
+        return QString::number(static_cast<double>(value), 'g').toUtf8();
     }
 
     static QByteArray serializeString(const QVariant &propertyValue) {
@@ -140,13 +140,10 @@ public:
     }
     ~QProtobufJsonSerializerPrivate() = default;
 
-    QByteArray serializeProperty(const QVariant &propertyValue, const QProtobufMetaProperty &metaProperty) {
+    QByteArray serializeValue(const QVariant &propertyValue, const QProtobufMetaProperty &metaProperty) {
         QByteArray buffer;
-        buffer.append("\"");
-        buffer.append(metaProperty.protoPropertyName().toUtf8());
-        buffer.append("\":");
-        auto userType = metaProperty.userType();
-        auto &value = QtProtobufPrivate::findHandler(metaProperty.userType());
+        auto userType = propertyValue.userType();
+        auto &value = QtProtobufPrivate::findHandler(userType);
         if (value.serializer) {
             value.serializer(q_ptr, propertyValue, metaProperty, buffer);
         } else {
@@ -160,6 +157,10 @@ public:
         return buffer;
     }
 
+    QByteArray serializeProperty(const QVariant &propertyValue, const QProtobufMetaProperty &metaProperty) {
+        return QByteArray("\"") + metaProperty.protoPropertyName().toUtf8() + "\":" + serializeValue(propertyValue, metaProperty);
+    }
+
     QByteArray serializeObject(const QObject *object, const QProtobufMetaObject &metaObject) {
         QByteArray result = "{";
         for (const auto &field : metaObject.propertyOrdering) {
@@ -217,9 +218,22 @@ void QProtobufJsonSerializer::deserializeObject(QObject *object, const QProtobuf
     Q_UNUSED(metaObject)
 }
 
+QByteArray QProtobufJsonSerializer::serializeListBegin(const QProtobufMetaProperty &/*metaProperty*/) const
+{
+    return {"["};
+}
+
 QByteArray QProtobufJsonSerializer::serializeListObject(const QObject *object, const QProtobufMetaObject &metaObject, const QProtobufMetaProperty &/*metaProperty*/) const
 {
-    return dPtr->serializeObject(object, metaObject);
+    return dPtr->serializeObject(object, metaObject)+",";
+}
+
+QByteArray QProtobufJsonSerializer::serializeListEnd(QByteArray &buffer, const QProtobufMetaProperty &/*metaProperty*/) const
+{
+    if (buffer[buffer.size() - 1] == ',') {
+        buffer.resize(buffer.size() - 1);
+    }
+    return {"]"};
 }
 
 void QProtobufJsonSerializer::deserializeListObject(QObject *object, const QProtobufMetaObject &metaObject, QProtobufSelfcheckIterator &it) const
@@ -229,12 +243,21 @@ void QProtobufJsonSerializer::deserializeListObject(QObject *object, const QProt
     Q_UNUSED(metaObject)
 }
 
+QByteArray QProtobufJsonSerializer::serializeMapBegin(const QProtobufMetaProperty &/*metaProperty*/) const
+{
+    return {"{"};
+}
 QByteArray QProtobufJsonSerializer::serializeMapPair(const QVariant &key, const QVariant &value, const QProtobufMetaProperty &metaProperty) const
 {
-    Q_UNUSED(key)
-    Q_UNUSED(value)
-    Q_UNUSED(metaProperty)
-    return QByteArray();
+    return QByteArray("\"") + key.toString().toUtf8() + "\":" + dPtr->serializeValue(value, metaProperty) + ",";
+}
+
+QByteArray QProtobufJsonSerializer::serializeMapEnd(QByteArray &buffer, const QProtobufMetaProperty &/*metaProperty*/) const
+{
+    if (buffer[buffer.size() - 1] == ',') {
+        buffer.resize(buffer.size() - 1);
+    }
+    return {"}"};
 }
 
 void QProtobufJsonSerializer::deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const

+ 6 - 0
src/protobuf/qprotobufjsonserializer.h

@@ -49,10 +49,16 @@ protected:
     QByteArray serializeObject(const QObject *object, const QProtobufMetaObject &metaObject, const QProtobufMetaProperty &metaProperty) const override;
     void deserializeObject(QObject *object, const QProtobufMetaObject &metaObject, QProtobufSelfcheckIterator &it) const override;
 
+    QByteArray serializeListBegin(const QProtobufMetaProperty &metaProperty) const override;
     QByteArray serializeListObject(const QObject *object, const QProtobufMetaObject &metaObject, const QProtobufMetaProperty &metaProperty) const override;
+    QByteArray serializeListEnd(QByteArray &buffer, const QProtobufMetaProperty &metaProperty) const override;
+
     void deserializeListObject(QObject *object, const QProtobufMetaObject &metaObject, QProtobufSelfcheckIterator &it) const override;
 
+    QByteArray serializeMapBegin(const QProtobufMetaProperty &metaProperty) const override;
     QByteArray serializeMapPair(const QVariant &key, const QVariant &value, const QProtobufMetaProperty &metaProperty) const override;
+    QByteArray serializeMapEnd(QByteArray &buffer, const QProtobufMetaProperty &metaProperty) const override;
+
     void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const override;
 
     QByteArray serializeEnum(int64 value, const QMetaEnum &metaEnum, const QtProtobuf::QProtobufMetaProperty &metaProperty) const override;

+ 109 - 0
tests/test_protobuf/jsonserializationtest.cpp

@@ -461,5 +461,114 @@ TEST_F(JsonSerializationTest, SimpleEnumListMessageTest)
     EXPECT_STREQ(QString::fromUtf8(result).toStdString().c_str(), "{\"localEnumList\":[]}");
 }
 
+TEST_F(JsonSerializationTest, SimpleFixed32StringMapSerializeTest)
+{
+    SimpleFixed32StringMapMessage test;
+    test.setMapField({{10, {"ten"}}, {42, {"fourty two"}}, {15, {"fifteen"}}});
+    QByteArray result = test.serialize(serializer.get());
+
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"10\":\"ten\",\"15\":\"fifteen\",\"42\":\"fourty two\"}}");
+}
+
+TEST_F(JsonSerializationTest, SimpleSFixed32StringMapSerializeTest)
+{
+    SimpleSFixed32StringMapMessage test;
+    test.setMapField({{10, {"ten"}}, {-42, {"minus fourty two"}}, {15, {"fifteen"}}});
+    QByteArray result = test.serialize(serializer.get());
+
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"-42\":\"minus fourty two\",\"10\":\"ten\",\"15\":\"fifteen\"}}");
+}
+
+TEST_F(JsonSerializationTest, SimpleInt32StringMapSerializeTest)
+{
+    SimpleInt32StringMapMessage test;
+    test.setMapField({{-10, {"minus ten"}}, {42, {"fourty two"}}, {15, {"fifteen"}}});
+    QByteArray result = test.serialize(serializer.get());
+
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"-10\":\"minus ten\",\"15\":\"fifteen\",\"42\":\"fourty two\"}}");
+}
+
+TEST_F(JsonSerializationTest, SimpleSInt32StringMapSerializeTest)
+{
+    SimpleSInt32StringMapMessage test;
+    test.setMapField({{10, {"ten"}}, {-42, {"minus fourty two"}}, {15, {"fifteen"}}});
+    QByteArray result = test.serialize(serializer.get());
+
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"-42\":\"minus fourty two\",\"10\":\"ten\",\"15\":\"fifteen\"}}");
+}
+
+TEST_F(JsonSerializationTest, SimpleUInt32StringMapSerializeTest)
+{
+    SimpleUInt32StringMapMessage test;
+    test.setMapField({{10, {"ten"}}, {42, {"fourty two"}}, {15, {"fifteen"}}});
+    QByteArray result = test.serialize(serializer.get());
+
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"10\":\"ten\",\"15\":\"fifteen\",\"42\":\"fourty two\"}}");
+}
+
+TEST_F(JsonSerializationTest, SimpleFixed64StringMapSerializeTest)
+{
+    SimpleFixed64StringMapMessage test;
+    test.setMapField({{10, {"ten"}}, {42, {"fourty two"}}, {15, {"fifteen"}}});
+    QByteArray result = test.serialize(serializer.get());
+
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"10\":\"ten\",\"15\":\"fifteen\",\"42\":\"fourty two\"}}");
+}
+
+TEST_F(JsonSerializationTest, SimpleSFixed64StringMapSerializeTest)
+{
+    SimpleSFixed64StringMapMessage test;
+    test.setMapField({{10, {"ten"}}, {-42, {"minus fourty two"}}, {15, {"fifteen"}}});
+    QByteArray result = test.serialize(serializer.get());
+
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"-42\":\"minus fourty two\",\"10\":\"ten\",\"15\":\"fifteen\"}}");
+}
+
+TEST_F(JsonSerializationTest, SimpleInt64StringMapSerializeTest)
+{
+    SimpleInt64StringMapMessage test;
+    test.setMapField({{-10, {"minus ten"}}, {42, {"fourty two"}}, {15, {"fifteen"}}});
+    QByteArray result = test.serialize(serializer.get());
+
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"-10\":\"minus ten\",\"15\":\"fifteen\",\"42\":\"fourty two\"}}");
+}
+
+TEST_F(JsonSerializationTest, SimpleSInt64StringMapSerializeTest)
+{
+    SimpleSInt64StringMapMessage test;
+    test.setMapField({{10, {"ten"}}, {-42, {"minus fourty two"}}, {15, {"fifteen"}}});
+    QByteArray result = test.serialize(serializer.get());
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"-42\":\"minus fourty two\",\"10\":\"ten\",\"15\":\"fifteen\"}}");
+}
+
+TEST_F(JsonSerializationTest, SimpleUInt64StringMapSerializeTest)
+{
+    SimpleUInt64StringMapMessage test;
+    test.setMapField({{10, {"ten"}}, {42, {"fourty two"}}, {15, {"fifteen"}}});
+    QByteArray result = test.serialize(serializer.get());
+
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"10\":\"ten\",\"15\":\"fifteen\",\"42\":\"fourty two\"}}");
+}
+
+TEST_F(JsonSerializationTest, SimpleStringStringMapSerializeTest)
+{
+    SimpleStringStringMapMessage test;
+    test.setMapField({{"ben", "ten"}, {"what is the answer?", "fourty two"}, {"sweet", "fifteen"}});
+    QByteArray result = test.serialize(serializer.get());
+
+    ASSERT_STREQ(result.toStdString().c_str(),
+                 "{\"mapField\":{\"ben\":\"ten\",\"sweet\":\"fifteen\",\"what is the answer?\":\"fourty two\"}}");
+}
+
 }
 }