Browse Source

Complete serializers intreface refactoring

- Move QProtobufSerializer to separate header
- Remove handlers registry from abstract serializer
- Make possible to select serializer ondemand
- Refactor interfaces
- Update tests
Alexey Edelev 5 years ago
parent
commit
1c8b61a2ac

+ 2 - 2
src/generator/templates.cpp

@@ -177,7 +177,7 @@ const char *Templates::RegisterQmlListPropertyMetaTypeTemplate = "qRegisterMetaT
 
 const char *Templates::QEnumTemplate = "Q_ENUM($type$)\n";
 
-const char *Templates::MapSerializationRegisterTemplate = "QtProtobuf::QProtobufSerializerRegistry::registerMap<$key_type$, $value_type$>();\n";
+const char *Templates::MapSerializationRegisterTemplate = "qRegisterProtobufMapType<$key_type$, $value_type$>();\n";
 
 const char *Templates::ClassDefinitionTemplate = "\nclass $classname$ : public $parent_class$\n"
                                                  "{\n";
@@ -207,7 +207,7 @@ const char *Templates::ClientMethodDefinitionAsync2Template = "\nvoid $classname
                                                               "    });\n"
                                                               "}\n";
 
-const char *Templates::RegisterSerializersTemplate = "QtProtobuf::QProtobufSerializerRegistry::registerSerializers<$classname$>();\n";
+const char *Templates::RegisterSerializersTemplate = "qRegisterProtobufType<$classname$>();\n";
 const char *Templates::RegistratorTemplate = "static QtProtobuf::QProtobufRegistrationHelper helper(registerTypes);\n";
 const char *Templates::QmlRegisterTypeTemplate = "qmlRegisterType<$namespaces$::$classname$>(\"$package$\", 1, 0, \"$classname$\");\n";
 const char *Templates::QmlRegisterTypeUncreatableTemplate = "qmlRegisterUncreatableType<$namespaces$::$classname$>(\"$package$\", 1, 0, \"$classname$\", \"$namespaces$::$classname$ Could not be created from qml context\");\n";

+ 16 - 1
src/grpc/qabstractgrpcclient.cpp

@@ -25,15 +25,22 @@
 
 #include "qabstractgrpcclient.h"
 
+#include "qprotobufserializer.h"
+#include "qgrpcasyncreply.h"
+
 #include <QTimer>
 
 namespace QtProtobuf {
 class QAbstractGrpcClientPrivate final {
 public:
-    QAbstractGrpcClientPrivate(const QString &service) : service(service) {}
+    QAbstractGrpcClientPrivate(const QString &service) : service(service) {
+        //TODO: probably this variable should be initialized by default serializer from registry
+        serializer.reset(new QProtobufSerializer);
+    }
 
     std::shared_ptr<QAbstractGrpcChannel> channel;
     const QString service;
+    std::unique_ptr<QAbstractProtobufSerializer> serializer;
 };
 }
 
@@ -50,6 +57,8 @@ QAbstractGrpcClient::~QAbstractGrpcClient()
 void QAbstractGrpcClient::attachChannel(const std::shared_ptr<QAbstractGrpcChannel> &channel)
 {
     d->channel = channel;
+    //TODO: construct serializer based on information recevied from channel
+    d->serializer.reset(new QProtobufSerializer);
 }
 
 QGrpcStatus QAbstractGrpcClient::call(const QString &method, const QByteArray &arg, QByteArray &ret)
@@ -99,3 +108,9 @@ void QAbstractGrpcClient::subscribe(const QString &method, const QByteArray &arg
         error({QGrpcStatus::Unknown, QLatin1String("No channel(s) attached.")});
     }
 }
+
+QAbstractProtobufSerializer *QAbstractGrpcClient::serializer() const
+{
+    return d->serializer.get();
+}
+

+ 11 - 6
src/grpc/qabstractgrpcclient.h

@@ -33,13 +33,15 @@
 #include <QByteArray>
 
 #include <qtprotobuflogging.h>
+#include <qabstractprotobufserializer.h>
 
 #include "qabstractgrpcchannel.h"
