Browse Source

Add possibility to switch serializer for basic types

- Add setupSerializer interface for QProtobufSerializerRegistry to reassign
  serialization set
- Add empty JSON serializer
- Change interface serializeProperty inteface, restore QMetaProperty
- Update tests
Alexey Edelev 5 years ago
parent
commit
17028450bf

+ 4 - 3
README.md

@@ -11,7 +11,7 @@ Check installation of protobuf and grpc in your system. Minimum required version
 #### All-in-one build
 If required versions of libraries are not found in your system, you may use all-in-one build procedure for prerequesties
 
-Clone grpc project from official repository to 3rdparty folder:
+Update submodules to fetch 3rdparty dependencies:
 
 ```bash
 git submodule update --init --recursive
@@ -38,7 +38,7 @@ Download and install:
 
 **Note:** All applications should be in PATH
 
-Enter to 3rdparty folder and run command:
+Update submodules to fetch 3rdparty dependencies:
 
 ```bash
 git submodule update --init --recursive
@@ -48,13 +48,14 @@ git submodule update --init --recursive
 Open Qt MSVC command line and follow steps:
 
 ```bash
-"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64
+"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86
 cd <directory with qtprotobuf project>
 mkdir build
 cd build
 cmake ..
 cmake --build . [--config <RELEASE|DEBUG>] -- /m:<N>
 ```
