/* Copyright (C) 2014 * swift project Community / Contributors * * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, * including this file, may be copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE file. */ //! \file #ifndef BLACKMISC_JSON_H #define BLACKMISC_JSON_H #include "blackmisc/blackmiscexport.h" #include "blackmisc/tuple.h" #include "blackmisc/inheritancetraits.h" #include "blackmisc/fileutils.h" #include #include #include #include #include #include #include #include #include #include /*! * \defgroup JSON Streaming operators for JSON */ //! \name Streaming operators for QJsonValue (to value) //! \ingroup JSON //! @{ BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, int &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, qlonglong &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, qulonglong &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, uint &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, qint16 &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, QString &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, QStringList &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, double &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, bool &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, QDateTime &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, QPixmap &value); BLACKMISC_EXPORT const QJsonValue &operator >>(const QJsonValue &json, QByteArray &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, int &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, qlonglong &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, qulonglong &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, uint &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, qint16 &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, QString &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, QStringList &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, double &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, bool &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, QDateTime &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, QPixmap &value); BLACKMISC_EXPORT const QJsonValueRef &operator >>(const QJsonValueRef &json, QByteArray &value); //! @} //! \brief Specialized JSON serialization for enum //! \remarks needs to be in global namespace //! \ingroup JSON template std::enable_if_t::value, QJsonObject> &operator<<(QJsonObject &json, std::pair value) { json.insert(value.first, QJsonValue(static_cast(value.second))); return json; } //! \brief Specialized JSON deserialization for enum //! \ingroup JSON template std::enable_if_t::value, QJsonValue> const &operator>>(const QJsonValue &json, ENUM &value) { value = static_cast(json.toInt()); return json; } //! \brief Specialized JSON deserialization for enum //! \ingroup JSON template std::enable_if_t::value, QJsonValueRef> const &operator>>(const QJsonValueRef &json, ENUM &value) { value = static_cast(json.toInt()); return json; } //! \brief Specialized JSON deserialization for pair //! \ingroup JSON template const QJsonValueRef &operator>>(const QJsonValueRef &json, std::pair &pair) { json.toArray() >> pair.first >> pair.second; return json; } //! \brief Specialized JSON serialization for pair //! \ingroup JSON template QJsonArray &operator<<(QJsonArray &json, const std::pair &pair) { QJsonArray array; return json << QJsonValue(array << pair.first << pair.second); } //! \name Streaming operators for QJsonArray (from value) //! \ingroup JSON //! @{ BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const int value); BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const std::pair &value); BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const qlonglong value); BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const uint value); BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const qulonglong value); BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const QString &value); BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const double value); BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const bool value); BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const QDateTime &value); BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const QPixmap &value); BLACKMISC_EXPORT QJsonArray &operator<<(QJsonArray &json, const QByteArray &value); //! @} //! \name Streaming operators for QJsonObject (from value) //! \ingroup JSON //! @{ BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair &value); //! @} namespace BlackMisc { namespace Json { //! Append to first JSON object (concatenate) //! \ingroup JSON BLACKMISC_EXPORT QJsonObject &appendJsonObject(QJsonObject &target, const QJsonObject &toBeAppended); //! JSON Object from string //! \ingroup JSON BLACKMISC_EXPORT QJsonObject jsonObjectFromString(const QString &json); //! JSON Array from string //! \ingroup JSON BLACKMISC_EXPORT QJsonArray jsonArrayFromString(const QString &json); //! Creates an incremental json object from two existing objects BLACKMISC_EXPORT QJsonObject getIncrementalObject(const QJsonObject &previousObject, const QJsonObject ¤tObject); //! Merges an incremental json object into an existing one BLACKMISC_EXPORT QJsonObject applyIncrementalObject(const QJsonObject &previousObject, const QJsonObject &incrementalObject); /*! * Load JSON file and init by that */ template bool loadFromJsonFile(T &object, const QString &fileNameAndPath) { const QString jsonString(CFileUtils::readFileToString(fileNameAndPath)); if (jsonString.isEmpty()) { return false; } object.convertFromJson(jsonString); return true; } /*! * Save to JSON file */ template bool saveToJsonFile(const T &object, const QString &fileNameAndPath) { const QString jsonString(object.toJsonString()); if (jsonString.isEmpty()) { return false; } return CFileUtils::writeStringToFile(jsonString, fileNameAndPath); } } // Json namespace Mixin { /*! * CRTP class template which will generate marshalling operators for a derived class with its own marshalling implementation. * * \tparam Must implement public methods QJsonObject toJson() const and void convertFromJson(const QJsonObject &json). */ template class JsonOperators { public: //! operator >> for JSON friend const QJsonObject &operator>>(const QJsonObject &json, Derived &obj) { obj.convertFromJson(json); return json; } //! operator >> for JSON friend const QJsonValue &operator>>(const QJsonValue &json, Derived &obj) { obj.convertFromJson(json.toObject()); return json; } //! operator >> for JSON friend const QJsonValueRef &operator>>(const QJsonValueRef &json, Derived &obj) { obj.convertFromJson(json.toObject()); return json; } //! operator << for JSON friend QJsonArray &operator<<(QJsonArray &json, const Derived &obj) { json.append(obj.toJson()); return json; } //! operator << for JSON friend QJsonObject &operator<<(QJsonObject &json, const std::pair &value) { json.insert(value.first, QJsonValue(value.second.toJson())); return json; } }; /*! * CRTP class template from which a derived class can inherit common methods dealing with JSON by metatuple. * * \tparam Derived Must be registered with BLACK_DECLARE_TUPLE_CONVERSION. * * \see BLACKMISC_DECLARE_USING_MIXIN_JSON */ template class JsonByTuple : public JsonOperators, private Private::EncapsulationBreaker { public: //! Cast to JSON object QJsonObject toJson() const { QJsonObject json = BlackMisc::serializeJson(Private::EncapsulationBreaker::toMetaTuple(*derived())); return Json::appendJsonObject(json, baseToJson(static_cast *>(derived()))); } //! Convenience function JSON as string QString toJsonString(QJsonDocument::JsonFormat format = QJsonDocument::Indented) const { QJsonDocument jsonDoc(toJson()); return jsonDoc.toJson(format); } //! Assign from JSON object void convertFromJson(const QJsonObject &json) { baseConvertFromJson(static_cast *>(derived()), json); BlackMisc::deserializeJson(json, Private::EncapsulationBreaker::toMetaTuple(*derived())); } //! Assign from JSON object string void convertFromJson(const QString &jsonString) { convertFromJson(BlackMisc::Json::jsonObjectFromString(jsonString)); } private: const Derived *derived() const { return static_cast(this); } Derived *derived() { return static_cast(this); } template static QJsonObject baseToJson(const T *base) { return base->toJson(); } template static void baseConvertFromJson(T *base, const QJsonObject &json) { base->convertFromJson(json); } static QJsonObject baseToJson(const void *) { return {}; } static void baseConvertFromJson(void *, const QJsonObject &) {} }; /*! * When a derived class and a base class both inherit from Mixin::JsonByTuple, * the derived class uses this macro to disambiguate the inherited members. */ # define BLACKMISC_DECLARE_USING_MIXIN_JSON(DERIVED) \ using ::BlackMisc::Mixin::JsonByTuple::toJson; \ using ::BlackMisc::Mixin::JsonByTuple::convertFromJson; } // Mixin } // BlackMisc #endif // guard