-#include "qgrpcasyncreply.h"
 
 #include "qtgrpcglobal.h"
 
 namespace QtProtobuf {
+
+class QGrpcAsyncReply;
 class QAbstractGrpcChannel;
 class QAbstractGrpcClientPrivate;
 /*!
@@ -90,7 +92,7 @@ protected:
         }
 
         QByteArray retData;
-        status = call(method, arg.serialize(), retData);
+        status = call(method, arg.serialize(serializer()), retData);
         if (status == QGrpcStatus::StatusCode::Ok) {
             return tryDeserialize(*ret, retData);
         }
@@ -105,7 +107,7 @@ protected:
      */
     template<typename A>
     QGrpcAsyncReply *call(const QString &method, const A &arg) {
-        return call(method, arg.serialize());
+        return call(method, arg.serialize(serializer()));
     }
 
     /*!
@@ -119,7 +121,7 @@ protected:
     template<typename A, typename R, typename C,
              typename std::enable_if_t<std::is_base_of<QAbstractGrpcClient, C>::value, int> = 0>
     void subscribe(const QString &method, const A &arg, void(C::*signal)(const R &)) {
-        subscribe(method, arg.serialize(), [this, signal](const QByteArray &data) {
+        subscribe(method, arg.serialize(serializer()), [this, signal](const QByteArray &data) {
             R ret;
             tryDeserialize(ret, data);
             C *client = static_cast<C *>(this);
@@ -146,7 +148,7 @@ protected:
             return;
         }
 
-        subscribe(method, arg.serialize(), [ret, this](const QByteArray &data) {
+        subscribe(method, arg.serialize(serializer()), [ret, this](const QByteArray &data) {
             if (!ret.isNull()) {
                 tryDeserialize(*ret, data);
             } else {
@@ -157,6 +159,9 @@ protected:
         });
     }
 
+    QAbstractProtobufSerializer *serializer() const;
+
+    friend class QGrpcAsyncReply;
 private:
     /*!
      * \private
@@ -181,7 +186,7 @@ private:
     QGrpcStatus tryDeserialize(R &ret, const QByteArray &retData) {
         QGrpcStatus status{QGrpcStatus::Ok};
         try {
-            ret.deserialize(retData);
+            ret.deserialize(serializer(), retData);
         } catch (std::invalid_argument &) {
             static const QLatin1String invalidArgumentErrorMessage("Response deserialization failed invalid field found");
             status = {QGrpcStatus::InvalidArgument, invalidArgumentErrorMessage};

+ 3 - 2
src/grpc/qgrpcasyncreply.h

@@ -31,6 +31,7 @@
 #include <memory>
 
 #include "qabstractgrpcchannel.h"
+#include "qabstractgrpcclient.h"
 
 #include "qtgrpcglobal.h"
 
@@ -55,7 +56,7 @@ public:
         QMutexLocker locker(&m_asyncLock);
         T value;
         try {
-            value.deserialize(m_data);
+            value.deserialize(static_cast<QAbstractGrpcClient*>(parent())->serializer(), m_data);
         } catch (std::invalid_argument &) {
             static const QLatin1String invalidArgumentErrorMessage("Response deserialization failed invalid field found");
             error({QGrpcStatus::InvalidArgument, invalidArgumentErrorMessage});
@@ -102,7 +103,7 @@ signals:
 
 protected:
     //! \private
-    QGrpcAsyncReply(const std::shared_ptr<QAbstractGrpcChannel> &channel, QObject *parent = nullptr) : QObject(parent)
+    QGrpcAsyncReply(const std::shared_ptr<QAbstractGrpcChannel> &channel, QAbstractGrpcClient *parent = nullptr) : QObject(parent)
     , m_channel(channel) {}
     //! \private
     ~QGrpcAsyncReply();

+ 1 - 2
src/grpc/qgrpchttp2channel.cpp

@@ -40,7 +40,7 @@
 #include <unordered_map>
 
 #include "qtprotobuflogging.h"
-#include "qprotobufserializerregistry.h"
+#include <qprotobufserializer.h>
 
 using namespace QtProtobuf;
 
@@ -190,7 +190,6 @@ 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

@@ -30,6 +30,8 @@ file(GLOB HEADERS
     qprotobufserializerregistry.h
     qqmllistpropertyconstructor.h
     qabstractprotobufserializer.h
+    qabstractprotobufserializer_p.h
+    qprotobufserializer.h
     qprotobufjsonserializer.h
     qprotobufselfcheckiterator.h
     qprotobufregistrationhelper.h)

+ 25 - 2
src/protobuf/qabstractprotobufserializer.cpp

@@ -31,7 +31,30 @@
 
 using namespace QtProtobuf;
 
-QByteArray QAbstractProtobufSerializer::serializeObjectCommon(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+namespace  {
+/*
+ * SerializerRegistry is container to store mapping between metatype identifier and serialization handlers.
+ */
+using SerializerRegistry = std::unordered_map<int/*metatypeid*/, QtProtobufPrivate::SerializationHandler>;
+static SerializerRegistry registry;
+static QtProtobufPrivate::SerializationHandler empty;
+}
+
+void QtProtobufPrivate::registerHandler(int userType, const QtProtobufPrivate::SerializationHandler &handlers)
+{
+    registry[userType] = handlers;
+}
+
+QtProtobufPrivate::SerializationHandler &QtProtobufPrivate::findHandler(int userType)
+{
+    auto it = registry.find(userType);
+    if (it != registry.end()) {
+        return it->second;
+    }
+    return empty;
+}
+
+QByteArray QAbstractProtobufSerializer::serializeObjectCommon(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     QByteArray result;
     for (const auto &field : propertyOrdering) {
@@ -47,7 +70,7 @@ QByteArray QAbstractProtobufSerializer::serializeObjectCommon(const QObject *obj
     return result;
 }
 
-void QAbstractProtobufSerializer::deserializeObjectCommon(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+void QAbstractProtobufSerializer::deserializeObjectCommon(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     for (QProtobufSelfcheckIterator it(data); it != data.end();) {
         deserializeProperty(object, it, propertyOrdering, metaObject);

+ 106 - 59
src/protobuf/qabstractprotobufserializer.h

@@ -31,6 +31,7 @@
 
 #include <unordered_map>
 #include <functional>
+#include <memory>
 
 #include "qtprotobuftypes.h"
 #include "qtprotobuflogging.h"
@@ -47,35 +48,76 @@ namespace QtProtobuf {
 /*!
  * \brief The QAbstractProtobufSerializer class is interface that represents basic functions for serialization/deserialization
  *
- * \details This class is used by QProtobufSerializerRegistry to access basic serialization routines.
+ * \details The QAbstractProtobufSerializer class registers serializers/deserializers for classes inherited of QObject.
+ *          To register serializers for user-defined class it has to be inherited of QObject and contains
+ *          Q_DECLARE_PROTOBUF_SERIALIZERS macro's.
+ *          \code{.cpp}
+ *          class MyType : public QObject
+ *          {
+ *              Q_OBJECT
+ *              Q_PROTOBUF_OBJECT
+ *              Q_PROPERTY(qprotobuf::sint32 prop READ prop WRITE setProp NOTIFY propChanged)
+ *              ...
+ *              Q_DECLARE_PROTOBUF_SERIALIZERS(MyType)
+ *          };
+ *          \endcode
+ *          Practically code above is generated automaticaly by running qtprotobufgenerator or using cmake build macro
+ *          generate_qtprotobuf, based on .proto files. But it's still possible to reuse manually written code if needed.
  *
+ *          This class should be used as base for specific serializers. The handlers property contains all
+ *          message-specific serializers and should be used while serialization/deserialization. Inherited classes should reimplement
+ *          scope of virtual methods that used by registred message serialization/deserialization functions.
  */
 class Q_PROTOBUF_EXPORT QAbstractProtobufSerializer
 {
 public:
     /*!
-     * \brief Serializer is interface function for serialize method
+     * \brief Serialization of a registered qtproto message object into byte-array
+     *
+     *
+     * \param[in] object Pointer to QObject containing message to be serialized
+     * \result serialized message bytes
      */
-    using Serializer = std::function<QByteArray(const QVariant &, int &)>;
+    template<typename T>
+    QByteArray serialize(const QObject *object) {
+        qProtoDebug() << T::staticMetaObject.className() << "serialize";
+        return serializeMessage(object, T::propertyOrdering, T::staticMetaObject);
+    }
+
     /*!
-     * \brief Deserializer is interface function for deserialize method
+     * \brief Deserialization of a byte-array into a registered qtproto message object
+     *
+     * \details Properties in a message are identified via ProtobufObjectPrivate::decodeHeader.
+     *          Bytes corresponding to unexpected properties are skipped without any exception
+     *
+     * \param[out] object Pointer to memory where result of deserialization should be injected
+     * \param[in] array Bytes with serialized message
      */
-    using Deserializer = std::function<void(QProtobufSelfcheckIterator &, QVariant &)>;
+    template<typename T>
+    void deserialize(QObject *object, const QByteArray &array) {
+        qProtoDebug() << T::staticMetaObject.className() << "deserialize";
+        deserializeMessage(object, array, T::propertyOrdering, T::staticMetaObject);
+    }
+
+    virtual ~QAbstractProtobufSerializer() = default;
 
     /*!
-     * \brief SerializationHandlers contains set of objects that required for class serializaion/deserialization
+     * \brief serializeMessage
+     * \param object
+     * \param propertyOrdering
+     * \param metaObject
+     * \return
      */
-    struct SerializationHandlers {
-        Serializer serializer; /*!< serializer assigned to class */
-        Deserializer deserializer;/*!< deserializer assigned to class */
-        WireTypes type;/*!< Serialization WireType */
-    };
+    virtual QByteArray serializeMessage(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const = 0;
+
     /*!
-     * \brief SerializerRegistry is container to store mapping between metatype identifier and serialization handlers.
+     * \brief serializeMessage
+     * \param object
+     * \param propertyOrdering
+     * \param metaObject
+     * \return
      */
-    using SerializerRegistry = std::unordered_map<int/*metatypeid*/, SerializationHandlers>;
-
-    virtual ~QAbstractProtobufSerializer() = default;
+    virtual void deserializeMessage(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const = 0;
 
     /*!
      * \brief serializeProperty Method called on property serialization cycle.
@@ -84,7 +126,7 @@ public:
      * \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, const QMetaProperty &metaProperty) = 0;
+    virtual QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const = 0;
 
     /*!
      * \brief deserializeProperty Method called on property deserialization cycle
@@ -94,7 +136,7 @@ public:
      * \param[in] metaObject Static meta object of given \a object. Static meta object usualy is used to get actual
      *            property value and write new property to \a object
      */
-    virtual void deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) = 0;
+    virtual void deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const = 0;
 
     /*!
      * \brief serializeObject Serializes complete \a object according given \a propertyOrdering and \a metaObject
@@ -104,7 +146,7 @@ public:
      * \param[in] metaObject Meta object information for given \a object
      * \return Raw serialized data represented as byte array
      */
-    virtual QByteArray serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) = 0;
+    virtual QByteArray serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const = 0;
 
     /*!
      * \brief deserializeObject Deserializes buffer to an \a object
@@ -114,7 +156,7 @@ public:
      * \param[in] metaObject Static meta object of given \a object. Static meta object usualy is used to get actual
      *        property value and write new property to \a object
      */
-    virtual void deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) = 0;
+    virtual void deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const = 0;
 
     /*!
      * \brief serializeListObject Method called to serialize \a object as a part of list property
@@ -124,7 +166,7 @@ public:
      * \param[in] fieldIndex Index of list property in target message
      * \return Raw serialized data represented as byte array
      */
-    virtual QByteArray serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex) = 0;
+    virtual QByteArray serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex) const = 0;
 
     /*!
      * \brief deserializeListObject Deserializes an \a object from byte stream as part of list property
@@ -134,7 +176,7 @@ public:
      * \param[in] metaObject Static meta object of given \a object. Static meta object usualy is used to get actual
      *        property value and write new property to \a object
      */
-    virtual void deserializeListObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) = 0;
+    virtual void deserializeListObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const = 0;
 
     /*!
      * \brief serializeMapPair Serializes QMap pair of \a key and \a value to raw data buffer
@@ -145,7 +187,7 @@ public:
      *
      * \see https://developers.google.com/protocol-buffers/docs/proto3#maps for details
      */
-    virtual QByteArray serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) = 0;
+    virtual QByteArray serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) const = 0;
 
     /*!
      * \brief deserializeMapPair Deserializes QMap pair of \a key and \a value from raw data
@@ -157,64 +199,69 @@ public:
      *
      * \see https://developers.google.com/protocol-buffers/docs/proto3#maps for details
      */
-    virtual void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) = 0;
+    virtual void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const = 0;
 
+protected:
     /*!
      * \brief serializeObjectCommon Common routine to iterate object properties. Could be used in serializer
-     *        implementations. But in practice is private interface for QProtobufSerializerRegistry
+     *        implementations. But in practice is private interface for QAbstractProtobufSerializer
      * \param[in] object Pointer to object to be serialized
      * \param[in] propertyOrdering Ordering of properties for given \a object
      * \param[in] metaObject Static meta object of given \a object.
      * \return Raw serialized data represented as byte array
      */
-    QByteArray serializeObjectCommon(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject);
+    QByteArray serializeObjectCommon(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const;
 
     /*!
      * \brief deserializeObjectCommon Common routine to iterate object properties. Could be used in serializer
-     *        implementations. But in practice is private interface for QProtobufSerializerRegistry
+     *        implementations. But in practice is private interface for QAbstractProtobufSerializer
      * \param[out] object Pointer to allocated object
      * \param[in] array Complete message buffer received from transport stream
      * \param[in] propertyOrdering Ordering of properties for given \a object
      * \param[in] metaObject Static meta object of given \a object. Static meta object usualy is used to get actual
      *        property value and write new property to \a object
      */
-    void deserializeObjectCommon(QObject *object, const QByteArray &array, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject);
-
-    /*!
-     * \brief handlers Method to access serializers set provided by serializer
-     * \return Serializers set provided by serializer
-     *
-     * \note In practice this method is interface for QProtobufSerializerRegistry
-     */
-    const SerializerRegistry& handlers() { return m_handlers; }
-
-protected:
-    SerializerRegistry m_handlers;//TODO: move to d-prointer
+    void deserializeObjectCommon(QObject *object, const QByteArray &array, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const;
 };
+/*! \} */
+}
+
+#include "qabstractprotobufserializer_p.h"
 
 /*!
- * \brief The QProtobufSerializer class
+ * \brief Registers serializers for type T in QtProtobuf global serializers registry
+ *
+ * \details generates default serializers for type T. Type T has to be inherited of QObject.
  */
