diff --git a/src/blackmisc/aviation/aircraftenginelist.h b/src/blackmisc/aviation/aircraftenginelist.h index a3cfa2f2f..8f665bfd8 100644 --- a/src/blackmisc/aviation/aircraftenginelist.h +++ b/src/blackmisc/aviation/aircraftenginelist.h @@ -48,10 +48,10 @@ namespace BlackMisc virtual void convertFromQVariant(const QVariant &variant) override { BlackMisc::setFromQVariant(this, variant); } //! \copydoc CValueObject::toJson - virtual QJsonObject toJson() const override; + QJsonObject toJson() const; //! \copydoc CValueObject::convertFromJson - virtual void convertFromJson(const QJsonObject &json) override; + void convertFromJson(const QJsonObject &json); //! Register metadata static void registerMetadata(); diff --git a/src/blackmisc/containerbase.h b/src/blackmisc/containerbase.h index 696b941cf..7755a4913 100644 --- a/src/blackmisc/containerbase.h +++ b/src/blackmisc/containerbase.h @@ -122,7 +122,7 @@ namespace BlackMisc friend uint qHash(const C &) { return 0; } //! \copydoc CValueObject::toJson - virtual QJsonObject toJson() const override + QJsonObject toJson() const { QJsonArray array; QJsonObject json; @@ -135,7 +135,7 @@ namespace BlackMisc } //! \copydoc CValueObject::convertFromJson - virtual void convertFromJson(const QJsonObject &json) override + void convertFromJson(const QJsonObject &json) { QJsonArray array = json.value("containerbase").toArray(); for (auto i = array.begin(); i != array.end(); ++i) diff --git a/src/blackmisc/dictionary.h b/src/blackmisc/dictionary.h index 8bcfd350f..0349f6230 100644 --- a/src/blackmisc/dictionary.h +++ b/src/blackmisc/dictionary.h @@ -233,7 +233,7 @@ namespace BlackMisc virtual void convertFromQVariant(const QVariant &variant) override { BlackMisc::setFromQVariant(this, variant); } //! \copydoc CValueObject::toJson - virtual QJsonObject toJson() const override + QJsonObject toJson() const { QJsonArray array; QJsonObject json; @@ -247,7 +247,7 @@ namespace BlackMisc } //! \copydoc CValueObject::convertFromJson - virtual void convertFromJson(const QJsonObject &json) override + void convertFromJson(const QJsonObject &json) { QJsonArray array = json.value("associativecontainerbase").toArray(); for (auto it = array.begin(); it != array.end(); ++it) diff --git a/src/blackmisc/pq/physicalquantity.h b/src/blackmisc/pq/physicalquantity.h index b60c9cf94..1e3278274 100644 --- a/src/blackmisc/pq/physicalquantity.h +++ b/src/blackmisc/pq/physicalquantity.h @@ -205,10 +205,10 @@ namespace BlackMisc friend uint qHash(const PQ &pq) { return pq.getValueHash(); }; //! \copydoc CValueObject::toJson - virtual QJsonObject toJson() const override; + QJsonObject toJson() const; //! \copydoc CValueObject::convertFromJson - virtual void convertFromJson(const QJsonObject &json) override; + void convertFromJson(const QJsonObject &json); //! Parse to string, with specified separator virtual void parseFromString(const QString &value, CPqString::SeparatorMode mode); diff --git a/src/blackmisc/simulation/simulatorplugininfo.h b/src/blackmisc/simulation/simulatorplugininfo.h index de9834f1b..71676919f 100644 --- a/src/blackmisc/simulation/simulatorplugininfo.h +++ b/src/blackmisc/simulation/simulatorplugininfo.h @@ -42,7 +42,8 @@ namespace BlackMisc //! Default constructor CSimulatorPluginInfo() = default; - virtual void convertFromJson(const QJsonObject &json) override; + //! \copydoc BlackMisc::CValueObject::convertFromJson + void convertFromJson(const QJsonObject &json); //! Unspecified simulator bool isUnspecified() const; diff --git a/src/blackmisc/valueobject.h b/src/blackmisc/valueobject.h index d041921d2..87fd760ef 100644 --- a/src/blackmisc/valueobject.h +++ b/src/blackmisc/valueobject.h @@ -105,18 +105,6 @@ namespace BlackMisc //! Dummy comparison. inline int compare(const CEmpty &, const CEmpty &) { return 0; } - /*! - * Terminating base cases for the recursive methods of CValueObject. - */ - struct CValueObjectDummyBase - { - //! To JSON - static QJsonObject toJson() { return {}; } - - //! From JSON - static void convertFromJson(const QJsonObject &) {} - }; - /*! * Default policy classes for use by CValueObject. * @@ -353,6 +341,130 @@ namespace BlackMisc static void baseUnmarshall(CEmpty &, const QDBusArgument &) {} }; + /*! + * CRTP class template from which a derived class can inherit common methods dealing with JSON by metatuple. + */ + template + class JsonByTuple : private Private::EncapsulationBreaker + { + 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; + } + + //! Cast to JSON object + QJsonObject toJson() const + { + QJsonObject json = BlackMisc::serializeJson(Private::EncapsulationBreaker::toMetaTuple(*derived())); + return Json::appendJsonObject(json, baseToJson(static_cast(*derived()))); + } + + //! Assign from JSON object + void convertFromJson(const QJsonObject &json) + { + baseConvertFromJson(static_cast(*derived()), json); + BlackMisc::deserializeJson(json, Private::EncapsulationBreaker::toMetaTuple(*derived())); + } + + 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 CEmpty &) { return {}; } + static void baseConvertFromJson(CEmpty &, const QJsonObject &) {} + }; + + /*! + * Specialization of JsonByTuple for classes not registered with the tuple system. + */ + template + class JsonByTuple + { + 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; + } + + //! Do nothing + QJsonObject toJson() const { return baseToJson(static_cast(*derived())); } + + //! Do nothing + void convertFromJson(const QJsonObject &json) { baseConvertFromJson(static_cast(*derived()), json); } + + 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 CEmpty &) { return {}; } + static void baseConvertFromJson(CEmpty &, const QJsonObject &) {} + }; + } /*! @@ -370,17 +482,15 @@ namespace BlackMisc public Mixin::MetaType, public Mixin::HashByTuple::value>, public Mixin::DBusByTuple::value>, + public Mixin::JsonByTuple::value>, private CValueObjectPolicy::Equals::template Ops, private CValueObjectPolicy::LessThan::template Ops, private CValueObjectPolicy::Compare::template Ops { static_assert(std::is_same::value || IsValueObject::value, "Base must be either CEmpty or derived from CValueObject"); - using JsonPolicy = typename CValueObjectPolicy::Json; using PropertyIndexPolicy = typename CValueObjectPolicy::PropertyIndex; - using BaseOrDummy = typename std::conditional::value, CValueObjectDummyBase, Base>::type; - //! Stream << overload to be used in debugging messages friend QDebug operator<<(QDebug debug, const Derived &obj) { @@ -416,41 +526,6 @@ namespace BlackMisc return ostr; } - //! operator >> for JSON - friend const QJsonObject &operator>>(const QJsonObject &json, Derived &valueObject) - { - valueObject.convertFromJson(json); - return json; - } - - //! operator >> for JSON - friend const QJsonValue &operator>>(const QJsonValue &json, Derived &valueObject) - { - valueObject.convertFromJson(json.toObject()); - return json; - } - - //! operator >> for JSON - friend const QJsonValueRef &operator>>(const QJsonValueRef &json, Derived &valueObject) - { - valueObject.convertFromJson(json.toObject()); - return json; - } - - //! operator << for JSON - friend QJsonArray &operator<<(QJsonArray &json, const Derived &value) - { - json.append(value.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; - } - public: //! Base class using base_type = Base; @@ -485,19 +560,11 @@ namespace BlackMisc //! \copydoc BlackMisc::Mixin::MetaType::convertFromCVariant using Mixin::MetaType::convertFromCVariant; - //! Cast to JSON object - virtual QJsonObject toJson() const - { - QJsonObject json = JsonPolicy::serializeImpl(*derived()); - return Json::appendJsonObject(json, BaseOrDummy::toJson()); - } + //! \copydoc BlackMisc::Mixin::JsonByTuple::toJson + using Mixin::JsonByTuple::value>::toJson; - //! Assign from JSON object - virtual void convertFromJson(const QJsonObject &json) - { - BaseOrDummy::convertFromJson(json); - JsonPolicy::deserializeImpl(json, *derived()); - } + //! \copydoc BlackMisc::Mixin::JsonByTuple::convertFromJson + using Mixin::JsonByTuple::value>::convertFromJson; //! \copydoc BlackMisc::Mixin::MetaType::toQVariant using Mixin::MetaType::toQVariant; diff --git a/src/blackmisc/valueobject_policy.h b/src/blackmisc/valueobject_policy.h index 77bfd231f..7c2c4813c 100644 --- a/src/blackmisc/valueobject_policy.h +++ b/src/blackmisc/valueobject_policy.h @@ -395,6 +395,11 @@ namespace BlackMisc template static void deserializeImpl(const QJsonObject &, T &) {} }; + + //! \private Detect the policy of T, following inheritance. + template ::Json> struct IsMetaTuple : public std::false_type {}; + template struct IsMetaTuple : public std::true_type {}; + template struct IsMetaTuple : public IsMetaTuple {}; } namespace PropertyIndex diff --git a/src/blackmisc/variant.h b/src/blackmisc/variant.h index cb4bbbe0f..beb7aff80 100644 --- a/src/blackmisc/variant.h +++ b/src/blackmisc/variant.h @@ -179,10 +179,10 @@ namespace BlackMisc int userType() const { return m_v.userType(); } //! \copydoc CValueObject::toJson - virtual QJsonObject toJson() const override; + QJsonObject toJson() const; //! \copydoc CValueObject::convertFromJson - virtual void convertFromJson(const QJsonObject &json) override; + void convertFromJson(const QJsonObject &json); //! \copydoc CValueObject::marshallToDbus void marshallToDbus(QDBusArgument &argument) const;