【QtJson】用Qt自带的QJson,直接一步到位封装和解析一个类的实例对象!

之前貌似没有看过类似的代码
我们现在的要求就是直接在不知道类成员的情况下,把一个类丢进去就能生成一个Json字符串,也可以把一个字符串和一个类成员丢进去就能根据成员变量名匹配到元素并赋值,大概就这样

中心思想就是Q_PROPERTY宏提供了一个property类型,可以直接通过变量名称获得一个变量名称对应的字符串,比如int a;可以直接获得一个"a"的字符串,而且还可以知道这个a 的类型。并据此来进行字符串的封装和解析。

主要是为了开发方便,就可以直接把一个QObject对象扔进去返回一个字符串,也可以把一个Json字符串和指定类的对象扔进去就直接自动把类中对应的属性修改了,总的来说应该是用点用。

--2023.2.2稍微修改了一下,与原先的使用上会有点区别

#pragma region Example调用实例

//Json相关方法调用实例:
//
// 如果想要调用JsonMaker类来把你的类成员元素,假设是A a,其中包含元素qint32 a1,QString a2,bool a3进行封装,那么你需要使用Q_PROPERTY来
// 声明封装a1,a2,a3元素和其set/get方法(如果需要解析就需要set方法,如果需要封装就需要get方法),set/get方法命名规则为set/get+元素名称
// 比如seta1,geta2,其中不对大小写做规定,也可以写成setA1,getA2
// 
// 调用方法如下:
// 1.封装字符串
// A a; 
// QString result = JsonMaker::Singleton().JsonSerialization<Tester1>(tester);
// 2.解析字符串
// A a
// JsonMaker::Singleton().JsonDeserialization<Tester1>(a, Json);
// 调用完毕后a中的对应数据都会被Json字符串中的数据覆盖
//

//测试解析、封装类举例:
class Tester1 :public QObject {
Q_OBJECT
	Q_PROPERTY(QString name READ getName WRITE setname)
	Q_PROPERTY(QString like READ getLike WRITE setlike)
	Q_PROPERTY(QString birthday READ getBirthday WRITE setbirthday)
	//Q_PROPERTY(QString str_public READ str_public,WRITE setStr_public)
	Q_PROPERTY(QList<QString> list READ getList WRITE setlist)
	Q_PROPERTY(QList<qint32> qint32_list READ getqint32_List WRITE setqint32_list)
	//暂时不支持float类型
	//Q_PROPERTY(QList<float> float_list READ getFloat_List)
	Q_PROPERTY(QList<double> double_list READ getDouble_List WRITE setdouble_list)
	Q_PROPERTY(QList<bool> bln_list READ getBln_List WRITE setbln_list)
	Q_PROPERTY(QList<int> int_list READ getInt_list WRITE setint_list)
public:
	Tester1(QObject* parent = Q_NULLPTR);
	//QString str_public = "str_public";
#pragma region get funcs

QString getName() {
	return name;
}
QString getLike() {
	return like;
}
QString getBirthday() {
	return birthday;
}
QList<QString> getList() {
	return this->list;
}
QList<int> getInt_list() {
	return this->int_list;
}
QList<qint32> getqint32_List() {
	return this->qint32_list;
}
QList<float> getFlost_List() {
	return this->float_list;
}
QList<double> getDouble_List() {
	return this->double_list;
}
QList<bool> getBln_List()
{
	return this->bln_list;
}
QList<float> getFloat_List() {
	return float_list;
}
#pragma endregion

#pragma region Set Funcs
	/*QList<QString> list = { "123","234","345","4356" };
	QList<qint32> qint_list = { 123,234,345,456 };
	QList<float> float_list = { 1.123123,2.234234,4.345345,45.457457 };
	QList<double> double_list = { 1.2443,3.52,2.351,1.235 };
	QList<int> int_list = { 234,345,456,567,678,123,32 };
	QList<bool> bln_list = { true,false,true,false };*/

	Q_INVOKABLE void setlist(QList<QString> list_value) {
		this->list = list_value;
	}
	Q_INVOKABLE void setqint32_list(QList<qint32> list_value) {
		this->qint32_list = list_value;
	}
	Q_INVOKABLE void setdouble_list(QList<double> list_value) {
		this->double_list = list_value;
	}
	Q_INVOKABLE void setint_list(QList<int> list_value) {
		this->int_list = list_value;
	}
	Q_INVOKABLE void setbln_list(QList<bool> list_value) {
		this->bln_list = list_value;
	}
	Q_INVOKABLE void setname(QString strValue) {
		this->name = strValue;
	}
	Q_INVOKABLE void setlike(QString strValue) {
		this->like = strValue;
	}
	Q_INVOKABLE void setbirthday(QString strValue) {
		this->birthday = strValue;
	}

#pragma endregion


private:
	QString name = "name";
	QString like = "like";
	QString birthday = "birthday";
	QList<QString> list = { "123","234","345","4356" };
	QList<qint32> qint32_list = { 123,234,345,456 };
	QList<float> float_list = { 1.123123,2.234234,4.345345,45.457457 };
	QList<double> double_list = { 1.2443,3.52,2.351,1.235 };
	QList<int> int_list = { 234,345,456,567,678,123,32 };
	QList<bool> bln_list = { true,false,true,false };
};
	#pragma endregion