-class Q_PROTOBUF_EXPORT QProtobufSerializer : public QAbstractProtobufSerializer
-{
-public:
-    QProtobufSerializer();
-    ~QProtobufSerializer() = default;
-
-    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;
+template<typename T>
+static void qRegisterProtobufType() {
+    QtProtobufPrivate::registerHandler(qMetaTypeId<T *>(), { QtProtobufPrivate::serializeComplexType<T>,
+            QtProtobufPrivate::deserializeComplexType<T>, QtProtobuf::LengthDelimited });
+    QtProtobufPrivate::registerHandler(qMetaTypeId<QList<QSharedPointer<T>>>(), { QtProtobufPrivate::serializeList<T>,
+            QtProtobufPrivate::deserializeList<T>, QtProtobuf::LengthDelimited });
+}
 
-    QByteArray serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) override;
-    void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) override;
-};
-/*! \} */
+/*!
+ * \brief Registers serializers for type QMap<K, V> in QtProtobuf global serializers registry
+ *
+ * \details generates default serializers for QMap<K, V>.
+ */
+template<typename K, typename V,
+         typename std::enable_if_t<!std::is_base_of<QObject, V>::value, int> = 0>
+inline void qRegisterProtobufMapType() {
+    QtProtobufPrivate::registerHandler(qMetaTypeId<QMap<K, V>>(), { QtProtobufPrivate::serializeMap<K, V>,
+    QtProtobufPrivate::deserializeMap<K, V>, QtProtobuf::LengthDelimited });
+}
 
-//! \private
-constexpr int NotUsedFieldIndex = -1;
+/*!
+ * \brief Registers serializers for type QMap<K, V> in QtProtobuf global serializers registry
+ *
+ * \details generates default serializers for QMap<K, V>. Specialization for V type
+ *          inherited of QObject.
+ */
+template<typename K, typename V,
+         typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
+inline void qRegisterProtobufMapType() {
+    QtProtobufPrivate::registerHandler(qMetaTypeId<QMap<K, QSharedPointer<V>>>(), { QtProtobufPrivate::serializeMap<K, V>,
+    QtProtobufPrivate::deserializeMap<K, V>, QtProtobuf::LengthDelimited });
 }

+ 227 - 0
src/protobuf/qabstractprotobufserializer_p.h

@@ -0,0 +1,227 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <QVariant>
+#include <QMetaObject>
+
+#include <functional>
+
+#include "qtprotobuftypes.h"
+#include "qtprotobuflogging.h"
+#include "qtprotobufglobal.h"
+
+namespace QtProtobuf {
+    class QAbstractProtobufSerializer;
+    class QProtobufSelfcheckIterator;
+}
+
+namespace QtProtobufPrivate {
+//! \private
+constexpr int NotUsedFieldIndex = -1;
+
+using Serializer = std::function<QByteArray(const QtProtobuf::QAbstractProtobufSerializer *, const QVariant &, int &)>;
+/*!
+ * \brief Deserializer is interface function for deserialize method
+ */
+using Deserializer = std::function<void(const QtProtobuf::QAbstractProtobufSerializer *, QtProtobuf::QProtobufSelfcheckIterator &, QVariant &)>;
+
+/*!
+ * \brief SerializationHandlers contains set of objects that required for class serializaion/deserialization
+ */
+struct SerializationHandler {
+    Serializer serializer; /*!< serializer assigned to class */
+    Deserializer deserializer;/*!< deserializer assigned to class */
+    QtProtobuf::WireTypes type;/*!< Serialization WireType */
+};
+
+extern Q_PROTOBUF_EXPORT SerializationHandler &findHandler(int userType);
+extern Q_PROTOBUF_EXPORT void registerHandler(int userType, const SerializationHandler &handlers);
+
+/*!
+ * \private
+ *
+ * \brief default serializer template for type T inherited of QObject
+ */
+template <typename T,
+          typename std::enable_if_t<std::is_base_of<QObject, T>::value, int> = 0>
+QByteArray serializeComplexType(const QtProtobuf::QAbstractProtobufSerializer *serializer, const QVariant &value, int &/*outFieldIndex*/) {
+    Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "serializer set is not setup");
+    return serializer->serializeObject(value.value<T *>(), T::propertyOrdering, T::staticMetaObject);
+}
+
+/*!
+ * \private
+ *
+ * \brief default serializer template for list of type T objects inherited of QObject
+ */
+template<typename V,
+         typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
+QByteArray serializeList(const QtProtobuf::QAbstractProtobufSerializer *serializer, const QVariant &listValue, int &outFieldIndex) {
+    Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "serializer set is not setup");
+    QList<QSharedPointer<V>> list = listValue.value<QList<QSharedPointer<V>>>();
+
+    qProtoDebug() << __func__ << "listValue.count" << list.count() << "outFiledIndex" << outFieldIndex;
+
+    if (list.count() <= 0) {
+        outFieldIndex = NotUsedFieldIndex;
+        return QByteArray();
+    }
+
+    QByteArray serializedList;
+    for (auto &value : list) {
+        if (!value) {
+            qProtoWarning() << "Null pointer in list";
+            continue;
+        }
+        serializedList.append(serializer->serializeListObject(value.data(), V::propertyOrdering, V::staticMetaObject, outFieldIndex));
+    }
+
+    outFieldIndex = NotUsedFieldIndex;
+
+    return serializedList;
+}
+
+/*!
+ * \private
+ *
+ * \brief default serializer template for map of key K, value V
+ */
+template<typename K, typename V,
+         typename std::enable_if_t<!std::is_base_of<QObject, V>::value, int> = 0>
+QByteArray serializeMap(const QtProtobuf::QAbstractProtobufSerializer *serializer, const QVariant &value, int &outFieldIndex) {
+    Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "serializer set is not setup");
+    QMap<K,V> mapValue = value.value<QMap<K,V>>();
+    using ItType = typename QMap<K,V>::const_iterator;
+    QByteArray mapResult;
+
+    for ( ItType it = mapValue.constBegin(); it != mapValue.constEnd(); it++) {
+        mapResult.append(serializer->serializeMapPair(QVariant::fromValue<K>(it.key()), QVariant::fromValue<V>(it.value()), outFieldIndex));
+    }
+    outFieldIndex = NotUsedFieldIndex;
+    return mapResult;
+}
+
+/*!
+ * \private
+ *
+ * \brief default serializer template for map of type key K, value V. Specialization for V
+ *        inherited of QObject
+ */
+template<typename K, typename V,
+         typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
+QByteArray serializeMap(const QtProtobuf::QAbstractProtobufSerializer *serializer, const QVariant &value, int &outFieldIndex) {
+    Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "serializer 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;
+
+    for ( ItType it = mapValue.constBegin(); it != mapValue.constEnd(); it++) {
+        if (it.value().isNull()) {
+            qProtoWarning() << __func__ << "Trying to serialize map value that contains nullptr";
+            continue;
+        }
+        mapResult.append(serializer->serializeMapPair(QVariant::fromValue<K>(it.key()), QVariant::fromValue<V *>(it.value().data()), outFieldIndex));
+    }
+    outFieldIndex = NotUsedFieldIndex;
+    return mapResult;
+}
+
+/*!
+ * \private
+ *
+ * \brief default deserializer template for type T inherited of QObject
+ */
+template <typename T,
+          typename std::enable_if_t<std::is_base_of<QObject, T>::value, int> = 0>
+void deserializeComplexType(const QtProtobuf::QAbstractProtobufSerializer *serializer, QtProtobuf::QProtobufSelfcheckIterator &it, QVariant &to) {
+    Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "serializer set is not setup");
+    T *value = new T;
+    serializer->deserializeObject(value, it, T::propertyOrdering, T::staticMetaObject);
+    to = QVariant::fromValue<T *>(value);
+}
+
+/*!
+ * \private
+ *
+ * \brief default deserializer template for list of type T objects inherited of QObject
+ */
+template <typename V,
+          typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
+void deserializeList(const QtProtobuf::QAbstractProtobufSerializer *serializer, QtProtobuf::QProtobufSelfcheckIterator &it, QVariant &previous) {
+    Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "serializer set is not setup");
+    qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
+
+    V *newValue = new V;
+    QList<QSharedPointer<V>> list = previous.value<QList<QSharedPointer<V>>>();
+    serializer->deserializeListObject(newValue, it, V::propertyOrdering, V::staticMetaObject);
+    list.append(QSharedPointer<V>(newValue));
+    previous.setValue(list);
+}
+
+/*!
+ * \private
+ *
+ * \brief default deserializer template for map of key K, value V
+ */
+template <typename K, typename V,
+          typename std::enable_if_t<!std::is_base_of<QObject, V>::value, int> = 0>
+void deserializeMap(const QtProtobuf::QAbstractProtobufSerializer *serializer, QtProtobuf::QProtobufSelfcheckIterator &it, QVariant &previous) {
+    Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "serializer set is not setup");
+    qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
+
+    QMap<K, V> out = previous.value<QMap<K, V>>();
+    QVariant key = QVariant::fromValue<K>(K());
+    QVariant value = QVariant::fromValue<V>(V());
+
+    serializer->deserializeMapPair(key, value, it);
+    out[key.value<K>()] = value.value<V>();
+    previous = QVariant::fromValue<QMap<K, V>>(out);
+}
+
+/*!
+ * \private
+ *
+ * \brief default deserializer template for map of type key K, value V. Specialization for V
+ *        inherited of QObject
+ */
+template <typename K, typename V,
+          typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
+void deserializeMap(const QtProtobuf::QAbstractProtobufSerializer *serializer, QtProtobuf::QProtobufSelfcheckIterator &it, QVariant &previous) {
+    Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "serializer set is not setup");
+    qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
+
+    auto out = previous.value<QMap<K, QSharedPointer<V>>>();
+    QVariant key = QVariant::fromValue<K>(K());
+    QVariant value = QVariant::fromValue<V *>(nullptr);
+
+    serializer->deserializeMapPair(key, value, it);
+    out[key.value<K>()] = QSharedPointer<V>(value.value<V *>());
+    previous = QVariant::fromValue<QMap<K, QSharedPointer<V>>>(out);
+}
+
+}

+ 39 - 14
src/protobuf/qprotobufjsonserializer.cpp

@@ -24,34 +24,59 @@
  */
 
 #include "qprotobufjsonserializer.h"
+#include <QMetaProperty>
 
 using namespace QtProtobuf;
 
