├── lib ├── QJsonSerializer ├── jsonserializer.prf ├── Array.cpp ├── Library.h ├── QJsonSerializer.cpp ├── ISerializable.h ├── Dictionary.cpp ├── SerializerBase.h ├── DeserializerBase.h ├── lib.pro ├── ISerializer.h ├── SerializerBase.cpp ├── QJsonSerializer.h ├── IObjectFactory.h ├── Array.h ├── Dictionary.h ├── IDeserializer.h └── DeserializerBase.cpp ├── QJsonSerializer.pro ├── tests ├── Child.cpp ├── GadgetChild.cpp ├── GadgetChild.h ├── Child.h ├── tests.pro ├── GadgetEntity.cpp ├── GadgetEntity.h ├── Entity.cpp ├── Entity.h └── SerializerTests.cpp ├── .gitignore ├── README.md └── LICENSE /lib/QJsonSerializer: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /QJsonSerializer.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = lib tests 3 | -------------------------------------------------------------------------------- /lib/jsonserializer.prf: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QJsonSerializer 2 | LIBS += -l$$qtLibraryTarget(QJsonSerializer) 3 | -------------------------------------------------------------------------------- /lib/Array.cpp: -------------------------------------------------------------------------------- 1 | #include "Array.h" 2 | #include "SerializerBase.h" 3 | 4 | QJsonValue IArray::serialize(const SerializerBase &serializer) const 5 | { 6 | return serializer.serializeArray(*this); 7 | } 8 | -------------------------------------------------------------------------------- /lib/Library.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBRARY_H 2 | #define LIBRARY_H 3 | 4 | #ifdef QJSONSERIALIZER_LIBRARY 5 | #define QJSONSERIALIZER_EXPORT Q_DECL_EXPORT 6 | #else 7 | #define QJSONSERIALIZER_EXPORT Q_DECL_IMPORT 8 | #endif 9 | 10 | #endif // LIBRARY_H 11 | -------------------------------------------------------------------------------- /tests/Child.cpp: -------------------------------------------------------------------------------- 1 | #include "Child.h" 2 | 3 | Child::Child() 4 | : m_intProperty(0) 5 | { 6 | } 7 | 8 | int Child::intProperty() const 9 | { 10 | return m_intProperty; 11 | } 12 | 13 | void Child::setIntProperty(int intProperty) 14 | { 15 | m_intProperty = intProperty; 16 | } 17 | -------------------------------------------------------------------------------- /lib/QJsonSerializer.cpp: -------------------------------------------------------------------------------- 1 | #include "QJsonSerializer.h" 2 | 3 | QJsonSerializer::QJsonSerializer() 4 | : m_factory(&m_defaultFactory) 5 | { 6 | 7 | } 8 | 9 | void QJsonSerializer::setObjectFactory(const IObjectFactory *factory) 10 | { 11 | m_factory = factory; 12 | } 13 | -------------------------------------------------------------------------------- /lib/ISerializable.h: -------------------------------------------------------------------------------- 1 | #ifndef ISERIALIZABLE_H 2 | #define ISERIALIZABLE_H 3 | 4 | #include 5 | 6 | class SerializerBase; 7 | 8 | class ISerializable 9 | { 10 | public: 11 | virtual QJsonValue serialize(const SerializerBase &serializer) const = 0; 12 | }; 13 | 14 | #endif // ISERIALIZABLE_H 15 | -------------------------------------------------------------------------------- /tests/GadgetChild.cpp: -------------------------------------------------------------------------------- 1 | #include "GadgetChild.h" 2 | 3 | GadgetChild::GadgetChild() 4 | : m_intProperty(0) 5 | { 6 | } 7 | 8 | int GadgetChild::intProperty() const 9 | { 10 | return m_intProperty; 11 | } 12 | 13 | void GadgetChild::setIntProperty(int intProperty) 14 | { 15 | m_intProperty = intProperty; 16 | } 17 | -------------------------------------------------------------------------------- /lib/Dictionary.cpp: -------------------------------------------------------------------------------- 1 | #include "Dictionary.h" 2 | #include "SerializerBase.h" 3 | 4 | QJsonValue IDictionary::serialize(const SerializerBase &serializer) const 5 | { 6 | auto elements = toVariantMap(); 7 | 8 | QJsonObject target; 9 | 10 | for (const auto &element : elements) 11 | { 12 | auto key = elements.key(element); 13 | auto object = *reinterpret_cast(element.constData()); 14 | 15 | target[key] = serializer.serializeObject(object, metaObject()); 16 | } 17 | 18 | return target; 19 | } 20 | -------------------------------------------------------------------------------- /lib/SerializerBase.h: -------------------------------------------------------------------------------- 1 | #ifndef SERIALIZERBASE_H 2 | #define SERIALIZERBASE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class IArray; 10 | class IDictionary; 11 | 12 | class SerializerBase 13 | { 14 | friend class IArray; 15 | friend class IDictionary; 16 | 17 | protected: 18 | QJsonArray serializeArray(const IArray &source) const; 19 | QJsonObject serializeObject(const void *source, const QMetaObject *metaObject) const; 20 | }; 21 | 22 | #endif // SERIALIZERBASE_H 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | /.qmake.cache 16 | /.qmake.stash 17 | *.pro.user 18 | *.pro.user.* 19 | *.qbs.user 20 | *.qbs.user.* 21 | *.moc 22 | moc_*.cpp 23 | moc_*.h 24 | qrc_*.cpp 25 | ui_*.h 26 | Makefile* 27 | *build-* 28 | 29 | # QtCreator 30 | 31 | *.autosave 32 | 33 | #QtCtreator Qml 34 | *.qmlproject.user 35 | *.qmlproject.user.* 36 | 37 | # Build output 38 | 39 | lib/libQJsonSerializer* 40 | tests/SerializerTests 41 | 42 | # Android 43 | 44 | *android* 45 | -------------------------------------------------------------------------------- /tests/GadgetChild.h: -------------------------------------------------------------------------------- 1 | #ifndef GADGETCHILD_H 2 | #define GADGETCHILD_H 3 | 4 | #include 5 | 6 | #include "Array.h" 7 | 8 | class GadgetChild 9 | { 10 | Q_GADGET 11 | 12 | Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty) 13 | 14 | public: 15 | Q_INVOKABLE GadgetChild(); 16 | 17 | int intProperty() const; 18 | void setIntProperty(int intProperty); 19 | 20 | private: 21 | int m_intProperty; 22 | }; 23 | 24 | Q_DECLARE_METATYPE(GadgetChild *) 25 | Q_DECLARE_METATYPE(GadgetChild) 26 | Q_DECLARE_METATYPE(Array) 27 | 28 | #endif // GADGETCHILD_H 29 | -------------------------------------------------------------------------------- /tests/Child.h: -------------------------------------------------------------------------------- 1 | #ifndef CHILD_H 2 | #define CHILD_H 3 | 4 | #include 5 | 6 | #include "Array.h" 7 | #include "Dictionary.h" 8 | 9 | class Child : public QObject 10 | { 11 | Q_OBJECT 12 | 13 | Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty) 14 | 15 | public: 16 | Q_INVOKABLE Child(); 17 | 18 | int intProperty() const; 19 | void setIntProperty(int intProperty); 20 | 21 | private: 22 | int m_intProperty; 23 | }; 24 | 25 | Q_DECLARE_METATYPE(Child *) 26 | Q_DECLARE_METATYPE(Array) 27 | Q_DECLARE_METATYPE(Dictionary) 28 | 29 | #endif // CHILD_H 30 | -------------------------------------------------------------------------------- /lib/DeserializerBase.h: -------------------------------------------------------------------------------- 1 | #ifndef DESERIALIZERBASE_H 2 | #define DESERIALIZERBASE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class IArray; 10 | class IObjectFactory; 11 | class IDictionary; 12 | 13 | class DeserializerBase 14 | { 15 | protected: 16 | DeserializerBase(const IObjectFactory &factory); 17 | 18 | void deserializeDictionary(const QJsonObject &object, IDictionary &target) const; 19 | void deserializeArray(const QJsonArray &array, IArray &target) const; 20 | void deserializeObject(const QJsonObject &object, void *instance, const QMetaObject *metaObject) const; 21 | 22 | const IObjectFactory &m_factory; 23 | }; 24 | 25 | #endif // DESERIALIZERBASE_H 26 | -------------------------------------------------------------------------------- /lib/lib.pro: -------------------------------------------------------------------------------- 1 | CONFIG += c++11 2 | TEMPLATE = lib 3 | TARGET = $$qtLibraryTarget(QJsonSerializer) 4 | DEFINES += QJSONSERIALIZER_LIBRARY 5 | VER_MAJ = 1 6 | 7 | HEADERS += \ 8 | Array.h \ 9 | DeserializerBase.h \ 10 | Dictionary.h \ 11 | IDeserializer.h \ 12 | ISerializable.h \ 13 | Library.h \ 14 | QJsonSerializer \ 15 | QJsonSerializer.h \ 16 | SerializerBase.h \ 17 | ISerializer.h \ 18 | IObjectFactory.h 19 | 20 | SOURCES += \ 21 | Array.cpp \ 22 | DeserializerBase.cpp \ 23 | Dictionary.cpp \ 24 | SerializerBase.cpp \ 25 | QJsonSerializer.cpp 26 | 27 | headers.files = $${HEADERS} 28 | headers.path = $$[QT_INSTALL_HEADERS]/QJsonSerializer 29 | 30 | target.path = $$[QT_INSTALL_LIBS] 31 | 32 | features.files = jsonserializer.prf 33 | features.path = $$[QMAKE_MKSPECS]/features 34 | 35 | INSTALLS += headers target features 36 | -------------------------------------------------------------------------------- /tests/tests.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2016-02-20T10:15:33 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += testlib 8 | QT -= gui 9 | 10 | TARGET = SerializerTests 11 | CONFIG += console c++11 12 | CONFIG -= app_bundle 13 | 14 | TEMPLATE = app 15 | 16 | HEADERS += \ 17 | Entity.h \ 18 | Child.h \ 19 | GadgetEntity.h \ 20 | GadgetChild.h 21 | 22 | SOURCES += SerializerTests.cpp \ 23 | Entity.cpp \ 24 | Child.cpp \ 25 | GadgetEntity.cpp \ 26 | GadgetChild.cpp 27 | 28 | DEFINES += SRCDIR=\\\"$$PWD/\\\" 29 | 30 | win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../lib/release/ -lQJsonSerializer 31 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../lib/debug/ -lQJsonSerializer 32 | else:unix: LIBS += -L$$OUT_PWD/../lib/ -lQJsonSerializer 33 | 34 | INCLUDEPATH += $$PWD/../lib 35 | DEPENDPATH += $$PWD/../lib 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QJsonSerializer 2 | =============== 3 | 4 | Summary 5 | ------- 6 | A library for serializing and deserializing complex Qt object graphs to and from JSON 7 | 8 | Installation 9 | ----------- 10 | 11 | Linux: 12 | 13 | ``` 14 | qmake 15 | make 16 | sudo make install 17 | ``` 18 | 19 | Windows (MSVC): 20 | 21 | ``` 22 | qmake 23 | nmake 24 | nmake install 25 | ``` 26 | 27 | Windows (MinGW): 28 | 29 | ``` 30 | qmake 31 | mingw32-make 32 | mingw32-make install 33 | ``` 34 | 35 | Getting started 36 | ------------ 37 | 38 | ``` 39 | CONFIG += jsonserializer 40 | ``` 41 | 42 | ```C++ 43 | #include 44 | ``` 45 | 46 | See the test cases for code examples. 47 | 48 | What works 49 | ---------- 50 | 51 | * Serialization and deserialization of complex object graphs, including nested objects and collections 52 | 53 | What does not work 54 | ------------------ 55 | 56 | * Serialization and deserialization of polymorphic objects is currently untested. 57 | -------------------------------------------------------------------------------- /lib/ISerializer.h: -------------------------------------------------------------------------------- 1 | #ifndef ISERIALIZER_H 2 | #define ISERIALIZER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "Array.h" 8 | #include "SerializerBase.h" 9 | #include "Library.h" 10 | 11 | template 12 | class ISerializer 13 | { 14 | public: 15 | virtual QByteArray serialize(const TSource &source) const = 0; 16 | }; 17 | 18 | template 19 | class QJSONSERIALIZER_EXPORT Serializer 20 | : public SerializerBase 21 | , public ISerializer 22 | { 23 | public: 24 | QByteArray serialize(const TSource &source) const override 25 | { 26 | Q_UNUSED(source); 27 | 28 | return QByteArray(); 29 | } 30 | }; 31 | 32 | template 33 | class QJSONSERIALIZER_EXPORT Serializer 34 | : public SerializerBase 35 | , public ISerializer 36 | { 37 | public: 38 | QByteArray serialize(TSource *const &source) const override 39 | { 40 | const QMetaObject &metaObject = TSource::staticMetaObject; 41 | const QJsonObject &object = serializeObject(source, &metaObject); 42 | 43 | QJsonDocument document; 44 | document.setObject(object); 45 | 46 | return document.toJson(QJsonDocument::Compact); 47 | } 48 | }; 49 | 50 | template 51 | class QJSONSERIALIZER_EXPORT Serializer> 52 | : public SerializerBase 53 | , public ISerializer> 54 | { 55 | public: 56 | QByteArray serialize(const Array &source) const override 57 | { 58 | const QJsonArray &array = serializeArray(source); 59 | 60 | QJsonDocument document; 61 | document.setArray(array); 62 | 63 | return document.toJson(QJsonDocument::Compact); 64 | } 65 | }; 66 | 67 | #endif // ISERIALIZER_H 68 | -------------------------------------------------------------------------------- /tests/GadgetEntity.cpp: -------------------------------------------------------------------------------- 1 | #include "GadgetEntity.h" 2 | 3 | GadgetEntity::GadgetEntity() 4 | : m_child(nullptr) 5 | , m_intProperty(0) 6 | , m_floatProperty(0) 7 | { 8 | } 9 | 10 | GadgetChild *GadgetEntity::child() const 11 | { 12 | return m_child; 13 | } 14 | 15 | void GadgetEntity::setChild(GadgetChild *child) 16 | { 17 | m_child = child; 18 | } 19 | 20 | Array GadgetEntity::children() const 21 | { 22 | return m_children; 23 | } 24 | 25 | void GadgetEntity::setChildren(const Array &children) 26 | { 27 | m_children = children; 28 | } 29 | 30 | QString GadgetEntity::stringProperty() const 31 | { 32 | return m_stringProperty; 33 | } 34 | 35 | void GadgetEntity::setStringProperty(const QString &property1) 36 | { 37 | m_stringProperty = property1; 38 | } 39 | 40 | QDateTime GadgetEntity::dateTimeProperty() const 41 | { 42 | return m_dateTimeProperty; 43 | } 44 | 45 | void GadgetEntity::setDateTimeProperty(const QDateTime &dateTimeProperty) 46 | { 47 | m_dateTimeProperty = dateTimeProperty; 48 | } 49 | 50 | Array GadgetEntity::intCollection() const 51 | { 52 | return m_intCollection; 53 | } 54 | 55 | void GadgetEntity::setIntCollection(const Array &intCollection) 56 | { 57 | m_intCollection = intCollection; 58 | } 59 | 60 | Array GadgetEntity::stringCollection() const 61 | { 62 | return m_stringCollection; 63 | } 64 | 65 | void GadgetEntity::setStringCollection(const Array &stringCollection) 66 | { 67 | m_stringCollection = stringCollection; 68 | } 69 | 70 | int GadgetEntity::intProperty() const 71 | { 72 | return m_intProperty; 73 | } 74 | 75 | void GadgetEntity::setIntProperty(int intProperty) 76 | { 77 | m_intProperty = intProperty; 78 | } 79 | 80 | float GadgetEntity::floatProperty() const 81 | { 82 | return m_floatProperty; 83 | } 84 | 85 | void GadgetEntity::setFloatProperty(float floatProperty) 86 | { 87 | m_floatProperty = floatProperty; 88 | } 89 | -------------------------------------------------------------------------------- /lib/SerializerBase.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "SerializerBase.h" 4 | #include "Array.h" 5 | 6 | QJsonArray SerializerBase::serializeArray(const IArray &source) const 7 | { 8 | const QVariantList &elements = source.toVariantList(); 9 | const QMetaObject *metaObject = source.metaObject(); 10 | 11 | if (source.isScalar()) 12 | { 13 | return QJsonArray::fromVariantList(elements); 14 | } 15 | 16 | QJsonArray array; 17 | 18 | for (const QVariant &element : elements) 19 | { 20 | const void *object = *reinterpret_cast(element.constData()); 21 | 22 | array.append(serializeObject(object, metaObject)); 23 | } 24 | 25 | return array; 26 | } 27 | 28 | QJsonObject SerializerBase::serializeObject(const void *source, const QMetaObject *metaObject) const 29 | { 30 | QJsonObject target; 31 | 32 | for (int i = metaObject->propertyOffset() 33 | ; i < metaObject->propertyCount() 34 | ; i++) 35 | { 36 | const QMetaProperty &property = metaObject->property(i); 37 | const QByteArray &name = property.name(); 38 | 39 | const QVariant &value = property.readOnGadget(source); 40 | const QVariant::Type type = value.type(); 41 | 42 | if (type == QVariant::UserType) 43 | { 44 | const int userType = property.userType(); 45 | const int flags = QMetaType::typeFlags(userType); 46 | 47 | if (flags & QMetaType::PointerToQObject || flags & QMetaType::PointerToGadget) 48 | { 49 | const void *object = *reinterpret_cast(value.constData()); 50 | 51 | if (object) 52 | { 53 | const QMetaObject *childMetaObject = QMetaType::metaObjectForType(userType); 54 | 55 | target[name] = serializeObject(object, childMetaObject); 56 | } 57 | } 58 | else 59 | { 60 | const ISerializable *serializable = (ISerializable *)value.data(); 61 | 62 | target[name] = serializable->serialize(*this); 63 | } 64 | } 65 | else 66 | { 67 | target[name] = QJsonValue::fromVariant(value); 68 | } 69 | } 70 | 71 | return target; 72 | } 73 | -------------------------------------------------------------------------------- /lib/QJsonSerializer.h: -------------------------------------------------------------------------------- 1 | #ifndef QJSONSERIALIZER_H 2 | #define QJSONSERIALIZER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Array.h" 14 | #include "IDeserializer.h" 15 | #include "IObjectFactory.h" 16 | #include "ISerializer.h" 17 | #include "Library.h" 18 | 19 | class QJSONSERIALIZER_EXPORT QJsonSerializer 20 | { 21 | public: 22 | QJsonSerializer(); 23 | 24 | void setObjectFactory(const IObjectFactory *factory); 25 | 26 | template 27 | TReturn deserialize(const QByteArray &data) const 28 | { 29 | Deserializer subject(*m_factory); 30 | 31 | return subject.deserialize(data); 32 | } 33 | 34 | template 35 | void deserialize(const QJsonObject &object, TReturn target) const 36 | { 37 | Deserializer subject(*m_factory); 38 | 39 | subject.deserialize(object, target); 40 | } 41 | 42 | template 43 | void deserialize(const QByteArray &data, TReturn target) const 44 | { 45 | Deserializer subject(*m_factory); 46 | 47 | subject.deserialize(data, target); 48 | } 49 | 50 | template 51 | TReturn deserialize(QIODevice *device) const 52 | { 53 | const QByteArray &data = device->readAll(); 54 | 55 | return deserialize(data); 56 | } 57 | 58 | template 59 | void deserialize(QIODevice *device, TReturn target) const 60 | { 61 | const QByteArray &data = device->readAll(); 62 | 63 | deserialize(data, target); 64 | } 65 | 66 | template 67 | QByteArray serialize(const TSource &source) const 68 | { 69 | Serializer subject; 70 | 71 | return subject.serialize(source); 72 | } 73 | 74 | private: 75 | const DefaultObjectFactory m_defaultFactory; 76 | const IObjectFactory *m_factory; 77 | }; 78 | 79 | #endif // QJSONSERIALIZER_H 80 | -------------------------------------------------------------------------------- /tests/GadgetEntity.h: -------------------------------------------------------------------------------- 1 | #ifndef GADGETENTITY_H 2 | #define GADGETENTITY_H 3 | 4 | #include 5 | #include 6 | 7 | #include "GadgetChild.h" 8 | 9 | class GadgetEntity 10 | { 11 | Q_GADGET 12 | 13 | Q_PROPERTY(GadgetChild *child READ child WRITE setChild) 14 | Q_PROPERTY(Array children READ children WRITE setChildren) 15 | 16 | Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) 17 | Q_PROPERTY(QDateTime dateTimeProperty READ dateTimeProperty WRITE setDateTimeProperty) 18 | Q_PROPERTY(Array intCollection READ intCollection WRITE setIntCollection) 19 | Q_PROPERTY(Array stringCollection READ stringCollection WRITE setStringCollection) 20 | 21 | Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty) 22 | Q_PROPERTY(float floatProperty READ floatProperty WRITE setFloatProperty) 23 | 24 | public: 25 | Q_INVOKABLE GadgetEntity(); 26 | 27 | GadgetChild *child() const; 28 | void setChild(GadgetChild *child); 29 | 30 | Array children() const; 31 | void setChildren(const Array &children); 32 | 33 | QString stringProperty() const; 34 | void setStringProperty(const QString &stringProperty); 35 | 36 | QDateTime dateTimeProperty() const; 37 | void setDateTimeProperty(const QDateTime &dateTimeProperty); 38 | 39 | Array intCollection() const; 40 | void setIntCollection(const Array &intCollection); 41 | 42 | Array stringCollection() const; 43 | void setStringCollection(const Array &stringCollection); 44 | 45 | int intProperty() const; 46 | void setIntProperty(int intProperty); 47 | 48 | float floatProperty() const; 49 | void setFloatProperty(float floatProperty); 50 | 51 | private: 52 | GadgetChild *m_child; 53 | Array m_children; 54 | 55 | QString m_stringProperty; 56 | QDateTime m_dateTimeProperty; 57 | Array m_intCollection; 58 | Array m_stringCollection; 59 | 60 | int m_intProperty; 61 | float m_floatProperty; 62 | }; 63 | 64 | #endif // GADGETENTITY_H 65 | -------------------------------------------------------------------------------- /lib/IObjectFactory.h: -------------------------------------------------------------------------------- 1 | #ifndef IOBJECTFACTORY_H 2 | #define IOBJECTFACTORY_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class IObjectFactory 9 | { 10 | public: 11 | virtual void *create(const QMetaObject *metaObject) const = 0; 12 | 13 | template 14 | T *create() const 15 | { 16 | return (T* )create(&T::staticMetaObject); 17 | } 18 | }; 19 | 20 | class DefaultObjectFactory : public IObjectFactory 21 | { 22 | public: 23 | DefaultObjectFactory() 24 | { 25 | 26 | } 27 | 28 | void *create(const QMetaObject *metaObject) const override 29 | { 30 | auto child = newInstance(metaObject); 31 | 32 | if (!child) 33 | { 34 | qCritical() << "Failed to create an instance of type" << metaObject->className(); 35 | qCritical() << "Did you forget to declare a public parameterless Q_INVOKABLE constructor?"; 36 | } 37 | 38 | return child; 39 | } 40 | 41 | private: 42 | // Works around QTBUG-76663 43 | void *newInstance(const QMetaObject *mo) const 44 | { 45 | QByteArray constructorName = mo->className(); 46 | 47 | { 48 | int idx = constructorName.lastIndexOf(':'); 49 | 50 | if (idx != -1) 51 | { 52 | constructorName.remove(0, idx + 1); // remove qualified part 53 | } 54 | } 55 | 56 | QVarLengthArray sig; 57 | sig.append(constructorName.constData(), constructorName.length()); 58 | sig.append('('); 59 | sig.append(')'); 60 | sig.append('\0'); 61 | 62 | int idx = mo->indexOfConstructor(sig.constData()); 63 | 64 | if (idx < 0) 65 | { 66 | QByteArray norm = QMetaObject::normalizedSignature(sig.constData()); 67 | idx = mo->indexOfConstructor(norm.constData()); 68 | } 69 | 70 | if (idx < 0) 71 | { 72 | return 0; 73 | } 74 | 75 | void *returnValue = 0; 76 | void *param[] = { &returnValue }; 77 | 78 | if (mo->static_metacall(QMetaObject::CreateInstance, idx, param) >= 0) 79 | { 80 | return 0; 81 | } 82 | 83 | return returnValue; 84 | } 85 | }; 86 | 87 | #endif // IOBJECTFACTORY_H 88 | -------------------------------------------------------------------------------- /tests/Entity.cpp: -------------------------------------------------------------------------------- 1 | #include "Entity.h" 2 | 3 | Entity::Entity() 4 | : m_child(nullptr) 5 | , m_intProperty(0) 6 | , m_floatProperty(0) 7 | { 8 | } 9 | 10 | Child *Entity::child() const 11 | { 12 | return m_child; 13 | } 14 | 15 | void Entity::setChild(Child *child) 16 | { 17 | m_child = child; 18 | } 19 | 20 | Array Entity::children() const 21 | { 22 | return m_children; 23 | } 24 | 25 | void Entity::setChildren(const Array &children) 26 | { 27 | m_children = children; 28 | } 29 | 30 | QString Entity::stringProperty() const 31 | { 32 | return m_stringProperty; 33 | } 34 | 35 | void Entity::setStringProperty(const QString &property1) 36 | { 37 | m_stringProperty = property1; 38 | } 39 | 40 | QDateTime Entity::dateTimeProperty() const 41 | { 42 | return m_dateTimeProperty; 43 | } 44 | 45 | void Entity::setDateTimeProperty(const QDateTime &dateTimeProperty) 46 | { 47 | m_dateTimeProperty = dateTimeProperty; 48 | } 49 | 50 | QVariant Entity::variantProperty() const 51 | { 52 | return m_variantProperty; 53 | } 54 | 55 | void Entity::setVariantProperty(const QVariant &variantProperty) 56 | { 57 | m_variantProperty = variantProperty; 58 | } 59 | 60 | Array Entity::intCollection() const 61 | { 62 | return m_intCollection; 63 | } 64 | 65 | void Entity::setIntCollection(const Array &intCollection) 66 | { 67 | m_intCollection = intCollection; 68 | } 69 | 70 | Array Entity::stringCollection() const 71 | { 72 | return m_stringCollection; 73 | } 74 | 75 | void Entity::setStringCollection(const Array &stringCollection) 76 | { 77 | m_stringCollection = stringCollection; 78 | } 79 | 80 | Dictionary Entity::dictionary() const 81 | { 82 | return m_dictionary; 83 | } 84 | 85 | void Entity::setDictionary(const Dictionary &dictionary) 86 | { 87 | m_dictionary = dictionary; 88 | } 89 | 90 | int Entity::intProperty() const 91 | { 92 | return m_intProperty; 93 | } 94 | 95 | void Entity::setIntProperty(int intProperty) 96 | { 97 | m_intProperty = intProperty; 98 | } 99 | 100 | float Entity::floatProperty() const 101 | { 102 | return m_floatProperty; 103 | } 104 | 105 | void Entity::setFloatProperty(float floatProperty) 106 | { 107 | m_floatProperty = floatProperty; 108 | } 109 | -------------------------------------------------------------------------------- /tests/Entity.h: -------------------------------------------------------------------------------- 1 | #ifndef ENTITY_H 2 | #define ENTITY_H 3 | 4 | #include 5 | #include 6 | 7 | #include "Child.h" 8 | 9 | class Entity : public QObject 10 | { 11 | Q_OBJECT 12 | 13 | Q_PROPERTY(Child *child READ child WRITE setChild) 14 | Q_PROPERTY(Array children READ children WRITE setChildren) 15 | 16 | Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) 17 | Q_PROPERTY(QDateTime dateTimeProperty READ dateTimeProperty WRITE setDateTimeProperty) 18 | Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty) 19 | Q_PROPERTY(Array intCollection READ intCollection WRITE setIntCollection) 20 | Q_PROPERTY(Array stringCollection READ stringCollection WRITE setStringCollection) 21 | Q_PROPERTY(Dictionary dictionary READ dictionary WRITE setDictionary) 22 | 23 | Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty) 24 | Q_PROPERTY(float floatProperty READ floatProperty WRITE setFloatProperty) 25 | 26 | public: 27 | Q_INVOKABLE Entity(); 28 | 29 | Child *child() const; 30 | void setChild(Child *child); 31 | 32 | Array children() const; 33 | void setChildren(const Array &children); 34 | 35 | QString stringProperty() const; 36 | void setStringProperty(const QString &stringProperty); 37 | 38 | QDateTime dateTimeProperty() const; 39 | void setDateTimeProperty(const QDateTime &dateTimeProperty); 40 | 41 | QVariant variantProperty() const; 42 | void setVariantProperty(const QVariant &variantProperty); 43 | 44 | Array intCollection() const; 45 | void setIntCollection(const Array &intCollection); 46 | 47 | Array stringCollection() const; 48 | void setStringCollection(const Array &stringCollection); 49 | 50 | Dictionary dictionary() const; 51 | void setDictionary(const Dictionary &dictionary); 52 | 53 | int intProperty() const; 54 | void setIntProperty(int intProperty); 55 | 56 | float floatProperty() const; 57 | void setFloatProperty(float floatProperty); 58 | 59 | private: 60 | Child *m_child; 61 | Array m_children; 62 | 63 | QString m_stringProperty; 64 | QDateTime m_dateTimeProperty; 65 | QVariant m_variantProperty; 66 | Array m_intCollection; 67 | Array m_stringCollection; 68 | Dictionary m_dictionary; 69 | 70 | int m_intProperty; 71 | float m_floatProperty; 72 | }; 73 | 74 | Q_DECLARE_METATYPE(Entity *) 75 | 76 | #endif // ENTITY_H 77 | -------------------------------------------------------------------------------- /lib/Array.h: -------------------------------------------------------------------------------- 1 | #ifndef ARRAY_H 2 | #define ARRAY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "IObjectFactory.h" 10 | #include "ISerializable.h" 11 | 12 | class IArray : public ISerializable 13 | { 14 | public: 15 | QJsonValue serialize(const SerializerBase &serializer) const override; 16 | 17 | virtual bool isScalar() const = 0; 18 | 19 | virtual const QMetaObject *metaObject() const = 0; 20 | 21 | virtual void *createElement(const IObjectFactory &factory) = 0; 22 | virtual QVariantList toVariantList() const = 0; 23 | 24 | virtual void addElement(const QVariant &variant) = 0; 25 | virtual void initialize() = 0; 26 | }; 27 | 28 | template 29 | class Array 30 | : public QList 31 | , public IArray 32 | { 33 | public: 34 | Q_INVOKABLE Array() 35 | : m_pointer(this) 36 | { 37 | 38 | } 39 | 40 | bool isScalar() const override 41 | { 42 | return true; 43 | } 44 | 45 | const QMetaObject *metaObject() const override 46 | { 47 | return nullptr; 48 | } 49 | 50 | void *createElement(const IObjectFactory &factory) override 51 | { 52 | Q_UNUSED(factory); 53 | 54 | return nullptr; 55 | } 56 | 57 | QVariantList toVariantList() const override 58 | { 59 | QVariantList list; 60 | 61 | for (const T &element : *m_pointer) 62 | { 63 | list << QVariant::fromValue(element); 64 | } 65 | 66 | return list; 67 | } 68 | 69 | void addElement(const QVariant &variant) override 70 | { 71 | *m_pointer << variant.value(); 72 | } 73 | 74 | void initialize() override 75 | { 76 | m_pointer->clear(); 77 | } 78 | 79 | private: 80 | Array *m_pointer; 81 | }; 82 | 83 | Q_DECLARE_METATYPE(Array) 84 | Q_DECLARE_METATYPE(Array) 85 | Q_DECLARE_METATYPE(Array) 86 | Q_DECLARE_METATYPE(Array) 87 | Q_DECLARE_METATYPE(Array) 88 | 89 | template 90 | class Array 91 | : public QList 92 | , public IArray 93 | { 94 | public: 95 | Q_INVOKABLE Array() 96 | : m_pointer(this) 97 | { 98 | 99 | } 100 | 101 | bool isScalar() const override 102 | { 103 | return false; 104 | } 105 | 106 | const QMetaObject *metaObject() const override 107 | { 108 | return &T::staticMetaObject; 109 | } 110 | 111 | void *createElement(const IObjectFactory &factory) override 112 | { 113 | T *element = factory.create(); 114 | 115 | m_pointer->append(element); 116 | 117 | return element; 118 | } 119 | 120 | QVariantList toVariantList() const override 121 | { 122 | QVariantList list; 123 | 124 | for (T *element : *m_pointer) 125 | { 126 | list << QVariant::fromValue(element); 127 | } 128 | 129 | return list; 130 | } 131 | 132 | void addElement(const QVariant &variant) override 133 | { 134 | Q_UNUSED(variant); 135 | } 136 | 137 | void initialize() override 138 | { 139 | m_pointer->clear(); 140 | } 141 | 142 | private: 143 | Array *m_pointer; 144 | }; 145 | 146 | #endif // ARRAY_H 147 | -------------------------------------------------------------------------------- /lib/Dictionary.h: -------------------------------------------------------------------------------- 1 | #ifndef DICTIONARY_H 2 | #define DICTIONARY_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "IObjectFactory.h" 9 | #include "ISerializable.h" 10 | 11 | class IDictionary : public ISerializable 12 | { 13 | public: 14 | QJsonValue serialize(const SerializerBase &serializer) const override; 15 | 16 | virtual bool isScalar() const = 0; 17 | 18 | virtual const QMetaObject *metaObject() const = 0; 19 | 20 | virtual void *createElement(const QString &key, const IObjectFactory &factory) = 0; 21 | 22 | virtual QVariantMap toVariantMap() const = 0; 23 | 24 | virtual void addElement(const QString &key, const QVariant &variant) = 0; 25 | virtual void initialize() = 0; 26 | }; 27 | 28 | template 29 | class Dictionary 30 | : public QHash 31 | , public IDictionary 32 | { 33 | public: 34 | Q_INVOKABLE Dictionary() 35 | : m_pointer(this) 36 | { 37 | } 38 | 39 | const QMetaObject *metaObject() const override 40 | { 41 | return nullptr; 42 | } 43 | 44 | void *createElement(const QString &key, const IObjectFactory &factory) override 45 | { 46 | Q_UNUSED(key); 47 | Q_UNUSED(factory); 48 | 49 | return nullptr; 50 | } 51 | 52 | QVariantMap toVariantMap() const override 53 | { 54 | QVariantMap map; 55 | 56 | for (const T &value : *m_pointer) 57 | { 58 | auto key = m_pointer->key(value); 59 | 60 | map[key] = QVariant::fromValue(value); 61 | } 62 | 63 | return map; 64 | } 65 | 66 | void addElement(const QString &key, const QVariant &variant) override 67 | { 68 | auto value = variant.value(); 69 | 70 | m_pointer->insert(key, value); 71 | } 72 | 73 | void initialize() override 74 | { 75 | m_pointer->clear(); 76 | } 77 | 78 | private: 79 | Dictionary *m_pointer; 80 | }; 81 | 82 | template 83 | class Dictionary 84 | : public QHash 85 | , public IDictionary 86 | { 87 | public: 88 | Q_INVOKABLE Dictionary() 89 | : m_pointer(this) 90 | { 91 | 92 | } 93 | 94 | bool isScalar() const override 95 | { 96 | return false; 97 | } 98 | 99 | const QMetaObject *metaObject() const override 100 | { 101 | return &T::staticMetaObject; 102 | } 103 | 104 | void *createElement(const QString &key, const IObjectFactory &factory) override 105 | { 106 | T *element = factory.create(); 107 | 108 | m_pointer->insert(key, element); 109 | 110 | return element; 111 | } 112 | 113 | QVariantMap toVariantMap() const override 114 | { 115 | QVariantMap map; 116 | 117 | for (T *value : *m_pointer) 118 | { 119 | auto key = m_pointer->key(value); 120 | 121 | map[key] = QVariant::fromValue(value); 122 | } 123 | 124 | return map; 125 | } 126 | 127 | void addElement(const QString &key, const QVariant &variant) override 128 | { 129 | Q_UNUSED(key); 130 | Q_UNUSED(variant); 131 | } 132 | 133 | void initialize() override 134 | { 135 | m_pointer->clear(); 136 | } 137 | 138 | private: 139 | Dictionary *m_pointer; 140 | }; 141 | 142 | #endif // DICTIONARY_H 143 | -------------------------------------------------------------------------------- /lib/IDeserializer.h: -------------------------------------------------------------------------------- 1 | #ifndef IDESERIALIZER_H 2 | #define IDESERIALIZER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "Array.h" 8 | #include "DeserializerBase.h" 9 | #include "Library.h" 10 | 11 | template 12 | class QJSONSERIALIZER_EXPORT Deserializer : public DeserializerBase 13 | { 14 | public: 15 | Deserializer(const IObjectFactory &factory) 16 | : DeserializerBase(factory) 17 | { 18 | 19 | } 20 | 21 | TReturn deserialize(const QByteArray &data) const 22 | { 23 | TReturn value; 24 | 25 | deserialize(data, value); 26 | 27 | return value; 28 | } 29 | 30 | void deserialize(const QJsonObject &object, TReturn &target) const 31 | { 32 | Q_UNUSED(object); 33 | Q_UNUSED(target); 34 | } 35 | 36 | void deserialize(const QByteArray &data, TReturn &target) const 37 | { 38 | /* 39 | * QJsonDocument does not support documents with roots other than objects or arrays, 40 | * despite RFC 7159 and ECMA-404 stating that it should be allowed. 41 | * Therefore we have to construct a dummy object and deserialize it. 42 | */ 43 | 44 | QByteArray cloned = data; 45 | 46 | cloned.insert(0, "{ \"dummy\": "); 47 | cloned.append("}"); 48 | 49 | const QJsonDocument &document = QJsonDocument::fromJson(cloned); 50 | const QJsonObject &object = document.object(); 51 | 52 | const QVariant &variant = object 53 | .value("dummy") 54 | .toVariant(); 55 | 56 | target = variant.value(); 57 | } 58 | }; 59 | 60 | template 61 | class QJSONSERIALIZER_EXPORT Deserializer : public DeserializerBase 62 | { 63 | public: 64 | Deserializer(const IObjectFactory &factory) 65 | : DeserializerBase(factory) 66 | { 67 | 68 | } 69 | 70 | void deserialize(const QJsonObject &object, TReturn *target) const 71 | { 72 | deserializeObject(object, target, &TReturn::staticMetaObject); 73 | } 74 | 75 | TReturn *deserialize(const QByteArray &data) const 76 | { 77 | TReturn *instance = m_factory.create(); 78 | 79 | deserialize(data, instance); 80 | 81 | return instance; 82 | } 83 | 84 | void deserialize(const QByteArray &data, TReturn *target) const 85 | { 86 | const QJsonDocument &document = QJsonDocument::fromJson(data); 87 | const QJsonObject &root = document.object(); 88 | 89 | deserializeObject(root, target, &TReturn::staticMetaObject); 90 | } 91 | }; 92 | 93 | template 94 | class QJSONSERIALIZER_EXPORT Deserializer> : public DeserializerBase 95 | { 96 | public: 97 | Deserializer(const IObjectFactory &factory) 98 | : DeserializerBase(factory) 99 | { 100 | 101 | } 102 | 103 | void deserialize(const QJsonObject &object, Array &target) const 104 | { 105 | Q_UNUSED(object); 106 | Q_UNUSED(target); 107 | } 108 | 109 | Array deserialize(const QByteArray &data) const 110 | { 111 | Array array; 112 | 113 | deserialize(data, array); 114 | 115 | return array; 116 | } 117 | 118 | void deserialize(const QByteArray &data, Array &target) const 119 | { 120 | const QJsonDocument &document = QJsonDocument::fromJson(data); 121 | const QJsonArray &root = document.array(); 122 | 123 | deserializeArray(root, target); 124 | } 125 | }; 126 | 127 | #endif // IDESERIALIZER_H 128 | -------------------------------------------------------------------------------- /lib/DeserializerBase.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "IObjectFactory.h" 5 | #include "DeserializerBase.h" 6 | #include "Array.h" 7 | #include "Dictionary.h" 8 | 9 | DeserializerBase::DeserializerBase(const IObjectFactory &factory) 10 | : m_factory(factory) 11 | { 12 | 13 | } 14 | 15 | void DeserializerBase::deserializeDictionary(const QJsonObject &object, IDictionary &target) const 16 | { 17 | target.initialize(); 18 | 19 | for (const QString &key : object.keys()) 20 | { 21 | auto value = object[key]; 22 | 23 | if (target.isScalar()) 24 | { 25 | auto variant = value.toVariant(); 26 | 27 | target.addElement(key, variant); 28 | } 29 | else 30 | { 31 | void *child = target.createElement(key, m_factory); 32 | 33 | const QMetaObject *metaObject = target.metaObject(); 34 | const QJsonObject &elementObject = value.toObject(); 35 | 36 | deserializeObject(elementObject, child, metaObject); 37 | } 38 | } 39 | } 40 | 41 | void DeserializerBase::deserializeArray(const QJsonArray &array, IArray &target) const 42 | { 43 | target.initialize(); 44 | 45 | for (int j = 0; j < array.count(); j++) 46 | { 47 | const QJsonValue &element = array[j]; 48 | 49 | if (target.isScalar()) 50 | { 51 | const QVariant &variant = element.toVariant(); 52 | 53 | target.addElement(variant); 54 | } 55 | else 56 | { 57 | void *child = target.createElement(m_factory); 58 | 59 | const QMetaObject *metaObject = target.metaObject(); 60 | const QJsonObject &elementObject = element.toObject(); 61 | 62 | deserializeObject(elementObject, child, metaObject); 63 | } 64 | } 65 | } 66 | 67 | void DeserializerBase::deserializeObject(const QJsonObject &object, void *instance, const QMetaObject *metaObject) const 68 | { 69 | if (!instance) 70 | { 71 | return; 72 | } 73 | 74 | for (int i = metaObject->propertyOffset() 75 | ; i < metaObject->propertyCount() 76 | ; i++) 77 | { 78 | const QMetaProperty &property = metaObject->property(i); 79 | const QByteArray &name = property.name(); 80 | 81 | const QJsonValue &value = object.value(name); 82 | const QJsonValue::Type type = value.type(); 83 | 84 | switch (type) 85 | { 86 | case QJsonValue::Object: 87 | { 88 | const int userType = property.userType(); 89 | 90 | if (userType != QMetaType::UnknownType) 91 | { 92 | const QMetaType type(userType); 93 | const QMetaObject *childMetaObject = type.metaObject(); 94 | const QJsonObject &childObject = value.toObject(); 95 | 96 | if (childMetaObject) 97 | { 98 | void *child = m_factory.create(childMetaObject); 99 | 100 | #if QT_VERSION >= 0x060000 101 | const QVariant variant(type, &child); 102 | #else 103 | const QVariant variant(userType, &child); 104 | #endif 105 | 106 | deserializeObject(childObject, child, childMetaObject); 107 | 108 | property.writeOnGadget(instance, variant); 109 | } 110 | else 111 | { 112 | auto variant = property.readOnGadget(instance); 113 | auto &factory = *(IDictionary *)variant.data(); 114 | 115 | deserializeDictionary(childObject, factory); 116 | } 117 | } 118 | else 119 | { 120 | qCritical() << "Unknown user type for property" << name; 121 | } 122 | 123 | break; 124 | } 125 | 126 | case QJsonValue::Array: 127 | { 128 | const QVariant &variant = property.readOnGadget(instance); 129 | const QJsonArray &array = value.toArray(); 130 | 131 | IArray &factory = *(IArray *)variant.data(); 132 | 133 | deserializeArray(array, factory); 134 | 135 | break; 136 | } 137 | 138 | case QJsonValue::Undefined: 139 | { 140 | break; 141 | } 142 | 143 | default: 144 | { 145 | const QVariant &variant = value.toVariant(); 146 | 147 | property.writeOnGadget(instance, variant); 148 | 149 | break; 150 | } 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /tests/SerializerTests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "QJsonSerializer.h" 5 | #include "Entity.h" 6 | #include "Child.h" 7 | #include "GadgetEntity.h" 8 | 9 | class SerializerTests : public QObject 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | SerializerTests() 15 | { 16 | qRegisterMetaType(); 17 | qRegisterMetaType(); 18 | qRegisterMetaType(); 19 | qRegisterMetaType(); 20 | } 21 | 22 | private Q_SLOTS: 23 | void shouldBeAbleToDeserializeStringProperties() 24 | { 25 | const QByteArray json = R"({ "stringProperty": "foo" })"; 26 | 27 | const Entity *entity = m_serializer.deserialize(json); 28 | 29 | QVERIFY(entity->stringProperty() == "foo"); 30 | } 31 | 32 | void shouldBeAbleToDeserializeIntProperties() 33 | { 34 | const QByteArray json = R"({ "intProperty": 42 })"; 35 | 36 | const Entity *entity = m_serializer.deserialize(json); 37 | 38 | QVERIFY(entity->intProperty() == 42); 39 | } 40 | 41 | void shouldBeAbleToDeserializeFloatProperties() 42 | { 43 | const QByteArray json = R"({ "floatProperty": 42.5 })"; 44 | 45 | const Entity *entity = m_serializer.deserialize(json); 46 | 47 | QVERIFY(entity->floatProperty() == 42.5); 48 | } 49 | 50 | void shouldBeAbleToDeserializeDateTimeProperties() 51 | { 52 | const QByteArray json = R"({ "dateTimeProperty": "2016-02-20T13:37:00" })"; 53 | 54 | const Entity *entity = m_serializer.deserialize(json); 55 | 56 | QVERIFY(entity->dateTimeProperty() == QDateTime::fromString("2016-02-20 13:37", "yyyy-MM-dd hh:mm")); 57 | } 58 | 59 | void shouldBeAbleToDeserializeComplexProperties() 60 | { 61 | const QByteArray json = R"({ "child": { "intProperty": 6 }})"; 62 | 63 | const Entity *entity = m_serializer.deserialize(json); 64 | const Child *child = entity->child(); 65 | 66 | QVERIFY(child); 67 | QCOMPARE(child->intProperty(), 6); 68 | } 69 | 70 | void shouldBeAbleToDeserializeArrayProperties() 71 | { 72 | const QByteArray json = R"({ "children": [ { "intProperty": 1 }, { "intProperty": 2 } ]})"; 73 | 74 | const Entity *entity = m_serializer.deserialize(json); 75 | const Array &children = entity->children(); 76 | 77 | QVERIFY(children.count() == 2); 78 | QVERIFY(children[0]->intProperty() == 1); 79 | QVERIFY(children[1]->intProperty() == 2); 80 | } 81 | 82 | void shouldBeAbleToDeserializeArrayDocument() 83 | { 84 | const QByteArray json = R"([{ "intProperty": 1 }, { "intProperty": 2 }])"; 85 | 86 | const Array &entities = m_serializer.deserialize>(json); 87 | 88 | QVERIFY(entities.count() == 2); 89 | QVERIFY(entities[0]->intProperty() == 1); 90 | QVERIFY(entities[1]->intProperty() == 2); 91 | } 92 | 93 | void shouldBeAbleToDeserializeArrayOfIntProperties() 94 | { 95 | const QByteArray json = R"({ "intCollection": [1, 2, 3] })"; 96 | 97 | const Entity *entity = m_serializer.deserialize(json); 98 | const Array &intCollection = entity->intCollection(); 99 | 100 | QCOMPARE(intCollection.count(), 3); 101 | QCOMPARE(intCollection[0], 1); 102 | QCOMPARE(intCollection[1], 2); 103 | QCOMPARE(intCollection[2], 3); 104 | } 105 | 106 | void shouldBeAbleToDeserializeArrayOfStringProperties() 107 | { 108 | const QByteArray json = R"({ "stringCollection": ["hi", "hello", "good bye"] })"; 109 | 110 | const Entity *entity = m_serializer.deserialize(json); 111 | const Array &intCollection = entity->stringCollection(); 112 | 113 | QCOMPARE(intCollection.count(), 3); 114 | QCOMPARE(intCollection[0], QStringLiteral("hi")); 115 | QCOMPARE(intCollection[1], QStringLiteral("hello")); 116 | QCOMPARE(intCollection[2], QStringLiteral("good bye")); 117 | } 118 | 119 | void shouldBeAbleToDeserializeOntoInstance() 120 | { 121 | const QByteArray json = R"({ "intProperty": 42 })"; 122 | 123 | Entity entity; 124 | 125 | m_serializer.deserialize(json, &entity); 126 | 127 | QCOMPARE(entity.intProperty(), 42); 128 | } 129 | 130 | void shouldBeAbleToSerializeStringProperties() 131 | { 132 | Entity entity; 133 | entity.setStringProperty("foo"); 134 | 135 | const QByteArray &json = m_serializer.serialize(&entity); 136 | const QByteArray expected(R"({"children":[],"dateTimeProperty":null,"dictionary":{},"floatProperty":0,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":"foo","variantProperty":null})"); 137 | 138 | QCOMPARE(json, expected); 139 | } 140 | 141 | void shouldBeAbleToSerializeIntProperties() 142 | { 143 | Entity entity; 144 | entity.setIntProperty(42); 145 | 146 | const QByteArray &json = m_serializer.serialize(&entity); 147 | const QByteArray expected(R"({"children":[],"dateTimeProperty":null,"dictionary":{},"floatProperty":0,"intCollection":[],"intProperty":42,"stringCollection":[],"stringProperty":"","variantProperty":null})"); 148 | 149 | QCOMPARE(json, expected); 150 | } 151 | 152 | void shouldBeAbleToSerializeFloatProperties() 153 | { 154 | Entity entity; 155 | entity.setFloatProperty(42.5); 156 | 157 | const QByteArray &json = m_serializer.serialize(&entity); 158 | const QByteArray expected(R"({"children":[],"dateTimeProperty":null,"dictionary":{},"floatProperty":42.5,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":"","variantProperty":null})"); 159 | 160 | QCOMPARE(json, expected); 161 | } 162 | 163 | void shouldBeAbleToSerializeDateTimeProperties() 164 | { 165 | Entity entity; 166 | entity.setDateTimeProperty(QDateTime::fromString("2016-02-20 13:37", "yyyy-MM-dd hh:mm")); 167 | 168 | const QByteArray &json = m_serializer.serialize(&entity); 169 | const QByteArray expected(R"({"children":[],"dateTimeProperty":"2016-02-20T13:37:00.000","dictionary":{},"floatProperty":0,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":"","variantProperty":null})"); 170 | 171 | QCOMPARE(json, expected); 172 | } 173 | 174 | void shouldBeAbleToSerializeComplexProperties() 175 | { 176 | Child child; 177 | child.setIntProperty(6); 178 | 179 | Entity entity; 180 | entity.setChild(&child); 181 | 182 | const QByteArray &json = m_serializer.serialize(&entity); 183 | const QByteArray expected(R"({"child":{"intProperty":6},"children":[],"dateTimeProperty":null,"dictionary":{},"floatProperty":0,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":"","variantProperty":null})"); 184 | 185 | QCOMPARE(json, expected); 186 | } 187 | 188 | void shouldBeAbleToSerializeArrayProperties() 189 | { 190 | Child child1; 191 | child1.setIntProperty(1); 192 | 193 | Child child2; 194 | child2.setIntProperty(2); 195 | 196 | Array array; 197 | array << &child1; 198 | array << &child2; 199 | 200 | Entity entity; 201 | entity.setChildren(array); 202 | 203 | const QByteArray &actual = m_serializer.serialize(&entity); 204 | const QByteArray expected(R"({"children":[{"intProperty":1},{"intProperty":2}],"dateTimeProperty":null,"dictionary":{},"floatProperty":0,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":"","variantProperty":null})"); 205 | 206 | QCOMPARE(actual, expected); 207 | } 208 | 209 | void shouldBeAbleToSerializeArrayDocument() 210 | { 211 | Child entity1; 212 | entity1.setIntProperty(1); 213 | 214 | Child entity2; 215 | entity2.setIntProperty(2); 216 | 217 | Array entities; 218 | entities << &entity1; 219 | entities << &entity2; 220 | 221 | const QByteArray &actual = m_serializer.serialize(entities); 222 | const QByteArray expected(R"([{"intProperty":1},{"intProperty":2}])"); 223 | 224 | QCOMPARE(actual, expected); 225 | } 226 | 227 | void shouldBeAbleToSerializeArrayOfIntProperties() 228 | { 229 | Array scalars; 230 | scalars << 1; 231 | scalars << 2; 232 | 233 | Entity entity; 234 | entity.setIntCollection(scalars); 235 | 236 | const QByteArray &actual = m_serializer.serialize(&entity); 237 | const QByteArray expected(R"({"children":[],"dateTimeProperty":null,"dictionary":{},"floatProperty":0,"intCollection":[1,2],"intProperty":0,"stringCollection":[],"stringProperty":"","variantProperty":null})"); 238 | 239 | QCOMPARE(actual, expected); 240 | } 241 | 242 | void shouldBeAbleToDeserializeArrayOfStringWithTarget() 243 | { 244 | Array target; 245 | 246 | const QByteArray json = R"([ "foo", "bar" ])"; 247 | 248 | m_serializer.deserialize(json, target); 249 | 250 | QCOMPARE(target[0], QStringLiteral("foo")); 251 | QCOMPARE(target[1], QStringLiteral("bar")); 252 | } 253 | 254 | void shouldBeAbleToDeserializePrimitiveDocuments() 255 | { 256 | const QByteArray json = R"("foo")"; 257 | const QString &target = m_serializer.deserialize(json); 258 | 259 | QCOMPARE(target, QStringLiteral("foo")); 260 | } 261 | 262 | void shouldBeAbleToDeserializeFromJSonObject() 263 | { 264 | QJsonObject child; 265 | child["intProperty"] = 22; 266 | 267 | QJsonArray children; 268 | children.append(child); 269 | 270 | QJsonObject object; 271 | object["floatProperty"] = 10.5f; 272 | object["intProperty"] = 2; 273 | object["children"] = children; 274 | 275 | Entity entity; 276 | 277 | m_serializer.deserialize(object, &entity); 278 | 279 | QCOMPARE(entity.floatProperty(), 10.5f); 280 | QCOMPARE(entity.intProperty(), 2); 281 | 282 | const Array &childArray = entity.children(); 283 | 284 | QCOMPARE(childArray.count(), 1); 285 | QCOMPARE(childArray[0]->intProperty(), 22); 286 | } 287 | 288 | void shouldBeAbleToDeserializeStringProperties_Gadget() 289 | { 290 | const QByteArray json = R"({ "stringProperty": "foo" })"; 291 | 292 | const GadgetEntity *entity = m_serializer.deserialize(json); 293 | 294 | QVERIFY(entity->stringProperty() == "foo"); 295 | } 296 | 297 | void shouldBeAbleToDeserializeIntProperties_Gadget() 298 | { 299 | const QByteArray json = R"({ "intProperty": 42 })"; 300 | 301 | const GadgetEntity *entity = m_serializer.deserialize(json); 302 | 303 | QVERIFY(entity->intProperty() == 42); 304 | } 305 | 306 | void shouldBeAbleToDeserializeFloatProperties_Gadget() 307 | { 308 | const QByteArray json = R"({ "floatProperty": 42.5 })"; 309 | 310 | const GadgetEntity *entity = m_serializer.deserialize(json); 311 | 312 | QVERIFY(entity->floatProperty() == 42.5); 313 | } 314 | 315 | void shouldBeAbleToDeserializeDateTimeProperties_Gadget() 316 | { 317 | const QByteArray json = R"({ "dateTimeProperty": "2016-02-20T13:37:00" })"; 318 | 319 | const GadgetEntity *entity = m_serializer.deserialize(json); 320 | 321 | QVERIFY(entity->dateTimeProperty() == QDateTime::fromString("2016-02-20 13:37", "yyyy-MM-dd hh:mm")); 322 | } 323 | 324 | void shouldBeAbleToDeserializeComplexProperties_Gadget() 325 | { 326 | const QByteArray json = R"({ "child": { "intProperty": 6 }})"; 327 | 328 | const GadgetEntity *entity = m_serializer.deserialize(json); 329 | const GadgetChild *child = entity->child(); 330 | 331 | QVERIFY(child); 332 | QVERIFY(child->intProperty() == 6); 333 | } 334 | 335 | void shouldBeAbleToDeserializeArrayProperties_Gadget() 336 | { 337 | const QByteArray json = R"({ "children": [ { "intProperty": 1 }, { "intProperty": 2 } ]})"; 338 | 339 | const GadgetEntity *entity = m_serializer.deserialize(json); 340 | const Array &children = entity->children(); 341 | 342 | QVERIFY(children.count() == 2); 343 | QVERIFY(children[0]->intProperty() == 1); 344 | QVERIFY(children[1]->intProperty() == 2); 345 | } 346 | 347 | void shouldBeAbleToDeserializeArrayDocument_Gadget() 348 | { 349 | const QByteArray json = R"([{ "intProperty": 1 }, { "intProperty": 2 }])"; 350 | 351 | const Array &entities = m_serializer.deserialize>(json); 352 | 353 | QVERIFY(entities.count() == 2); 354 | QVERIFY(entities[0]->intProperty() == 1); 355 | QVERIFY(entities[1]->intProperty() == 2); 356 | } 357 | 358 | void shouldBeAbleToDeserializeArrayOfIntProperties_Gadget() 359 | { 360 | const QByteArray json = R"({ "intCollection": [1, 2, 3] })"; 361 | 362 | const GadgetEntity *entity = m_serializer.deserialize(json); 363 | const Array &intCollection = entity->intCollection(); 364 | 365 | QCOMPARE(intCollection.count(), 3); 366 | QCOMPARE(intCollection[0], 1); 367 | QCOMPARE(intCollection[1], 2); 368 | QCOMPARE(intCollection[2], 3); 369 | } 370 | 371 | void shouldBeAbleToDeserializeArrayOfStringProperties_Gadget() 372 | { 373 | const QByteArray json = R"({ "stringCollection": ["hi", "hello", "good bye"] })"; 374 | 375 | const GadgetEntity *entity = m_serializer.deserialize(json); 376 | const Array &intCollection = entity->stringCollection(); 377 | 378 | QCOMPARE(intCollection.count(), 3); 379 | QCOMPARE(intCollection[0], QStringLiteral("hi")); 380 | QCOMPARE(intCollection[1], QStringLiteral("hello")); 381 | QCOMPARE(intCollection[2], QStringLiteral("good bye")); 382 | } 383 | 384 | void shouldBeAbleToDeserializeOntoInstance_Gadget() 385 | { 386 | const QByteArray json = R"({ "intProperty": 42 })"; 387 | 388 | GadgetEntity entity; 389 | 390 | m_serializer.deserialize(json, &entity); 391 | 392 | QCOMPARE(entity.intProperty(), 42); 393 | } 394 | 395 | void shouldBeAbleToSerializeStringProperties_Gadget() 396 | { 397 | GadgetEntity entity; 398 | entity.setStringProperty("foo"); 399 | 400 | const QByteArray &json = m_serializer.serialize(&entity); 401 | const QByteArray expected(R"({"children":[],"dateTimeProperty":null,"floatProperty":0,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":"foo"})"); 402 | 403 | QCOMPARE(json, expected); 404 | } 405 | 406 | void shouldBeAbleToSerializeIntProperties_Gadget() 407 | { 408 | GadgetEntity entity; 409 | entity.setIntProperty(42); 410 | 411 | const QByteArray &json = m_serializer.serialize(&entity); 412 | const QByteArray expected(R"({"children":[],"dateTimeProperty":null,"floatProperty":0,"intCollection":[],"intProperty":42,"stringCollection":[],"stringProperty":""})"); 413 | 414 | QCOMPARE(json, expected); 415 | } 416 | 417 | void shouldBeAbleToSerializeFloatProperties_Gadget() 418 | { 419 | GadgetEntity entity; 420 | entity.setFloatProperty(42.5); 421 | 422 | const QByteArray &json = m_serializer.serialize(&entity); 423 | const QByteArray expected(R"({"children":[],"dateTimeProperty":null,"floatProperty":42.5,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":""})"); 424 | 425 | QCOMPARE(json, expected); 426 | } 427 | 428 | void shouldBeAbleToSerializeDateTimeProperties_Gadget() 429 | { 430 | GadgetEntity entity; 431 | entity.setDateTimeProperty(QDateTime::fromString("2016-02-20 13:37", "yyyy-MM-dd hh:mm")); 432 | 433 | const QByteArray &json = m_serializer.serialize(&entity); 434 | const QByteArray expected(R"({"children":[],"dateTimeProperty":"2016-02-20T13:37:00.000","floatProperty":0,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":""})"); 435 | 436 | QCOMPARE(json, expected); 437 | } 438 | 439 | void shouldBeAbleToSerializeComplexProperties_Gadget() 440 | { 441 | GadgetChild child; 442 | child.setIntProperty(6); 443 | 444 | GadgetEntity entity; 445 | entity.setChild(&child); 446 | 447 | const QByteArray &json = m_serializer.serialize(&entity); 448 | const QByteArray expected(R"({"child":{"intProperty":6},"children":[],"dateTimeProperty":null,"floatProperty":0,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":""})"); 449 | 450 | QCOMPARE(json, expected); 451 | } 452 | 453 | void shouldBeAbleToSerializeArrayProperties_Gadget() 454 | { 455 | GadgetChild child1; 456 | child1.setIntProperty(1); 457 | 458 | GadgetChild child2; 459 | child2.setIntProperty(2); 460 | 461 | Array array; 462 | array << &child1; 463 | array << &child2; 464 | 465 | GadgetEntity entity; 466 | entity.setChildren(array); 467 | 468 | const QByteArray &actual = m_serializer.serialize(&entity); 469 | const QByteArray expected(R"({"children":[{"intProperty":1},{"intProperty":2}],"dateTimeProperty":null,"floatProperty":0,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":""})"); 470 | 471 | QCOMPARE(actual, expected); 472 | } 473 | 474 | void shouldBeAbleToSerializeArrayDocument_Gadget() 475 | { 476 | GadgetChild entity1; 477 | entity1.setIntProperty(1); 478 | 479 | GadgetChild entity2; 480 | entity2.setIntProperty(2); 481 | 482 | Array entities; 483 | entities << &entity1; 484 | entities << &entity2; 485 | 486 | const QByteArray &actual = m_serializer.serialize(entities); 487 | const QByteArray expected(R"([{"intProperty":1},{"intProperty":2}])"); 488 | 489 | QCOMPARE(actual, expected); 490 | } 491 | 492 | void shouldBeAbleToSerializeArrayOfIntProperties_Gadget() 493 | { 494 | Array scalars; 495 | scalars << 1; 496 | scalars << 2; 497 | 498 | GadgetEntity entity; 499 | entity.setIntCollection(scalars); 500 | 501 | const QByteArray &actual = m_serializer.serialize(&entity); 502 | const QByteArray expected(R"({"children":[],"dateTimeProperty":null,"floatProperty":0,"intCollection":[1,2],"intProperty":0,"stringCollection":[],"stringProperty":""})"); 503 | 504 | QCOMPARE(actual, expected); 505 | } 506 | 507 | void shouldBeAbleToDeserializeArrayOfStringWithTarget_Gadget() 508 | { 509 | Array target; 510 | 511 | const QByteArray json = R"([ "foo", "bar" ])"; 512 | 513 | m_serializer.deserialize(json, target); 514 | 515 | QCOMPARE(target[0], QStringLiteral("foo")); 516 | QCOMPARE(target[1], QStringLiteral("bar")); 517 | } 518 | 519 | void shouldBeAbleToDeserializePrimitiveDocuments_Gadget() 520 | { 521 | const QByteArray json = R"("foo")"; 522 | const QString &target = m_serializer.deserialize(json); 523 | 524 | QCOMPARE(target, QStringLiteral("foo")); 525 | } 526 | 527 | void shouldBeAbleToDeserializeFromJSonObject_Gadget() 528 | { 529 | QJsonObject child; 530 | child["intProperty"] = 22; 531 | 532 | QJsonArray children; 533 | children.append(child); 534 | 535 | QJsonObject object; 536 | object["floatProperty"] = 10.5f; 537 | object["intProperty"] = 2; 538 | object["children"] = children; 539 | 540 | GadgetEntity entity; 541 | 542 | m_serializer.deserialize(object, &entity); 543 | 544 | QCOMPARE(entity.floatProperty(), 10.5f); 545 | QCOMPARE(entity.intProperty(), 2); 546 | 547 | const Array &childArray = entity.children(); 548 | 549 | QCOMPARE(childArray.count(), 1); 550 | QCOMPARE(childArray[0]->intProperty(), 22); 551 | } 552 | 553 | void shouldBeAbleToDeserializeVariants() 554 | { 555 | const QByteArray json = R"([{ "variantProperty": "foo" }, { "variantProperty": 1.23 }])"; 556 | 557 | auto array = m_serializer.deserialize>(json); 558 | 559 | QCOMPARE(array.count(), 2); 560 | 561 | QCOMPARE("foo", array[0]->variantProperty().toString()); 562 | QCOMPARE(1.23f, array[1]->variantProperty().toFloat()); 563 | } 564 | 565 | void shouldClearTargetArrayWhenSerializingToTarget() 566 | { 567 | const QByteArray json = R"({"intCollection": [1, 2, 3]})"; 568 | 569 | Entity entity; 570 | 571 | m_serializer.deserialize(json, &entity); 572 | m_serializer.deserialize(json, &entity); 573 | 574 | QCOMPARE(entity.intCollection().count(), 3); 575 | } 576 | 577 | void canSerializeDictionaries() 578 | { 579 | Child child1; 580 | child1.setIntProperty(1); 581 | 582 | Child child2; 583 | child2.setIntProperty(2); 584 | 585 | Dictionary dictionary; 586 | dictionary["foo"] = &child1; 587 | dictionary["bar"] = &child2; 588 | 589 | Entity entity; 590 | entity.setDictionary(dictionary); 591 | 592 | const QByteArray &actual = m_serializer.serialize(&entity); 593 | const QByteArray expected(R"({"children":[],"dateTimeProperty":null,"dictionary":{"bar":{"intProperty":2},"foo":{"intProperty":1}},"floatProperty":0,"intCollection":[],"intProperty":0,"stringCollection":[],"stringProperty":"","variantProperty":null})"); 594 | 595 | QCOMPARE(actual, expected); 596 | } 597 | 598 | void canDeserializeDictionaries() 599 | { 600 | const QByteArray json = R"({"dictionary":{"bar":{"intProperty":2},"foo":{"intProperty":1}}})"; 601 | 602 | Entity entity; 603 | 604 | m_serializer.deserialize(json, &entity); 605 | 606 | auto dictionary = entity.dictionary(); 607 | 608 | QCOMPARE(2, dictionary.count()); 609 | 610 | auto child1 = dictionary["bar"]; 611 | auto child2 = dictionary["foo"]; 612 | 613 | QCOMPARE(2, child1->intProperty()); 614 | QCOMPARE(1, child2->intProperty()); 615 | } 616 | 617 | private: 618 | QJsonSerializer m_serializer; 619 | }; 620 | 621 | QTEST_APPLESS_MAIN(SerializerTests) 622 | 623 | #include "SerializerTests.moc" 624 | --------------------------------------------------------------------------------