//Json相关
//给定任意模板类,将其公开属性打包成一个Json字符串,使用此方法需要所有的公开属性均为Q_PROPERTY宏声明,该类提供单例。
//序列化类Q_PROPERTY宏声明的属性 set/get函数命名规则:get/set+属性名 如getBirthday setList,大小写不限,如果是set方法需要在set方法前面加上Q_INVOKABLE 宏
//如果需要反序列化数组,请保证数组中的所有数据结构是同一个类型,否则可能会出错
//注:请尽量使用int不要使用qint32,使用double不要使用float
#pragma region JsonMaker
//JsonMaker类使用方法:


//Json相关
//给定任意模板类,将其公开属性打包成一个Json字符串,使用此方法需要所有的公开属性均为Q_PROPERTY宏声明,该类提供单例。
//序列化类Q_PROPERTY宏声明的属性 set/get函数命名规则:get/set+属性名 如getBirthday setList,大小写不限,如果是set方法需要在set方法前面加上Q_INVOKABLE 宏
//如果需要反序列化数组,请保证数组中的所有数据结构是同一个类型,否则可能会出错
//注:请尽量使用int不要使用qint32,使用double不要使用float
	class JsonMaker :public QObject {
		JsonMaker();
		//提供单例
	public:
		static JsonMaker& JsonMaker::Singleton() {
			static JsonMaker Instance;
			return Instance;
			// TODO: 在此处插入 return 语句
		}

	//序列化类Q_PROPERTY宏声明的属性,如果有数组类型,请使用QList<QSharedPointer>来执行指定操作
	template<class T1>
	QString JsonSerialization(QSharedPointer<T1>T_Class_1) {
		auto T_Class = dynamic_cast<QObject*>(T_Class_1.data());
		QJsonObject jsonObject;
		//通过元对象定义成员
		const QMetaObject* metaObject = T_Class->metaObject();
		for (int i = 0; i < metaObject->propertyCount(); ++i) {
			QMetaProperty property = metaObject->property(i);

			if (!property.isReadable()) {
				continue;
			}
			//这个不知道是什么,暂时需要先屏蔽掉

			if (QString(property.name()) == "objectName") {
				continue;
			}

			//如果是QList

			if (QString(property.typeName()).contains("QList")) {
				//这里可能要根据常见类型进行一下分类
				QJsonArray jsonListArray;
				//输入一个模板类类型,输出一个jsonObject
				if (QString(property.typeName()) == "QList<QString>") {
					QList<QString> str_message = property.read(T_Class).value<QList<QString>>();
					jsonListArray = QListToJsonArray(str_message);
				}
				else if (QString(property.typeName()) == "QList<qint32>" || QString(property.typeName()) == "QList<int>") {
					QList<qint32> str_message = property.read(T_Class).value<QList<qint32>>();
					jsonListArray = QListToJsonArray(str_message);
				}
				else if (QString(property.typeName()) == "QList<qint64>") {
					QList<qint64> str_message = property.read(T_Class).value<QList<qint64>>();
					jsonListArray = QListToJsonArray(str_message);
				}
				else if (QString(property.typeName()) == "QList<int>") {
					QList<int> str_message = property.read(T_Class).value<QList<int>>();
					jsonListArray = QListToJsonArray(str_message);
				}
				else if (QString(property.typeName()) == "QList<bool>") {
					QList<bool> str_message = property.read(T_Class).value<QList<bool>>();
					jsonListArray = QListToJsonArray(str_message);
				}
				else if (QString(property.typeName()) == "QList<double>") {
					QList<double> str_message = property.read(T_Class).value<QList<double>>();
					jsonListArray = QListToJsonArray(str_message);
				}
				else if (QString(property.typeName()) == "QList<Float>") {
					QList<float> str_message = property.read(T_Class).value<QList<float>>();
					jsonListArray = QListToJsonArray(str_message);
				}
				else if (QString(property.typeName()) == "QList<QByteArray>") {
					QList<QByteArray> str_message = property.read(T_Class).value<QList<QByteArray>>();
					jsonListArray = QListToJsonArray(str_message);
				}

				jsonObject.insert(property.name(), QJsonValue(jsonListArray));
			}
			//如果不是QList
			else {
				QVariant result = property.read(T_Class);
				jsonObject[property.name()] = QJsonValue::fromVariant(property.read(T_Class));

			}
			qDebug() << property.name();
		}

		QJsonDocument doc(jsonObject);
		return doc.toJson(QJsonDocument::Compact);
	}
	//反序列化类Q_PROPERTY宏声明的属性,如果有数组类型,请使用QList
	template<class T>
	void JsonDeserialization(QSharedPointer<T> T_Class, const QString& jsonString)
	{
		auto qobject = dynamic_cast<QObject*>(T_Class.data());

		QJsonDocument doc = QJsonDocument::fromJson(jsonString.toUtf8());
		QJsonObject jsonObject = doc.object();
		// 使用QMetaObject的invokeMethod()函数来调用模板类T的setter函数
		const QMetaObject* metaObject = qobject->metaObject();

		for (int i = 0; i < metaObject->propertyCount(); ++i) {
			QMetaProperty property = metaObject->property(i);
			if (property.isReadable() && property.isWritable()) {
				QString propertyName = property.name();
				QString str_functinoname = QString("set" + propertyName);
				//为了转换成const char*类型必须的一个中间步骤
				QByteArray temp_qba_functinoname = str_functinoname.toLocal8Bit();
				const char* func_name = temp_qba_functinoname.data();

				if (jsonObject.contains(propertyName)) {
					QJsonValue value = jsonObject[propertyName];
					JsonMaker temp;
					qDebug() << value;
					switch (value.type()) {
					case QJsonValue::Type::Bool:
						QMetaObject::invokeMethod(qobject, func_name, Q_ARG(bool, value.toBool()));
						break;
					case QJsonValue::Type::Double:
						if (!QMetaObject::invokeMethod(qobject, func_name, Q_ARG(int, value.toDouble())))
							QMetaObject::invokeMethod(qobject, func_name, Q_ARG(double, value.toDouble()));
						break;
					case QJsonValue::Type::String:
						qDebug() << QMetaObject::invokeMethod(qobject, func_name, Q_ARG(QString, value.toString()));
						break;
					case QJsonValue::Type::Array: {
						//如果是数组则需要根据情况进行解析
						if (!value.isArray()) {
							break;
						}
						QJsonArray arr = value.toArray();
						//下面确定数组类型
						this->JsonArrayDeserialization(qobject, func_name, arr);
					}
												break;
					case QJsonValue::Type::Object:
						QMetaObject::invokeMethod(qobject, func_name, Q_ARG(QJsonValue, value));
						break;
					default:
						break;
					}
				}
			}
		}
	}

private:
	//将模板类QList转换成JsonObject
	template<class T>
	QJsonArray QListToJsonArray(QList<T> list) {
		QJsonArray jsonArray;
		for each (T temp_T in list)
		{
			jsonArray.append(QJsonValue::fromVariant(temp_T));
		}

		return jsonArray;
	}

	//解析数组并注入QObject对象
	void JsonArrayDeserialization(QObject* qobject, const char* func_name, QJsonArray arr) {
		try {
			//判断类型
		   //QString
			if (arr[0].type() == QJsonValue::String) {
				QList<QString> list_result;
				QJsonValue value;

				for each (QJsonValue temp_value in arr)
				{
					list_result.append(temp_value.toString());
				}
				QMetaObject::invokeMethod(qobject, func_name, Q_ARG(QList<QString>, list_result));

			}
			else if (arr[0].isDouble()) {
				//若为为整形
				if (arr[0].toDouble() == arr[0].toInt()) {
					qDebug() << arr[0].toDouble() << arr[0].toInt();
					QList<qint32> list_result;
					QList<int> list_result_2;
					QJsonValue value;

					for each (QJsonValue temp_value in arr)
					{
						//int 和 qint32都需要尝试,但请尽量尝试使用qint32,这段代码占用了两倍的内存,将来可能考虑删除
						list_result.append(temp_value.toInt());
						list_result_2.append(temp_value.toInt());
					}
					if (!QMetaObject::invokeMethod(qobject, func_name, Q_ARG(QList<qint32>, list_result))) {
						QMetaObject::invokeMethod(qobject, func_name, Q_ARG(QList<int>, list_result_2));
					}
				}
				//若为双精度
				else {
					QList<double> list_result;
					QList<float> list_result_2;
					QJsonValue value;

					for each (QJsonValue temp_value in arr)
					{
						list_result.append(temp_value.toDouble());
					}
					//double和float都会尝试,请尽量使用double
					if (!QMetaObject::invokeMethod(qobject, func_name, Q_ARG(QList<double>, list_result))) {
						QMetaObject::invokeMethod(qobject, func_name, Q_ARG(QList<float>, list_result_2));
					}

				}
			}if (arr[0].type() == QJsonValue::Bool) {
				QList<bool> list_result;
				QJsonValue value;

				for each (QJsonValue temp_value in arr)
				{
					list_result.append(temp_value.toBool());
				}
				QMetaObject::invokeMethod(qobject, func_name, Q_ARG(QList<bool>, list_result));
			}
		}
		catch (const QException& e) {
			WriteErrorMessage("JsonArrayDeserialization", "JsonArrayDeserialization", e.what());
		}
	}

};
#pragma endregion
posted @ 2023-01-11 09:06  轩先生。  阅读(1086)  评论(2编辑  收藏  举报