-QByteArray QProtobufJsonSerializer::serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty)
+QProtobufJsonSerializer::QProtobufJsonSerializer()
 {
-    Q_UNUSED(propertyValue)
-    Q_UNUSED(fieldIndex)
-    Q_UNUSED(metaProperty)
-    return QByteArray();
 }
 
-void QProtobufJsonSerializer::deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+QByteArray QProtobufJsonSerializer::serializeMessage(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
+{
+    QByteArray result = "{";
+    result.append(serializeObjectCommon(object, propertyOrdering, metaObject));
+    result.append("}");
+    return result;
+}
+
+void QProtobufJsonSerializer::deserializeMessage(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     Q_UNUSED(object)
-    Q_UNUSED(it)
+    Q_UNUSED(data)
     Q_UNUSED(propertyOrdering)
     Q_UNUSED(metaObject)
 }
 
-QByteArray QProtobufJsonSerializer::serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+QByteArray QProtobufJsonSerializer::serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const
+{
+    Q_UNUSED(fieldIndex)
+    auto &value = QtProtobufPrivate::findHandler(metaProperty.userType());
+    if (value.serializer) {
+        return value.serializer(this, propertyValue, fieldIndex);
+    } else {
+        QString result("\"%1\":%2");
+        return result.arg(metaProperty.name(), propertyValue.toString()).toUtf8();
+    }
+}
+
+void QProtobufJsonSerializer::deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     Q_UNUSED(object)
+    Q_UNUSED(it)
     Q_UNUSED(propertyOrdering)
     Q_UNUSED(metaObject)
-    return QByteArray();
 }
 
-void QProtobufJsonSerializer::deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+QByteArray QProtobufJsonSerializer::serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
+{
+    QByteArray result = "{";
+    result.append(serializeObjectCommon(object, propertyOrdering, metaObject));
+    result.append("}");
+    return result;
+}
+
+void QProtobufJsonSerializer::deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     Q_UNUSED(object)
     Q_UNUSED(it)
@@ -59,7 +84,7 @@ void QProtobufJsonSerializer::deserializeObject(QObject *object, QProtobufSelfch
     Q_UNUSED(metaObject)
 }
 
-QByteArray QProtobufJsonSerializer::serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex)
+QByteArray QProtobufJsonSerializer::serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex) const
 {
     Q_UNUSED(object)
     Q_UNUSED(propertyOrdering)
@@ -68,7 +93,7 @@ QByteArray QProtobufJsonSerializer::serializeListObject(const QObject *object, c
     return QByteArray();
 }
 
-void QProtobufJsonSerializer::deserializeListObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+void QProtobufJsonSerializer::deserializeListObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     Q_UNUSED(object)
     Q_UNUSED(it)
@@ -76,7 +101,7 @@ void QProtobufJsonSerializer::deserializeListObject(QObject *object, QProtobufSe
     Q_UNUSED(metaObject)
 }
 
-QByteArray QProtobufJsonSerializer::serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex)
+QByteArray QProtobufJsonSerializer::serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) const
 {
     Q_UNUSED(key)
     Q_UNUSED(value)
@@ -84,7 +109,7 @@ QByteArray QProtobufJsonSerializer::serializeMapPair(const QVariant &key, const
     return QByteArray();
 }
 
-void QProtobufJsonSerializer::deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it)
+void QProtobufJsonSerializer::deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const
 {
     Q_UNUSED(key)
     Q_UNUSED(value)

+ 16 - 8
src/protobuf/qprotobufjsonserializer.h

@@ -33,17 +33,25 @@ namespace QtProtobuf {
  */
 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;
+public:
+    QProtobufJsonSerializer();
+    ~QProtobufJsonSerializer() = default;
 
-    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;
+protected:
+    QByteArray serializeMessage(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const  override;
+    void deserializeMessage(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const 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 serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const override;
+    void deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
 
-    QByteArray serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) override;
-    void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) override;
+    QByteArray serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
+    void deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
+
+    QByteArray serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex) const override;
+    void deserializeListObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
+
+    QByteArray serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) const override;
+    void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const override;
 };
 
 }

+ 3 - 3
src/protobuf/qprotobufobject.h

@@ -25,7 +25,7 @@
 
 #pragma once
 
