赞
踩
最近项目中需要使用C++ Json序列化和反序列化,顺便调研了下目前比较好用的C++ json库,发现nlohmann/json应该是其中相对较好的json库。nlohmann/json有如下主要优点:
1、语法比较直观,类似于Python。
2、要使用nlohmann/json,只需要引入头文件json.hpp。无需引入lib之类的。
#include <nlohmann/json.hpp>
// for convenience
using json = nlohmann::json;
3、经过非常多的测试,代码质量非常高,没有内存泄漏。
4、内存效率、速度相对其它库较高。
使用nlohmann/json创建Json对象,无需关心值类型,比如创建如下Json对象:
// create an empty structure (null) json j; // add a number that is stored as double (note the implicit conversion of j to an object) j["pi"] = 3.141; // add a Boolean that is stored as bool j["happy"] = true; // add a string that is stored as std::string j["name"] = "Niels"; // add another null object by passing nullptr j["nothing"] = nullptr; // add an object inside the object j["answer"]["everything"] = 42; // add an array that is stored as std::vector (using an initializer list) j["list"] = { 1, 0, 2 }; // add another object (using an initializer list of pairs) j["object"] = { {"currency", "USD"}, {"value", 42.99} }; // instead, you could also write (which looks very similar to the JSON above) json j2 = { {"pi", 3.141}, {"happy", true}, {"name", "Niels"}, {"nothing", nullptr}, {"answer", { {"everything", 42} }}, {"list", {1, 0, 2}}, {"object", { {"currency", "USD"}, {"value", 42.99} }} };
在class/struct内部定义NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, …)
class Address
{
std::string street;
int housenumber;
int postcode;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Address, street, housenumber, postcode)
};
std::string strTemp =(R"({"street": "test", "housenumber": 0, "postcode": 0})";
Address temp = nlohmann::json::parse(strTemp).get<Address>();
Addree temp{"Test", 0, 0};
nlohmann::json jsonTemp = temp;
std::string strTemp = jsonTemp.dump();
为了方便序列/反序列化,可以封装下面两个接口:
template<class T>
static void deserialize(const std::string &str, T &value)
{
if (str.size() <= 0)
return;
value = parse(str).template get<T>();
}
template<class T>
static void serialize(const T &value, std::string &str)
{
str = json(value).dump();
}
实际项目中,json使用未必非常标准,有解析strings参数比较少的需求。比如2.2中类Address
std::string strTemp =(R"({"street": "test", "housenumber": 0})";
Address temp = nlohmann::json::parse(strTemp).get<Address>();
strTemp少了postcode,执行第二行代码就会崩溃。
打开nlohmann/json.hpp找到源码
#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);
将其改成
#define NLOHMANN_JSON_FROM(v1) if(nlohmann_json_j.contains(#v1)){nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);}
相比源码,就加了contains的判断,若待解析的json没有对应字段,就不作处理。
strings包含中文、“\“等“特殊字符”,用nlohmann::json反序列化就会崩溃。跟大多数json库一样,nlohmann::json是不支持中文、”\"等“特殊字符”的,因此需要先替换strings中的特殊字符,再反序列化。
实际项目中协议定的某些字段,经常出现数字、string混用的情况。nlohmann/json默认实现要求反序列化的目标class/struct参数类型和strings中完美匹配,否则解析过程中崩溃。
原代码
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
{
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
{
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j));
}
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
}
改造后
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
{
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
{
/* 为了提高健壮性,对于json中非string的类型,也将其转成string */
s = to_string(j);
return;
/* JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); */
}
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
}
NLOHMANN_DEFINE_TYPE_INTRUSIVE并不能无限展开,nlohmann/json默认支持63个参数。
NLOHMANN_DEFINE_TYPE_INTRUSIVE的定义如下:
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
NLOHMANN_DEFINE_TYPE_INTRUSIVE的原理就是用NLOHMANN_JSON_EXPAND,1个NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, …))可以支持63个,超过可以另起1个,如下:
struct StructTest { std::string param1; std::string param2; ... std::string param63; std::string param64; ... friend void from_json(const nlohmann::json& nlohmann_json_j, StructTest& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(func, param1, param2, ..., param63)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(func, param64, param65, ...)); } friend void to_json(nlohmann::json& nlohmann_json_j, const StructTest& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(func, param1, param2, ..., param63)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(func, param64, param65, ...)); } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。