// SPDX-License-Identifier: LGPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of nymea. * * nymea is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * nymea is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with nymea. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef JSONHANDLER_H #define JSONHANDLER_H #include #include #include #include #include #include #include "jsonreply.h" #include "jsoncontext.h" #include "typeutils.h" class JsonHandler : public QObject { Q_OBJECT public: enum BasicType { Uuid = QMetaType::QUuid, String = QMetaType::QString, StringList = QMetaType::QStringList, Int = QMetaType::Int, Uint = QMetaType::UInt, Double = QMetaType::Double, Bool = QMetaType::Bool, Variant = QMetaType::QVariant, Color = QMetaType::QColor, Time = QMetaType::QTime, Object = QMetaType::QVariantMap }; Q_ENUM(BasicType) explicit JsonHandler(QObject *parent = nullptr); virtual ~JsonHandler() = default; virtual QString name() const = 0; virtual QHash cacheHashes() const; virtual QVariantMap translateNotification(const QString ¬ification, const QVariantMap ¶ms, const QLocale &locale); QVariantMap jsonEnums() const; QVariantMap jsonFlags() const; QVariantMap jsonObjects() const; QVariantMap jsonMethods() const; QVariantMap jsonNotifications() const; template static QString enumRef(); template static QString flagRef(); template static QString objectRef(); static QString objectRef(const QString &objectName); template static QString enumValueName(T value); template static T enumNameToValue(const QString &name); template static QStringList flagValueNames(T value); template static T flagNamesToValue(const QStringList &names); static BasicType variantTypeToBasicType(QMetaType::Type variantType); static QMetaType::Type basicTypeToMetaType(BasicType basicType); template QVariant pack(const T &value) const; template QVariant pack(T *value) const; template T unpack(const QVariant &value) const; protected: template void registerEnum(); template void registerFlag(); // Registers the given object template void registerObject(); // Registers the given list type object as a container for the given object type, without registering the object type itself template void registerList(); // Registers an object and its list type object template void registerObject(); template void registerUncreatableObject(); template void registerUncreatableObject(); template void registerList(BasicTypeName typeName); // Deprecated QString based registerObject void registerObject(const QString &name, const QVariantMap &object); void registerMethod(const QString &name, const QString &description, const QVariantMap ¶ms, const QVariantMap &returns, Types::PermissionScope permissionScope = Types::PermissionScopeAdmin, const QString &deprecationInfo = QString()); void registerNotification(const QString &name, const QString &description, const QVariantMap ¶ms, const QString &deprecationInfo = QString()); JsonReply *createReply(const QVariantMap &data) const; JsonReply *createAsyncReply(const QString &method) const; private: void registerObject(const QMetaObject &metaObject); void registerList(const QMetaObject &listObject, const QMetaObject &metaObject); void registerObject(const QMetaObject &metaObject, const QMetaObject &listMetaObject); QVariant pack(const QMetaObject &metaObject, const void *gadget) const; QVariant unpack(const QMetaObject &metaObject, const QVariant &value) const; private: QVariantMap m_enums; QHash m_metaEnums; QVariantMap m_flags; QHash m_metaFlags; QHash m_flagsEnums; QVariantMap m_objects; QHash m_metaObjects; QHash m_listMetaObjects; QHash m_listEntryTypes; QVariantMap m_methods; QVariantMap m_notifications; }; Q_DECLARE_METATYPE(QMetaType::Type) template void JsonHandler::registerEnum() { QMetaEnum metaEnum = QMetaEnum::fromType(); QStringList values; for (int i = 0; i < metaEnum.keyCount(); i++) { values << metaEnum.key(i); } m_enums.insert(metaEnum.name(), values); m_metaEnums.insert(metaEnum.name(), metaEnum); } template void JsonHandler::registerFlag() { registerEnum(); QMetaEnum metaEnum = QMetaEnum::fromType(); QMetaEnum metaFlags = QMetaEnum::fromType(); m_metaFlags.insert(metaFlags.name(), metaFlags); m_flagsEnums.insert(metaFlags.name(), metaEnum.name()); m_flags.insert(metaFlags.name(), QVariantList() << QString("$ref:%1").arg(metaEnum.name())); } template void JsonHandler::registerObject() { qRegisterMetaType(); QMetaObject metaObject = ObjectType::staticMetaObject; registerObject(metaObject); } template void JsonHandler::registerList() { qRegisterMetaType(); QMetaObject metaObject = ObjectType::staticMetaObject; QMetaObject listMetaObject = ListType::staticMetaObject; registerList(listMetaObject, metaObject); } template void JsonHandler::registerObject() { qRegisterMetaType(); qRegisterMetaType(); QMetaObject metaObject = ObjectType::staticMetaObject; QMetaObject listMetaObject = ListType::staticMetaObject; registerObject(metaObject, listMetaObject); } template void JsonHandler::registerUncreatableObject() { QMetaObject metaObject = ObjectType::staticMetaObject; registerObject(metaObject); } template void JsonHandler::registerUncreatableObject() { QMetaObject metaObject = ObjectType::staticMetaObject; QMetaObject listMetaObject = ListType::staticMetaObject; registerObject(metaObject, listMetaObject); } template void JsonHandler::registerList(BasicTypeName typeName) { QMetaObject listMetaObject = ListType::staticMetaObject; QString listTypeName = QString(listMetaObject.className()).split("::").last(); m_metaObjects.insert(listTypeName, listMetaObject); //m_objects.insert(listTypeName, QVariantList() << QVariant(QString("$ref:%1").arg(enumValueName(typeName)))); m_objects.insert(listTypeName, QVariant(QString("$ref:%1").arg(typeName))); Q_ASSERT_X(listMetaObject.indexOfProperty("count") >= 0, "JsonHandler", QString("List type %1 does not implement \"count\" property!").arg(listTypeName).toUtf8()); Q_ASSERT_X(listMetaObject.indexOfMethod("get(int)") >= 0, "JsonHandler", QString("List type %1 does not implement \"Q_INVOKABLE QVariant get(int index)\" method!").arg(listTypeName).toUtf8()); Q_ASSERT_X(listMetaObject.indexOfMethod("put(QVariant)") >= 0, "JsonHandler", QString("List type %1 does not implement \"Q_INVOKABLE void put(QVariant variant)\" method!").arg(listTypeName).toUtf8()); } template QString JsonHandler::enumRef() { QMetaEnum metaEnum = QMetaEnum::fromType(); Q_ASSERT_X(!metaEnum.isFlag(), "JsonHandler", QString("The given type reference %1 is a flag. Please use flagRef() instead.").arg(metaEnum.name()).toUtf8()); return QString("$ref:%1").arg(metaEnum.name()); } template QString JsonHandler::flagRef() { QMetaEnum metaFlag = QMetaEnum::fromType(); Q_ASSERT_X(metaFlag.isFlag(), "JsonHandler", QString("The given type reference %1 is not a flag.").arg(metaFlag.name()).toUtf8()); return QString("$ref:%1").arg(metaFlag.name()); } template QString JsonHandler::objectRef() { QMetaObject metaObject = T::staticMetaObject; return QString("$ref:%1").arg(QString(metaObject.className()).split("::").last()); } template QString JsonHandler::enumValueName(T value) { QMetaEnum metaEnum = QMetaEnum::fromType(); return metaEnum.valueToKey(value); } template T JsonHandler::enumNameToValue(const QString &name) { QMetaEnum metaEnum = QMetaEnum::fromType(); return static_cast(metaEnum.keyToValue(name.toUtf8())); } template QStringList JsonHandler::flagValueNames(T value) { QMetaEnum metaFlag = QMetaEnum::fromType(); Q_ASSERT_X(metaFlag.isFlag(), "JsonHandler", QString("The given template type %1 is not a flag.").arg(metaFlag.name()).toUtf8()); QStringList names; for (int i = 0; i < metaFlag.keyCount(); i++) { if ((metaFlag.value(i) & value) > 0) { names.append(metaFlag.key(i)); } } return names; } template T JsonHandler::flagNamesToValue(const QStringList &names) { QMetaEnum metaFlag = QMetaEnum::fromType(); Q_ASSERT_X(metaFlag.isFlag(), "JsonHandler", QString("The given template type %1 is not a flag.").arg(metaFlag.name()).toUtf8()); T flag; foreach (const QString &name, names) { bool keyOk; flag |= metaFlag.keyToValue(name.toUtf8(), &keyOk); Q_ASSERT_X(keyOk, "JsonHandler", QString("The given enum value for the flag %1 is not ok.").arg(metaFlag.name()).toUtf8()); } return flag; } template QVariant JsonHandler::pack(const T &value) const { QMetaObject metaObject = T::staticMetaObject; return pack(metaObject, static_cast(&value)); } template QVariant JsonHandler::pack(T *value) const { QMetaObject metaObject = T::staticMetaObject; return pack(metaObject, static_cast(value)); } template T JsonHandler::unpack(const QVariant &value) const { QMetaObject metaObject = T::staticMetaObject; QVariant ret = unpack(metaObject, value); return ret.value(); } #endif // JSONHANDLER_H