-#include "qprotobufserializerregistry.h"
+#include "qabstractprotobufserializer.h"
 #include <unordered_map>
 
 /*!
@@ -40,8 +40,8 @@
 
 #define Q_DECLARE_PROTOBUF_SERIALIZERS(T)\
     public:\
-        QByteArray serialize() const { return QtProtobuf::QProtobufSerializerRegistry::serialize<T>(this); }\
-        void deserialize(const QByteArray &array) { QtProtobuf::QProtobufSerializerRegistry::deserialize<T>(this, array); }\
+        QByteArray serialize(QtProtobuf::QAbstractProtobufSerializer *serializer) const { return serializer->serialize<T>(this); }\
+        void deserialize(QtProtobuf::QAbstractProtobufSerializer *serializer, const QByteArray &array) { serializer->deserialize<T>(this, array); }\
     private:
 
 /*!

+ 90 - 53
src/protobuf/qprotobufserializer.cpp

@@ -23,50 +23,61 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "qabstractprotobufserializer.h"
+#include "qprotobufserializer.h"
 #include "qprotobufserializer_p.h"
-#include "qprotobufserializerregistry.h"
 
 #include <QMetaProperty>
 
 using namespace QtProtobuf;
 
+QProtobufSerializer::~QProtobufSerializer() = default;
+
 QProtobufSerializer::QProtobufSerializer()
 {
-    QProtobufSerializerPrivate::wrapSerializer<float>(m_handlers, QProtobufSerializerPrivate::serializeBasic<float>, QProtobufSerializerPrivate::deserializeBasic<float>, Fixed32);
-    QProtobufSerializerPrivate::wrapSerializer<double>(m_handlers, QProtobufSerializerPrivate::serializeBasic<double>, QProtobufSerializerPrivate::deserializeBasic<double>, Fixed64);
-    QProtobufSerializerPrivate::wrapSerializer<int32>(m_handlers, QProtobufSerializerPrivate::serializeBasic<int32>, QProtobufSerializerPrivate::deserializeBasic<int32>, Varint);
-    QProtobufSerializerPrivate::wrapSerializer<int64>(m_handlers, QProtobufSerializerPrivate::serializeBasic<int64>, QProtobufSerializerPrivate::deserializeBasic<int64>, Varint);
-    QProtobufSerializerPrivate::wrapSerializer<uint32>(m_handlers, QProtobufSerializerPrivate::serializeBasic<uint32>, QProtobufSerializerPrivate::deserializeBasic<uint32>, Varint);
-    QProtobufSerializerPrivate::wrapSerializer<uint64>(m_handlers, QProtobufSerializerPrivate::serializeBasic<uint64>, QProtobufSerializerPrivate::deserializeBasic<uint64>, Varint);
-    QProtobufSerializerPrivate::wrapSerializer<sint32>(m_handlers, QProtobufSerializerPrivate::serializeBasic<sint32>, QProtobufSerializerPrivate::deserializeBasic<sint32>, Varint);
-    QProtobufSerializerPrivate::wrapSerializer<sint64>(m_handlers, QProtobufSerializerPrivate::serializeBasic<sint64>, QProtobufSerializerPrivate::deserializeBasic<sint64>, Varint);
-    QProtobufSerializerPrivate::wrapSerializer<fixed32>(m_handlers, QProtobufSerializerPrivate::serializeBasic<fixed32>, QProtobufSerializerPrivate::deserializeBasic<fixed32>, Fixed32);
-    QProtobufSerializerPrivate::wrapSerializer<fixed64>(m_handlers, QProtobufSerializerPrivate::serializeBasic<fixed64>, QProtobufSerializerPrivate::deserializeBasic<fixed64>, Fixed64);
-    QProtobufSerializerPrivate::wrapSerializer<sfixed32>(m_handlers, QProtobufSerializerPrivate::serializeBasic<sfixed32>, QProtobufSerializerPrivate::deserializeBasic<sfixed32>, Fixed32);
-    QProtobufSerializerPrivate::wrapSerializer<sfixed64>(m_handlers, QProtobufSerializerPrivate::serializeBasic<sfixed64>, QProtobufSerializerPrivate::deserializeBasic<sfixed64>, Fixed64);
-    QProtobufSerializerPrivate::wrapSerializer<bool>(m_handlers, QProtobufSerializerPrivate::serializeBasic<uint32>, QProtobufSerializerPrivate::deserializeBasic<uint32>, Varint);
-    QProtobufSerializerPrivate::wrapSerializer<QString>(m_handlers, QProtobufSerializerPrivate::serializeBasic<QString>, QProtobufSerializerPrivate::deserializeBasic<QString>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<QByteArray>(m_handlers, QProtobufSerializerPrivate::serializeBasic<QByteArray>, QProtobufSerializerPrivate::deserializeBasic<QByteArray>, LengthDelimited);
-
-    QProtobufSerializerPrivate::wrapSerializer<FloatList>(m_handlers, QProtobufSerializerPrivate::serializeListType<float>, QProtobufSerializerPrivate::deserializeList<float>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<DoubleList>(m_handlers, QProtobufSerializerPrivate::serializeListType<double>, QProtobufSerializerPrivate::deserializeList<double>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<fixed32List>(m_handlers, QProtobufSerializerPrivate::serializeListType<fixed32>, QProtobufSerializerPrivate::deserializeList<fixed32>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<fixed64List>(m_handlers, QProtobufSerializerPrivate::serializeListType<fixed64>, QProtobufSerializerPrivate::deserializeList<fixed64>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<sfixed32List>(m_handlers, QProtobufSerializerPrivate::serializeListType<sfixed32>, QProtobufSerializerPrivate::deserializeList<sfixed32>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<sfixed64List>(m_handlers, QProtobufSerializerPrivate::serializeListType<sfixed64>, QProtobufSerializerPrivate::deserializeList<sfixed64>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<int32List>(m_handlers, QProtobufSerializerPrivate::serializeListType<int32>, QProtobufSerializerPrivate::deserializeList<int32>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<int64List>(m_handlers, QProtobufSerializerPrivate::serializeListType<int64>, QProtobufSerializerPrivate::deserializeList<int64>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<sint32List>(m_handlers, QProtobufSerializerPrivate::serializeListType<sint32>, QProtobufSerializerPrivate::deserializeList<sint32>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<sint64List>(m_handlers, QProtobufSerializerPrivate::serializeListType<sint64>, QProtobufSerializerPrivate::deserializeList<sint64>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<uint32List>(m_handlers, QProtobufSerializerPrivate::serializeListType<uint32>, QProtobufSerializerPrivate::deserializeList<uint32>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<uint64List>(m_handlers, QProtobufSerializerPrivate::serializeListType<uint64>, QProtobufSerializerPrivate::deserializeList<uint64>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<QStringList>(m_handlers, QProtobufSerializerPrivate::serializeListType<QString>, QProtobufSerializerPrivate::deserializeList<QString>, LengthDelimited);
-    QProtobufSerializerPrivate::wrapSerializer<QByteArrayList>(m_handlers, QProtobufSerializerPrivate::serializeListType<QByteArray>, QProtobufSerializerPrivate::deserializeList<QByteArray>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<float>(QProtobufSerializerPrivate::serializeBasic<float>, QProtobufSerializerPrivate::deserializeBasic<float>, Fixed32);
+    QProtobufSerializerPrivate::wrapSerializer<double>(QProtobufSerializerPrivate::serializeBasic<double>, QProtobufSerializerPrivate::deserializeBasic<double>, Fixed64);
+    QProtobufSerializerPrivate::wrapSerializer<int32>(QProtobufSerializerPrivate::serializeBasic<int32>, QProtobufSerializerPrivate::deserializeBasic<int32>, Varint);
+    QProtobufSerializerPrivate::wrapSerializer<int64>(QProtobufSerializerPrivate::serializeBasic<int64>, QProtobufSerializerPrivate::deserializeBasic<int64>, Varint);
+    QProtobufSerializerPrivate::wrapSerializer<uint32>(QProtobufSerializerPrivate::serializeBasic<uint32>, QProtobufSerializerPrivate::deserializeBasic<uint32>, Varint);
+    QProtobufSerializerPrivate::wrapSerializer<uint64>(QProtobufSerializerPrivate::serializeBasic<uint64>, QProtobufSerializerPrivate::deserializeBasic<uint64>, Varint);
+    QProtobufSerializerPrivate::wrapSerializer<sint32>(QProtobufSerializerPrivate::serializeBasic<sint32>, QProtobufSerializerPrivate::deserializeBasic<sint32>, Varint);
+    QProtobufSerializerPrivate::wrapSerializer<sint64>(QProtobufSerializerPrivate::serializeBasic<sint64>, QProtobufSerializerPrivate::deserializeBasic<sint64>, Varint);
+    QProtobufSerializerPrivate::wrapSerializer<fixed32>(QProtobufSerializerPrivate::serializeBasic<fixed32>, QProtobufSerializerPrivate::deserializeBasic<fixed32>, Fixed32);
+    QProtobufSerializerPrivate::wrapSerializer<fixed64>(QProtobufSerializerPrivate::serializeBasic<fixed64>, QProtobufSerializerPrivate::deserializeBasic<fixed64>, Fixed64);
+    QProtobufSerializerPrivate::wrapSerializer<sfixed32>(QProtobufSerializerPrivate::serializeBasic<sfixed32>, QProtobufSerializerPrivate::deserializeBasic<sfixed32>, Fixed32);
+    QProtobufSerializerPrivate::wrapSerializer<sfixed64>(QProtobufSerializerPrivate::serializeBasic<sfixed64>, QProtobufSerializerPrivate::deserializeBasic<sfixed64>, Fixed64);
+    QProtobufSerializerPrivate::wrapSerializer<bool>(QProtobufSerializerPrivate::serializeBasic<uint32>, QProtobufSerializerPrivate::deserializeBasic<uint32>, Varint);
+    QProtobufSerializerPrivate::wrapSerializer<QString>(QProtobufSerializerPrivate::serializeBasic<QString>, QProtobufSerializerPrivate::deserializeBasic<QString>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<QByteArray>(QProtobufSerializerPrivate::serializeBasic<QByteArray>, QProtobufSerializerPrivate::deserializeBasic<QByteArray>, LengthDelimited);
+
+    QProtobufSerializerPrivate::wrapSerializer<FloatList>(QProtobufSerializerPrivate::serializeListType<float>, QProtobufSerializerPrivate::deserializeList<float>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<DoubleList>(QProtobufSerializerPrivate::serializeListType<double>, QProtobufSerializerPrivate::deserializeList<double>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<fixed32List>(QProtobufSerializerPrivate::serializeListType<fixed32>, QProtobufSerializerPrivate::deserializeList<fixed32>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<fixed64List>(QProtobufSerializerPrivate::serializeListType<fixed64>, QProtobufSerializerPrivate::deserializeList<fixed64>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<sfixed32List>(QProtobufSerializerPrivate::serializeListType<sfixed32>, QProtobufSerializerPrivate::deserializeList<sfixed32>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<sfixed64List>(QProtobufSerializerPrivate::serializeListType<sfixed64>, QProtobufSerializerPrivate::deserializeList<sfixed64>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<int32List>(QProtobufSerializerPrivate::serializeListType<int32>, QProtobufSerializerPrivate::deserializeList<int32>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<int64List>(QProtobufSerializerPrivate::serializeListType<int64>, QProtobufSerializerPrivate::deserializeList<int64>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<sint32List>(QProtobufSerializerPrivate::serializeListType<sint32>, QProtobufSerializerPrivate::deserializeList<sint32>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<sint64List>(QProtobufSerializerPrivate::serializeListType<sint64>, QProtobufSerializerPrivate::deserializeList<sint64>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<uint32List>(QProtobufSerializerPrivate::serializeListType<uint32>, QProtobufSerializerPrivate::deserializeList<uint32>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<uint64List>(QProtobufSerializerPrivate::serializeListType<uint64>, QProtobufSerializerPrivate::deserializeList<uint64>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<QStringList>(QProtobufSerializerPrivate::serializeListType<QString>, QProtobufSerializerPrivate::deserializeList<QString>, LengthDelimited);
+    QProtobufSerializerPrivate::wrapSerializer<QByteArrayList>(QProtobufSerializerPrivate::serializeListType<QByteArray>, QProtobufSerializerPrivate::deserializeList<QByteArray>, LengthDelimited);
+
+}
+
+QByteArray QProtobufSerializer::serializeMessage(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
+{
+    return serializeObjectCommon(object, propertyOrdering, metaObject);
+}
 
+void QProtobufSerializer::deserializeMessage(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
+{
+    deserializeObjectCommon(object, data, propertyOrdering, metaObject);
 }
 
-QByteArray QProtobufSerializer::serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty)
+QByteArray QProtobufSerializer::serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const
 {
     qProtoDebug() << __func__ << "propertyValue" << propertyValue << "fieldIndex" << fieldIndex
                   << static_cast<QMetaType::Type>(propertyValue.type());
@@ -79,21 +90,28 @@ QByteArray QProtobufSerializer::serializeProperty(const QVariant &propertyValue,
         userType = qMetaTypeId<int64>();
     }
 
-    auto handler = QProtobufSerializerRegistry::handler(userType);
-    type = handler.type;
-    result.append(handler.serializer(propertyValue, fieldIndex));
+    //TODO: replace with some common function
+    auto basicIt = QProtobufSerializerPrivate::handlers.find(userType);
+    if (basicIt != QProtobufSerializerPrivate::handlers.end()) {
+        type = basicIt->second.type;
+        result.append(basicIt->second.serializer(propertyValue, fieldIndex));
+    } else {
+        auto &handler = QtProtobufPrivate::findHandler(userType);
+        type = handler.type;
+        result.append(handler.serializer(this, propertyValue, fieldIndex));//throws if not implemented
+    }
 
-    if (fieldIndex != NotUsedFieldIndex
+    if (fieldIndex != QtProtobufPrivate::NotUsedFieldIndex
             && type != UnknownWireType) {
         result.prepend(QProtobufSerializerPrivate::encodeHeader(fieldIndex, type));
     }
     return result;
 }
 
-void QProtobufSerializer::deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+void QProtobufSerializer::deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     //Each iteration we expect iterator is setup to beginning of next chunk
-    int fieldNumber = NotUsedFieldIndex;
+    int fieldNumber = QtProtobufPrivate::NotUsedFieldIndex;
     WireTypes wireType = UnknownWireType;
     if (!QProtobufSerializerPrivate::decodeHeader(it, fieldNumber, wireType)) {
         qProtoCritical() << "Message received doesn't contains valid header byte. "
@@ -122,43 +140,49 @@ void QProtobufSerializer::deserializeProperty(QObject *object, QProtobufSelfchec
     } else {
         newPropertyValue = metaProperty.read(object);
         int userType = metaProperty.userType();
-        auto deserializer = QProtobufSerializerRegistry::handler(userType).deserializer;
-        deserializer(it, newPropertyValue);
+        //TODO: replace with some common function
+        auto basicIt = QProtobufSerializerPrivate::handlers.find(userType);
+        if (basicIt != QProtobufSerializerPrivate::handlers.end()) {
+            basicIt->second.deserializer(it, newPropertyValue);
+        } else {
+            auto &handler = QtProtobufPrivate::findHandler(userType);
+            handler.deserializer(this, it, newPropertyValue);//throws if not implemented
+        }
     }
     metaProperty.write(object, newPropertyValue);
 }
 
-QByteArray QProtobufSerializer::serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+QByteArray QProtobufSerializer::serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     return QProtobufSerializerPrivate::prependLengthDelimitedSize(serializeObjectCommon(object, propertyOrdering, metaObject));
 }
 
-void QProtobufSerializer::deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+void QProtobufSerializer::deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     QByteArray array = QProtobufSerializerPrivate::deserializeLengthDelimited(it);
     deserializeObjectCommon(object, array, propertyOrdering, metaObject);
 }
 
-QByteArray QProtobufSerializer::serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex)
+QByteArray QProtobufSerializer::serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex) const
 {
     QByteArray result = QProtobufSerializerPrivate::encodeHeader(fieldIndex, LengthDelimited);
     result.append(serializeObject(object, propertyOrdering, metaObject));
     return result;
 }
 
-void QProtobufSerializer::deserializeListObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+void QProtobufSerializer::deserializeListObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     deserializeObject(object, it, propertyOrdering, metaObject);
 }
 
-QByteArray QProtobufSerializer::serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex)
+QByteArray QProtobufSerializer::serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) const
 {
     QByteArray result = QProtobufSerializerPrivate::encodeHeader(fieldIndex, LengthDelimited);
     result.append(QProtobufSerializerPrivate::prependLengthDelimitedSize(serializeProperty(key, 1, QMetaProperty()) + serializeProperty(value, 2, QMetaProperty())));
     return result;
 }
 
-void QProtobufSerializer::deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it)
+void QProtobufSerializer::deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const
 {
     int mapIndex = 0;
     WireTypes type = WireTypes::UnknownWireType;
@@ -168,9 +192,25 @@ void QProtobufSerializer::deserializeMapPair(QVariant &key, QVariant &value, QPr
     while (it != last) {
         QProtobufSerializerPrivate::decodeHeader(it, mapIndex, type);
         if (mapIndex == 1) {
-            QProtobufSerializerPrivate::deserializeMapField(key, it);
+            //TODO: replace with some common function
+            int userType = key.userType();
+            auto basicIt = QProtobufSerializerPrivate::handlers.find(userType);
+            if (basicIt != QProtobufSerializerPrivate::handlers.end()) {
+                basicIt->second.deserializer(it, key);
+            } else {
+                auto &handler = QtProtobufPrivate::findHandler(userType);
+                handler.deserializer(this, it, key);
+            }
         } else {
-            QProtobufSerializerPrivate::deserializeMapField(value, it);
+            //TODO: replace with some common function
+            int userType = value.userType();
+            auto basicIt = QProtobufSerializerPrivate::handlers.find(userType);
+            if (basicIt != QProtobufSerializerPrivate::handlers.end()) {
+                basicIt->second.deserializer(it, value);
+            } else {
+                auto &handler = QtProtobufPrivate::findHandler(userType);
+                handler.deserializer(this, it, value);//throws if not implemented
+            }
         }
     }
 }
@@ -214,7 +254,4 @@ int QProtobufSerializerPrivate::skipSerializedFieldBytes(QProtobufSelfcheckItera
     return std::distance(initialIt, QByteArray::const_iterator(it));
 }
 
-void QProtobufSerializerPrivate::deserializeMapField(QVariant &value, QProtobufSelfcheckIterator &it)
-{
-    QProtobufSerializerRegistry::handler(value.userType()).deserializer(it, value);
-}
+QProtobufSerializerPrivate::SerializerRegistry QProtobufSerializerPrivate::handlers = {};

+ 64 - 0
src/protobuf/qprotobufserializer.h

@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "qabstractprotobufserializer.h"
+#include "qtprotobufglobal.h"
+
+namespace QtProtobuf {
+
+class QProtobufSerializerPrivate;
+/*!
+ * \ingroup QtProtobuf
+ * \brief The QProtobufSerializer class
+ */
+class Q_PROTOBUF_EXPORT QProtobufSerializer : public QAbstractProtobufSerializer
+{
+public:
+    QProtobufSerializer();
+    ~QProtobufSerializer();
+
+protected:
+    QByteArray serializeMessage(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
+    void deserializeMessage(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
+
+    QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const override;
+    void deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
+
+    QByteArray serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
+    void deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
+
+    QByteArray serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex) const override;
+    void deserializeListObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
+
+    QByteArray serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) const override;
+    void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const override;
+
+private:
+    std::unique_ptr<QProtobufSerializerPrivate> d;
+};
+
+}

