// 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