+**Note:** 64-bit build is not supported yet
 
 ## Usage
 ```bash

+ 2 - 0
src/grpc/qgrpchttp2channel.cpp

@@ -40,6 +40,7 @@
 #include <unordered_map>
 
 #include "qtprotobuflogging.h"
+#include "qprotobufserializerregistry.h"
 
 using namespace QtProtobuf;
 
@@ -189,6 +190,7 @@ struct QGrpcHttp2ChannelPrivate {
 QGrpcHttp2Channel::QGrpcHttp2Channel(const QUrl &url, const AbstractCredentials &credentials) : QAbstractGrpcChannel()
   , d(std::make_unique<QGrpcHttp2ChannelPrivate>(url, credentials))
 {
+    QProtobufSerializerRegistry::setupSerializer<QProtobufSerializer>();
 }
 
 QGrpcHttp2Channel::~QGrpcHttp2Channel()

+ 2 - 0
src/protobuf/CMakeLists.txt

@@ -19,6 +19,7 @@ file(GLOB SOURCES
     qtprotobuflogging.cpp
     qprotobufserializerregistry.cpp
     qabstractprotobufserializer.cpp
+    qprotobufjsonserializer.cpp
     qprotobufserializer.cpp)
 
 file(GLOB HEADERS
@@ -29,6 +30,7 @@ file(GLOB HEADERS
     qprotobufserializerregistry.h
     qqmllistpropertyconstructor.h
     qabstractprotobufserializer.h
+    qprotobufjsonserializer.h
     qprotobufselfcheckiterator.h
     qprotobufregistrationhelper.h)
 

+ 1 - 1
src/protobuf/qabstractprotobufserializer.cpp

@@ -41,7 +41,7 @@ QByteArray QAbstractProtobufSerializer::serializeObjectCommon(const QObject *obj
         QMetaProperty metaProperty = metaObject.property(propertyIndex);
         const char *propertyName = metaProperty.name();
         const QVariant &propertyValue = object->property(propertyName);
-        result.append(serializeProperty(propertyValue, fieldIndex, metaProperty.isEnumType()));
+        result.append(serializeProperty(propertyValue, fieldIndex, metaProperty));
     }
 
     return result;

+ 3 - 3
src/protobuf/qabstractprotobufserializer.h

@@ -81,10 +81,10 @@ public:
      * \brief serializeProperty Method called on property serialization cycle.
      * \param[in] propertyValue Value of property and metainformation stored in QVariant
      * \param[in] fieldIndex index of property in message
-     * \param[in] isEnum Flag that indicates property of enum type
+     * \param[in] metaProperty meta information about property to be serialized
      * \return Raw serialized data represented as byte array
      */
-    virtual QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, bool isEnum) = 0;
+    virtual QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) = 0;
 
     /*!
      * \brief deserializeProperty Method called on property deserialization cycle
@@ -201,7 +201,7 @@ public:
     QProtobufSerializer();
     ~QProtobufSerializer() = default;
 
-    QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, bool isEnum) override;
+    QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) override;
     void deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) override;
 
     QByteArray serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) override;

+ 92 - 0
src/protobuf/qprotobufjsonserializer.cpp

@@ -0,0 +1,92 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ *
+ * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "qprotobufjsonserializer.h"
+
+using namespace QtProtobuf;
+
+QByteArray QProtobufJsonSerializer::serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty)
+{
+    Q_UNUSED(propertyValue)
+    Q_UNUSED(fieldIndex)
+    Q_UNUSED(metaProperty)
+    return QByteArray();
+}
+
+void QProtobufJsonSerializer::deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+{
+    Q_UNUSED(object)
+    Q_UNUSED(it)
+    Q_UNUSED(propertyOrdering)
+    Q_UNUSED(metaObject)
+}
+
+QByteArray QProtobufJsonSerializer::serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+{
+    Q_UNUSED(object)
+    Q_UNUSED(propertyOrdering)
+    Q_UNUSED(metaObject)
+    return QByteArray();
+}
+
+void QProtobufJsonSerializer::deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+{
+    Q_UNUSED(object)
+    Q_UNUSED(it)
+    Q_UNUSED(propertyOrdering)
+    Q_UNUSED(metaObject)
+}
+
+QByteArray QProtobufJsonSerializer::serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex)
+{
+    Q_UNUSED(object)
+    Q_UNUSED(propertyOrdering)
+    Q_UNUSED(metaObject)
+    Q_UNUSED(fieldIndex)
+    return QByteArray();
+}
+
+void QProtobufJsonSerializer::deserializeListObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+{
+    Q_UNUSED(object)
+    Q_UNUSED(it)
+    Q_UNUSED(propertyOrdering)
+    Q_UNUSED(metaObject)
+}
+
+QByteArray QProtobufJsonSerializer::serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex)
+{
+    Q_UNUSED(key)
+    Q_UNUSED(value)
+    Q_UNUSED(fieldIndex)
+    return QByteArray();
+}
+
+void QProtobufJsonSerializer::deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it)
+{
+    Q_UNUSED(key)
+    Q_UNUSED(value)
+    Q_UNUSED(it)
+}

+ 49 - 0
src/protobuf/qprotobufjsonserializer.h

@@ -0,0 +1,49 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ *
+ * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "qabstractprotobufserializer.h"
+#include "qtprotobufglobal.h"
+
+namespace QtProtobuf {
+/*!
+*  \ingroup QtProtobuf
+ * \brief The QProtobufJsonSerializer class
+ */
+class Q_PROTOBUF_EXPORT QProtobufJsonSerializer : public QAbstractProtobufSerializer
+{
+    QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) override;
+    void deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) override;
+
+    QByteArray serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) override;
+    void deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) override;
+
+    QByteArray serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex) override;
+    void deserializeListObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) override;
+
+    QByteArray serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) override;
+    void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) override;
+};
+
+}

+ 3 - 3
src/protobuf/qprotobufserializer.cpp

@@ -66,7 +66,7 @@ QProtobufSerializer::QProtobufSerializer()
 
 }
 
-QByteArray QProtobufSerializer::serializeProperty(const QVariant &propertyValue, int fieldIndex, bool isEnum)
+QByteArray QProtobufSerializer::serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty)
 {
     qProtoDebug() << __func__ << "propertyValue" << propertyValue << "fieldIndex" << fieldIndex
                   << static_cast<QMetaType::Type>(propertyValue.type());
@@ -75,7 +75,7 @@ QByteArray QProtobufSerializer::serializeProperty(const QVariant &propertyValue,
     WireTypes type = UnknownWireType;
 
     int userType = propertyValue.userType();
-    if (isEnum) {
+    if (metaProperty.isEnumType()) {
         userType = qMetaTypeId<int64>();
     }
 
@@ -154,7 +154,7 @@ void QProtobufSerializer::deserializeListObject(QObject *object, QProtobufSelfch
 QByteArray QProtobufSerializer::serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex)
 {
     QByteArray result = QProtobufSerializerPrivate::encodeHeader(fieldIndex, LengthDelimited);
-    result.append(QProtobufSerializerPrivate::prependLengthDelimitedSize(serializeProperty(key, 1, false) + serializeProperty(value, 2, false)));
+    result.append(QProtobufSerializerPrivate::prependLengthDelimitedSize(serializeProperty(key, 1, QMetaProperty()) + serializeProperty(value, 2, QMetaProperty())));
     return result;
 }
 

+ 1 - 1
src/protobuf/qprotobufserializerregistry.cpp

@@ -28,7 +28,7 @@
 using namespace QtProtobuf;
 
 QAbstractProtobufSerializer::SerializerRegistry QProtobufSerializerRegistry::handlers = {};
-std::unique_ptr<QAbstractProtobufSerializer> QProtobufSerializerRegistry::basicSerializer = std::make_unique<QProtobufSerializer>();
+std::unique_ptr<QAbstractProtobufSerializer> QProtobufSerializerRegistry::basicSerializer;
 QAbstractProtobufSerializer::SerializationHandlers QProtobufSerializerRegistry::empty;
 
 const QAbstractProtobufSerializer::SerializationHandlers &QProtobufSerializerRegistry::handler(int userType)

+ 22 - 1
src/protobuf/qprotobufserializerregistry.h

@@ -70,6 +70,18 @@ class Q_PROTOBUF_EXPORT QProtobufSerializerRegistry
     static std::unique_ptr<QAbstractProtobufSerializer> basicSerializer;
     static QAbstractProtobufSerializer::SerializationHandlers empty;
 public:
+
+    /*!
+     * \brief QProtobufSerializerRegistry holds application-wide serializers set. Basic types are serialized by
+     *        QAbstractProtobufSerializer, that should be setup using this function. In most cases serializer is
+     *        selected according to channel preferences.
+     */
+    template<typename T,
+             std::enable_if_t<std::is_base_of<QAbstractProtobufSerializer, T>::value, int> = 0>
+    static void setupSerializer() {
+        basicSerializer.reset(new T);
+    }
+
     static const QAbstractProtobufSerializer::SerializationHandlers &handler(int userType);
     /*!
      * \brief Serialization of a registered qtproto message object into byte-array
@@ -80,6 +92,7 @@ public:
      */
     template<typename T>
     static QByteArray serialize(const QObject *object) {
+        Q_ASSERT_X(basicSerializer, "QProtobufSerializerRegistry", "Serializers set is not setup");
         qProtoDebug() << T::staticMetaObject.className() << "serialize";
         return basicSerializer->serializeObjectCommon(object, T::propertyOrdering, T::staticMetaObject);
     }
@@ -95,11 +108,11 @@ public:
      */
     template<typename T>
     static void deserialize(QObject *object, const QByteArray &array) {
+        Q_ASSERT_X(basicSerializer, "QProtobufSerializerRegistry", "Serializers set is not setup");
         qProtoDebug() << T::staticMetaObject.className() << "deserialize";
         basicSerializer->deserializeObjectCommon(object, array, T::propertyOrdering, T::staticMetaObject);
     }
 
-
     /*!
      * \brief Registers serializers for type T in QProtobufSerializerRegistry
      *
@@ -147,6 +160,7 @@ private:
     template <typename T,
               typename std::enable_if_t<std::is_base_of<QObject, T>::value, int> = 0>
     static QByteArray serializeComplexType(const QVariant &value, int &/*outFieldIndex*/) {
+        Q_ASSERT_X(basicSerializer, "QProtobufSerializerRegistry", "Serializers set is not setup");
         return basicSerializer->serializeObject(value.value<T *>(), T::propertyOrdering, T::staticMetaObject);
     }
 
@@ -158,6 +172,7 @@ private:
     template<typename V,
              typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
     static QByteArray serializeList(const QVariant &listValue, int &outFieldIndex) {
+        Q_ASSERT_X(basicSerializer, "QProtobufSerializerRegistry", "Serializers set is not setup");
         QList<QSharedPointer<V>> list = listValue.value<QList<QSharedPointer<V>>>();
 
         qProtoDebug() << __func__ << "listValue.count" << list.count() << "outFiledIndex" << outFieldIndex;
@@ -189,6 +204,7 @@ private:
     template<typename K, typename V,
              typename std::enable_if_t<!std::is_base_of<QObject, V>::value, int> = 0>
     static QByteArray serializeMap(const QVariant &value, int &outFieldIndex) {
+        Q_ASSERT_X(basicSerializer, "QProtobufSerializerRegistry", "Serializers set is not setup");
         QMap<K,V> mapValue = value.value<QMap<K,V>>();
         using ItType = typename QMap<K,V>::const_iterator;
         QByteArray mapResult;
@@ -209,6 +225,7 @@ private:
     template<typename K, typename V,
              typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
     static QByteArray serializeMap(const QVariant &value, int &outFieldIndex) {
+        Q_ASSERT_X(basicSerializer, "QProtobufSerializerRegistry", "Serializers set is not setup");
         QMap<K, QSharedPointer<V>> mapValue = value.value<QMap<K, QSharedPointer<V>>>();
         using ItType = typename QMap<K, QSharedPointer<V>>::const_iterator;
         QByteArray mapResult;
@@ -232,6 +249,7 @@ private:
     template <typename T,
               typename std::enable_if_t<std::is_base_of<QObject, T>::value, int> = 0>
     static void deserializeComplexType(QProtobufSelfcheckIterator &it, QVariant &to) {
+        Q_ASSERT_X(basicSerializer, "QProtobufSerializerRegistry", "Serializers set is not setup");
         T *value = new T;
         basicSerializer->deserializeObject(value, it, T::propertyOrdering, T::staticMetaObject);
         to = QVariant::fromValue<T *>(value);
@@ -245,6 +263,7 @@ private:
     template <typename V,
               typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
     static void deserializeList(QProtobufSelfcheckIterator &it, QVariant &previous) {
+        Q_ASSERT_X(basicSerializer, "QProtobufSerializerRegistry", "Serializers set is not setup");
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
 
         V *newValue = new V;
@@ -262,6 +281,7 @@ private:
     template <typename K, typename V,
               typename std::enable_if_t<!std::is_base_of<QObject, V>::value, int> = 0>
     static void deserializeMap(QProtobufSelfcheckIterator &it, QVariant &previous) {
+        Q_ASSERT_X(basicSerializer, "QProtobufSerializerRegistry", "Serializers set is not setup");
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
 
         QMap<K, V> out = previous.value<QMap<K, V>>();
@@ -282,6 +302,7 @@ private:
     template <typename K, typename V,
               typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
     static void deserializeMap(QProtobufSelfcheckIterator &it, QVariant &previous) {
+        Q_ASSERT_X(basicSerializer, "QProtobufSerializerRegistry", "Serializers set is not setup");
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
 
         auto out = previous.value<QMap<K, QSharedPointer<V>>>();

+ 1 - 0
tests/test_grpc/clienttest.cpp

@@ -57,6 +57,7 @@ QUrl ClientTest::m_echoServerAddress("http://localhost:50051", QUrl::StrictMode)
 TEST_F(ClientTest, CheckMethodsGeneration)
 {
     //Dummy compile time check of functions generation and interface compatibility
+    QProtobufSerializerRegistry::setupSerializer<QProtobufSerializer>();
     TestServiceClient testClient;
     SimpleStringMessage request;
     QPointer<SimpleStringMessage> result(new SimpleStringMessage);

+ 7 - 0
tests/test_protobuf/deserializationtest.cpp

@@ -86,10 +86,17 @@
 #include "fieldindextest3message.h"
 #include "fieldindextest4message.h"
 
+#include "qabstractprotobufserializer.h"
+
 using namespace qtprotobufnamespace::tests;
 using namespace QtProtobuf::tests;
 using namespace QtProtobuf;
 
+void DeserializationTest::SetUp()
+{
+    QProtobufSerializerRegistry::setupSerializer<QProtobufSerializer>();
+}
+
 TEST_F(DeserializationTest, FixedInt32MessageDeserializeTest)
 {
     SimpleFixedInt32Message test;

+ 1 - 0
tests/test_protobuf/deserializationtest.h

@@ -34,6 +34,7 @@ class DeserializationTest : public ::testing::Test
 {
 public:
     DeserializationTest() = default;
+    void SetUp() override;
 };
 
 }

+ 2 - 1
tests/test_protobuf/serializationtest.cpp

@@ -80,8 +80,9 @@ using namespace qtprotobufnamespace::tests;
 using namespace QtProtobuf::tests;
 using namespace QtProtobuf;
 
-SerializationTest::SerializationTest()
+void SerializationTest::SetUp()
 {
+    QProtobufSerializerRegistry::setupSerializer<QProtobufSerializer>();
 }
 
 TEST_F(SerializationTest, IntMessageSerializeTest)

+ 2 - 1
tests/test_protobuf/serializationtest.h

@@ -33,7 +33,8 @@ namespace tests {
 class SerializationTest : public ::testing::Test
 {
 public:
-    SerializationTest();
+    SerializationTest() = default;
+    void SetUp() override;
 };
 
 }