+ 37 - 15
src/protobuf/qprotobufserializer_p.h

@@ -38,13 +38,36 @@ namespace QtProtobuf {
  *
  * \brief The QProtobufSerializerPrivate class
  */
-class QProtobufSerializerPrivate {
-    QProtobufSerializerPrivate() = delete;
-    ~QProtobufSerializerPrivate() = delete;
+class QProtobufSerializer;
+
+class QProtobufSerializerPrivate final {
     Q_DISABLE_COPY(QProtobufSerializerPrivate)
     QProtobufSerializerPrivate(QProtobufSerializerPrivate &&) = delete;
     QProtobufSerializerPrivate &operator =(QProtobufSerializerPrivate &&) = delete;
 public:
+
+    /*!
+     * \brief Serializer is interface function for serialize method
+     */
+    using Serializer = std::function<QByteArray(const QVariant &, int &)>;
+    /*!
+     * \brief Deserializer is interface function for deserialize method
+     */
+    using Deserializer = std::function<void(QProtobufSelfcheckIterator &, QVariant &)>;
+
+    /*!
+     * \brief SerializationHandlers contains set of objects that required for class serializaion/deserialization
+     */
+    struct SerializationHandlers {
+        Serializer serializer; /*!< serializer assigned to class */
+        Deserializer deserializer;/*!< deserializer assigned to class */
+        WireTypes type;/*!< Serialization WireType */
+    };
+
+    using SerializerRegistry = std::unordered_map<int/*metatypeid*/, SerializationHandlers>;
+
+    QProtobufSerializerPrivate();
+    ~QProtobufSerializerPrivate() = default;
     //###########################################################################
     //                               Serializers
     //###########################################################################
@@ -179,7 +202,7 @@ public:
         // Invalidate field index in case if serialized result is empty
         // NOTE: the field will not be sent if its index is equal to NotUsedFieldIndex
         if (result.size() == 0) {
-            outFieldIndex = NotUsedFieldIndex;
+            outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
         } else {
             //Mark last chunk as last by clearing last bit
             result.data()[result.size() - 1] &= ~0b10000000;
@@ -209,11 +232,11 @@ public:
         qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
 
         if (listValue.count() <= 0) {
-            outFieldIndex = NotUsedFieldIndex;
+            outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
             return QByteArray();
         }
 
-        int empty = NotUsedFieldIndex;
+        int empty = QtProtobufPrivate::NotUsedFieldIndex;
         QByteArray serializedList;
         for (auto &value : listValue) {
             serializedList.append(serializeBasic<V>(value, empty));
@@ -229,7 +252,7 @@ public:
         qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
 
         if (listValue.count() <= 0) {
-            outFieldIndex = NotUsedFieldIndex;
+            outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
             return QByteArray();
         }
 
@@ -239,7 +262,7 @@ public:
             serializedList.append(serializeLengthDelimited(value.toUtf8()));
         }
 
-        outFieldIndex = NotUsedFieldIndex;
+        outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
         return serializedList;
     }
 
@@ -249,7 +272,7 @@ public:
         qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
 
         if (listValue.count() <= 0) {
-            outFieldIndex = NotUsedFieldIndex;
+            outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
             return QByteArray();
         }
 
@@ -259,7 +282,7 @@ public:
             serializedList.append(serializeLengthDelimited(value));
         }
 
-        outFieldIndex = NotUsedFieldIndex;
+        outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
         return serializedList;
     }
 
@@ -424,11 +447,9 @@ public:
     // in a serialized message met while the message being deserialized
     static int skipSerializedFieldBytes(QProtobufSelfcheckIterator &it, WireTypes type);
 
-    static void deserializeMapField(QVariant &value, QProtobufSelfcheckIterator &it);
-
     template <typename T,
               typename std::enable_if_t<!std::is_base_of<QObject, T>::value, int> = 0>
-    static void wrapSerializer(QAbstractProtobufSerializer::SerializerRegistry &handlers, const std::function<QByteArray(const T &, int &)> &s, const std::function<QVariant(QProtobufSelfcheckIterator &)> &d, WireTypes type)
+    static void wrapSerializer(const std::function<QByteArray(const T &, int &)> &s, const std::function<QVariant(QProtobufSelfcheckIterator &)> &d, WireTypes type)
     {
         handlers[qMetaTypeId<T>()] = {
             [s](const QVariant &value, int &fieldIndex) {
@@ -443,7 +464,7 @@ public:
 
     template <typename T,
     typename std::enable_if_t<!std::is_base_of<QObject, T>::value, int> = 0>
-    static void wrapSerializer(QAbstractProtobufSerializer::SerializerRegistry &handlers, const std::function<QByteArray(const T &, int &)> &s, const std::function<void(QProtobufSelfcheckIterator &it, QVariant & value)> &d, WireTypes type)
+    static void wrapSerializer(const std::function<QByteArray(const T &, int &)> &s, const std::function<void(QProtobufSelfcheckIterator &it, QVariant & value)> &d, WireTypes type)
     {
         handlers[qMetaTypeId<T>()] = {
             [s](const QVariant &value, int &fieldIndex) {
@@ -453,7 +474,8 @@ public:
             type
         };
     }
-protected:
+
+    static SerializerRegistry handlers;
     static void skipVarint(QProtobufSelfcheckIterator &it);
     static void skipLengthDelimited(QProtobufSelfcheckIterator &it);
 };

+ 0 - 21
src/protobuf/qprotobufserializerregistry.cpp

@@ -26,24 +26,3 @@
 #include "qprotobufserializerregistry.h"
 
 using namespace QtProtobuf;
-
-QAbstractProtobufSerializer::SerializerRegistry QProtobufSerializerRegistry::handlers = {};
-std::unique_ptr<QAbstractProtobufSerializer> QProtobufSerializerRegistry::basicSerializer;
-QAbstractProtobufSerializer::SerializationHandlers QProtobufSerializerRegistry::empty;
-
-const QAbstractProtobufSerializer::SerializationHandlers &QProtobufSerializerRegistry::handler(int userType)
-{
-    QAbstractProtobufSerializer::SerializerRegistry::const_iterator it = handlers.find(userType);
-    if (it != handlers.end()) {
-        return it->second;
-    }
-
-    if (basicSerializer != nullptr) {
-        it = basicSerializer->handlers().find(userType);
-        if (it != basicSerializer->handlers().end()) {
-            return it->second;
-        }
-    }
-    qProtoCritical() << "Serializer for user type: " << QMetaType::typeName(userType) << " is not found";
-    return empty;
-}

+ 3 - 262
src/protobuf/qprotobufserializerregistry.h

@@ -40,23 +40,11 @@
 namespace QtProtobuf {
 /*!
  * \ingroup QtProtobuf
- * \brief The QProtobufSerializerRegistry class provides api to register serializers of QObjects
+ * \brief The QProtobufSerializerRegistry class provides api to register serializers
+ *        Loads serializer plugins and constructs them based on plugin identifier.
  *
- * \details The QProtobufSerializerRegistry class registers serializers/deserializers for classes inherited of QObject.
- *          To register serializers for user-defined class it has to be inherited of QObjec contain macro's.
- *          \code{.cpp}
- *          class MyType : public QObject
- *          {
- *              Q_OBJECT
- *              Q_PROTOBUF_OBJECT
- *              Q_PROPERTY(qprotobuf::sint32 prop READ prop WRITE setProp NOTIFY propChanged)
- *              ...
- *              Q_DECLARE_PROTOBUF_SERIALIZERS(MyType)
- *          };
- *          \endcode
- *          Practically code above is generated automaticaly by running qtprotobufgenerator or using cmake build macro
- *          generate_qtprotobuf, based on .proto files. But it's still possible to reuse manually written code if needed.
  */
+//TODO: this class is not implemented and is private
 class Q_PROTOBUF_EXPORT QProtobufSerializerRegistry
 {
     QProtobufSerializerRegistry() = delete;
@@ -65,253 +53,6 @@ class Q_PROTOBUF_EXPORT QProtobufSerializerRegistry
     Q_DISABLE_COPY(QProtobufSerializerRegistry)
     QProtobufSerializerRegistry(QProtobufSerializerRegistry &&) = delete;
     QProtobufSerializerRegistry &operator =(QProtobufSerializerRegistry &&) = delete;
-
-    static QAbstractProtobufSerializer::SerializerRegistry handlers;
-    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
-     *
-     *
-     * \param[in] object Pointer to QObject containing message to be serialized
-     * @result serialized message bytes
-     */
-    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);
-    }
-
-    /*!
-     * \brief Deserialization of a byte-array into a registered qtproto message object
-     *
-     * \details Properties in a message are identified via ProtobufObjectPrivate::decodeHeader.
-     *          Bytes corresponding to unexpected properties are skipped without any exception
-     *
-     * \param[out] object Pointer to memory where result of deserialization should be injected
-     * \param[in] array Bytes with serialized message
-     */
-    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
-     *
-     * \details generates default serializers for type T. Type T has to be inherited of QObject.
-     */
-    template<typename T>
-    static void registerSerializers() {
-        handlers[qMetaTypeId<T *>()] = { serializeComplexType<T>,
-                deserializeComplexType<T>, LengthDelimited };
-        handlers[qMetaTypeId<QList<QSharedPointer<T>>>()] = { serializeList<T>,
-                deserializeList<T>, LengthDelimited };
-    }
-
-    /*!
-     * \brief Registers serializers for type QMap<K, V> in QProtobufSerializerRegistry
-     *
-     * \details generates default serializers for QMap<K, V>.
-     */
-    template<typename K, typename V,
-             typename std::enable_if_t<!std::is_base_of<QObject, V>::value, int> = 0>
-    static void registerMap() {
-        handlers[qMetaTypeId<QMap<K, V>>()] = { serializeMap<K, V>,
-        deserializeMap<K, V>, LengthDelimited };
-    }
-
-    /*!
-     * \brief Registers serializers for type QMap<K, V> in QProtobufSerializerRegistry
-     *
-     * \details generates default serializers for QMap<K, V>. Specialization for V type
-     *          inherited of QObject.
-     */
-    template<typename K, typename V,
-             typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
-    static void registerMap() {
-        handlers[qMetaTypeId<QMap<K, QSharedPointer<V>>>()] = { serializeMap<K, V>,
-        deserializeMap<K, V>, LengthDelimited };
-    }
-
-private:
-    /*!
-     * \private
-     *
-     * \brief default serializer template for type T inherited of QObject
-     */
-    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);
-    }
-
-    /*!
-     * \private
-     *
-     * \brief default serializer template for list of type T objects inherited of QObject
-     */
-    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;
-
-        if (list.count() <= 0) {
-            outFieldIndex = NotUsedFieldIndex;
-            return QByteArray();
-        }
-
-        QByteArray serializedList;
-        for (auto &value : list) {
-            if (!value) {
-                qProtoWarning() << "Null pointer in list";
-                continue;
-            }
-            serializedList.append(basicSerializer->serializeListObject(value.data(), V::propertyOrdering, V::staticMetaObject, outFieldIndex));
-        }
-
-        outFieldIndex = NotUsedFieldIndex;
-
-        return serializedList;
-    }
-
-    /*!
-     * \private
-     *
-     * \brief default serializer template for map of key K, value V
-     */
-    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;
-
-        for ( ItType it = mapValue.constBegin(); it != mapValue.constEnd(); it++) {
-            mapResult.append(basicSerializer->serializeMapPair(QVariant::fromValue<K>(it.key()), QVariant::fromValue<V>(it.value()), outFieldIndex));
-        }
-        outFieldIndex = NotUsedFieldIndex;
-        return mapResult;
-    }
-
-    /*!
-     * \private
-     *
-     * \brief default serializer template for map of type key K, value V. Specialization for V
-     *        inherited of QObject
-     */
-    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;
-
-        for ( ItType it = mapValue.constBegin(); it != mapValue.constEnd(); it++) {
-            if (it.value().isNull()) {
-                qProtoWarning() << __func__ << "Trying to serialize map value that contains nullptr";
-                continue;
-            }
-            mapResult.append(basicSerializer->serializeMapPair(QVariant::fromValue<K>(it.key()), QVariant::fromValue<V *>(it.value().data()), outFieldIndex));
-        }
-        outFieldIndex = NotUsedFieldIndex;
-        return mapResult;
-    }
-
-    /*!
-     * \private
-     *
-     * \brief default deserializer template for type T inherited of QObject
-     */
-    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);
-    }
-
-    /*!
-     * \private
-     *
-     * \brief default deserializer template for list of type T objects inherited of QObject
-     */
-    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;
-        QList<QSharedPointer<V>> list = previous.value<QList<QSharedPointer<V>>>();
-        basicSerializer->deserializeListObject(newValue, it, V::propertyOrdering, V::staticMetaObject);
-        list.append(QSharedPointer<V>(newValue));
-        previous.setValue(list);
-    }
-
-    /*!
-     * \private
-     *
-     * \brief default deserializer template for map of key K, value V
-     */
-    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>>();
-        QVariant key = QVariant::fromValue<K>(K());
-        QVariant value = QVariant::fromValue<V>(V());
-
-        basicSerializer->deserializeMapPair(key, value, it);
-        out[key.value<K>()] = value.value<V>();
-        previous = QVariant::fromValue<QMap<K, V>>(out);
-    }
-
-    /*!
-     * \private
-     *
-     * \brief default deserializer template for map of type key K, value V. Specialization for V
-     *        inherited of QObject
-     */
-    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>>>();
-        QVariant key = QVariant::fromValue<K>(K());
-        QVariant value = QVariant::fromValue<V *>(nullptr);
-
-        basicSerializer->deserializeMapPair(key, value, it);
-        out[key.value<K>()] = QSharedPointer<V>(value.value<V *>());
-        previous = QVariant::fromValue<QMap<K, QSharedPointer<V>>>(out);
-    }
 };
 }

+ 3 - 1
tests/test_grpc/clienttest.cpp

@@ -37,6 +37,8 @@
 #include <QCoreApplication>
 #include <gtest/gtest.h>
 
+#include <qprotobufserializer.h>
+
 using namespace qtprotobufnamespace::tests;
 using namespace QtProtobuf;
 
@@ -57,8 +59,8 @@ 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;
+    testClient.attachChannel(std::make_shared<QGrpcHttp2Channel>(QUrl(), InsecureCredentials()));
     SimpleStringMessage request;
     QPointer<SimpleStringMessage> result(new SimpleStringMessage);
     testClient.testMethod(request, result);

+ 2 - 1
tests/test_protobuf/CMakeLists.txt

@@ -143,7 +143,8 @@ file(GLOB SOURCES
     serializationtest.cpp
     deserializationtest.cpp
     serializationcomplexmessagemap.cpp
-    converterstest.cpp)
+    converterstest.cpp
+    jsonserializationtest.cpp)
 
 add_test_target(TARGET ${TARGET}
     GENERATED_HEADERS ${GENERATED_HEADERS}

File diff suppressed because it is too large
+ 83 - 85
tests/test_protobuf/deserializationtest.cpp


+ 3 - 0
tests/test_protobuf/deserializationtest.h

@@ -26,6 +26,7 @@
 #pragma once
 
 #include <gtest/gtest.h>
+#include <qprotobufserializer.h>
 
 namespace QtProtobuf {
 namespace tests {
@@ -35,6 +36,8 @@ class DeserializationTest : public ::testing::Test
 public:
     DeserializationTest() = default;
     void SetUp() override;
+protected:
+    std::unique_ptr<QProtobufSerializer> serializer;
 };
 
 }

+ 60 - 0
tests/test_protobuf/jsonserializationtest.cpp

@@ -0,0 +1,60 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <QByteArray>
+#include <QString>
+#include <simplefixedint32message.h>
+#include <qprotobufjsonserializer.h>
+
+using namespace qtprotobufnamespace::tests;
+
+namespace QtProtobuf {
+namespace tests {
+
+class JsonSerializationTest : public ::testing::Test
+{
+public:
+    JsonSerializationTest() = default;
+    void SetUp() override;
+protected:
+    std::unique_ptr<QProtobufJsonSerializer> serializer;
+};
+
+void JsonSerializationTest::SetUp() {
+    serializer.reset(new QProtobufJsonSerializer);
+}
+
+TEST_F(JsonSerializationTest, FixedInt32MessageDeserializeTest)
+{
+    SimpleFixedInt32Message msg;
+    msg.setTestFieldFixedInt32(555);
+    QByteArray result = msg.serialize(serializer.get());
+    ASSERT_STREQ(QString::fromUtf8(result).toStdString().c_str(), "{\"testFieldFixedInt32\":555}");
+}
+
+
+}
+}

+ 11 - 11
tests/test_protobuf/serializationcomplexmessagemap.cpp

@@ -48,7 +48,7 @@ TEST_F(SerializationTest, SimpleFixed32ComplexMapSerializeTest)
 {
     SimpleFixed32ComplexMessageMapMessage test;
     test.setMapField({{10, QSharedPointer<ComplexMessage>(new ComplexMessage{16, {"ten sixteen"}})}, {42, QSharedPointer<ComplexMessage>(new ComplexMessage{10, {"fourty two ten sixteen"}})}, {65555, QSharedPointer<ComplexMessage>(new ComplexMessage{10, {"WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
 
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "3a180d0a0000001211120d320b74656e207369787465656e08103a230d2a000000121c12183216666f757274792074776f2074656e207369787465656e080a3a110d13000100120a120632045755543f080a");
@@ -58,7 +58,7 @@ TEST_F(SerializationTest, SimpleSFixed32ComplexMapSerializeTest)
 {
     SimpleSFixed32ComplexMessageMapMessage test;
     test.setMapField({{10, QSharedPointer<ComplexMessage>(new ComplexMessage{16 , {"ten sixteen"}})}, {-42, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"minus fourty two ten sixteen"}})}, {65555, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
 
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "4a290dd6ffffff1222121e321c6d696e757320666f757274792074776f2074656e207369787465656e080a4a180d0a0000001211120d320b74656e207369787465656e08104a110d13000100120a120632045755543f080a");
@@ -68,7 +68,7 @@ TEST_F(SerializationTest, SimpleInt32ComplexMapSerializeTest)
 {
     SimpleInt32ComplexMessageMapMessage test;
     test.setMapField({{10, QSharedPointer<ComplexMessage>(new ComplexMessage{16 , {"ten sixteen"}})}, {-42, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"minus fourty two ten sixteen"}})}, {65555, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
 
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "1a2a08d6ffffff0f1222121e321c6d696e757320666f757274792074776f2074656e207369787465656e080a1a15080a1211120d320b74656e207369787465656e08101a1008938004120a120632045755543f080a");
@@ -78,7 +78,7 @@ TEST_F(SerializationTest, SimpleSInt32ComplexMapSerializeTest)
 {
     SimpleSInt32ComplexMessageMapMessage test;
     test.setMapField({{10, QSharedPointer<ComplexMessage>(new ComplexMessage{16 , {"ten sixteen"}})}, {42, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"fourty two ten sixteen"}})}, {-65555, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"minus WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
 
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "0a1608a580081210120c320a6d696e7573205755543f080a0a1508141211120d320b74656e207369787465656e08100a200854121c12183216666f757274792074776f2074656e207369787465656e080a");
@@ -88,7 +88,7 @@ TEST_F(SerializationTest, SimpleUInt32ComplexMapSerializeTest)
 {
     SimpleUInt32ComplexMessageMapMessage test;
     test.setMapField({{10, QSharedPointer<ComplexMessage>(new ComplexMessage{16 , {"ten sixteen"}})}, {42, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"fourty two ten sixteen"}})}, {65555, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
 
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "2a15080a1211120d320b74656e207369787465656e08102a20082a121c12183216666f757274792074776f2074656e207369787465656e080a2a1008938004120a120632045755543f080a");
@@ -98,7 +98,7 @@ TEST_F(SerializationTest, SimpleFixed64ComplexMapSerializeTest)
 {
     SimpleFixed64ComplexMessageMapMessage test;
     test.setMapField({{10, QSharedPointer<ComplexMessage>(new ComplexMessage{16 , {"ten sixteen"}})}, {UINT64_MAX, QSharedPointer<ComplexMessage>(new ComplexMessage{42 , {"minus fourty two ten MAAAX"}})}, {65555, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
 
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "421c090a000000000000001211120d320b74656e207369787465656e08104215091300010000000000120a120632045755543f080a422b09ffffffffffffffff1220121c321a6d696e757320666f757274792074776f2074656e204d41414158082a");
@@ -108,7 +108,7 @@ TEST_F(SerializationTest, SimpleSFixed64ComplexMapSerializeTest)
 {
     SimpleSFixed64ComplexMessageMapMessage test;
     test.setMapField({{10, QSharedPointer<ComplexMessage>(new ComplexMessage{16 , {"ten sixteen"}})}, {-42, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"minus fourty two ten sixteen"}})}, {65555, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
 
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "522d09d6ffffffffffffff1222121e321c6d696e757320666f757274792074776f2074656e207369787465656e080a521c090a000000000000001211120d320b74656e207369787465656e08105215091300010000000000120a120632045755543f080a");
@@ -118,7 +118,7 @@ TEST_F(SerializationTest, SimpleInt64ComplexMapSerializeTest)
 {
     SimpleInt64ComplexMessageMapMessage test;
     test.setMapField({{10, QSharedPointer<ComplexMessage>(new ComplexMessage{16 , {"ten sixteen"}})}, {-42, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"minus fourty two ten sixteen"}})}, {65555, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
 
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "222f08d6ffffffffffffffff011222121e321c6d696e757320666f757274792074776f2074656e207369787465656e080a2215080a1211120d320b74656e207369787465656e0810221008938004120a120632045755543f080a");
@@ -128,7 +128,7 @@ TEST_F(SerializationTest, SimpleSInt64ComplexMapSerializeTest)
 {
     SimpleSInt64ComplexMessageMapMessage test;
     test.setMapField({{10, QSharedPointer<ComplexMessage>(new ComplexMessage{16 , {"ten sixteen"}})}, {-42, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"minus fourty two ten sixteen"}})}, {65555, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "122608531222121e321c6d696e757320666f757274792074776f2074656e207369787465656e080a121508141211120d320b74656e207369787465656e0810121008a68008120a120632045755543f080a");
 }
@@ -137,7 +137,7 @@ TEST_F(SerializationTest, SimpleUInt64ComplexMapSerializeTest)
 {
     SimpleUInt64ComplexMessageMapMessage test;
     test.setMapField({{10, QSharedPointer<ComplexMessage>(new ComplexMessage{11 , {"ten eleven"}})}, {42, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"fourty two ten sixteen"}})}, {65555, QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
 
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "3214080a1210120c320a74656e20656c6576656e080b3220082a121c12183216666f757274792074776f2074656e207369787465656e080a321008938004120a120632045755543f080a");
@@ -147,7 +147,7 @@ TEST_F(SerializationTest, SimpleStringComplexMapSerializeTest)
 {
     SimpleStringComplexMessageMapMessage test;
     test.setMapField({{"ben", QSharedPointer<ComplexMessage>(new ComplexMessage{11 , {"ten eleven"}})}, {"where is my car dude?", QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"fourty two ten sixteen"}})}, {"WUT??", QSharedPointer<ComplexMessage>(new ComplexMessage{10 , {"?WUT?"}})}});
-    QByteArray result = test.serialize();
+    QByteArray result = test.serialize(serializer.get());
 
     ASSERT_STREQ(result.toHex().toStdString().c_str(),
                 "6a140a055755543f3f120b120732053f5755543f080a6a170a0362656e1210120c320a74656e20656c6576656e080b6a350a157768657265206973206d792063617220647564653f121c12183216666f757274792074776f2074656e207369787465656e080a");

File diff suppressed because it is too large
+ 147 - 147
tests/test_protobuf/serializationtest.cpp


+ 3 - 0
tests/test_protobuf/serializationtest.h

@@ -26,6 +26,7 @@
 #pragma once
 
 #include <gtest/gtest.h>
+#include <qprotobufserializer.h>
 
 namespace QtProtobuf {
 namespace tests {
@@ -35,6 +36,8 @@ class SerializationTest : public ::testing::Test
 public:
     SerializationTest() = default;
     void SetUp() override;
+protected:
+    std::unique_ptr<QProtobufSerializer> serializer;
 };
 
 }

Some files were not shown because too many files changed in this diff