将对象序列化和反序列化为 JSON 的方法?

我想要一种将对象序列化和反序列化为 JSON 的方法,尽可能自动化。

序列化: 对我来说,理想的方法是,如果我调用一个实例 JSONSerialize() 它返回一个带有 JSON 对象的字符串,该对象的所有公共属性为 "name_of_property": "value" 。对于那些原语值,这很简单,对于对象,它应该尝试调用每个 JSONSerialize() 或 ToString() 或类似的东西以递归地序列化所有公共属性。对于集合,它也应该表现正确(只是向量/数组就可以了)。

反序列化:只需创建给定对象的实例(假设是一只狗)并调用 JSONDeserialize(json_string) ,这应该填充所有公共属性,创建所需的对象以防属性不是基元,或者需要的收藏品。

一个例子应该像这样运行:

 Dog *d1 = new Dog();
d1->name = "myDog";

string serialized = d1->JSONSerialize();

Dog *d2 = new Dog();
d2->JSONDeserialize(serialized);
std::cout << d2->name; // This will print "myDog"

或者像这样:

 Dog *d1 = new Dog();
d1->name = "myDog";

string serialized = JSONSerializer.Serialize(d1);

Dog *d2 = JSONSerializer.Deserialize(serialized, Dog);
std::cout << d2->name; // This will print "myDog"

我怎样才能轻松做到这一点?

原文由 Vicenç Gascó 发布,翻译遵循 CC BY-SA 4.0 许可协议
阅读 1.7k
2 个回答

为此,您需要在不存在的 C/C++ 中进行反射。您需要有一些描述类结构的元数据(成员、继承的基类)。目前,C/C++ 编译器不会在构建的二进制文件中自动提供该信息。

我也有同样的想法,我使用 GCC XML 项目来获取这些信息。它输出描述类结构的 XML 数据。我已经建立了一个项目,并在此 页面 中解释了一些关键点:

序列化很容易,但我们必须处理复杂的数据结构实现(例如 std::string,std::map),这些实现使用分配的缓冲区。反序列化更复杂,您需要重建对象及其所有成员,以及对 vtables 的引用……这是一个痛苦的实现。

例如,您可以像这样序列化:

     // Random class initialization
    com::class1* aObject = new com::class1();

    for (int i=0; i<10; i++){
            aObject->setData(i,i);
    }

    aObject->pdata = new char[7];
    for (int i=0; i<7; i++){
            aObject->pdata[i] = 7-i;
    }
    // dictionary initialization
    cjson::dictionary aDict("./data/dictionary.xml");

    // json transformation
    std::string aJson = aDict.toJson<com::class1>(aObject);

    // print encoded class
    cout << aJson << std::endl ;

要反序列化数据,它的工作方式如下:

     // decode the object
    com::class1* aDecodedObject = aDict.fromJson<com::class1>(aJson);

    // modify data
    aDecodedObject->setData(4,22);

    // json transformation
    aJson = aDict.toJson<com::class1>(aDecodedObject);

    // print encoded class
    cout << aJson << std::endl ;

输出:

 >:~/cjson$ ./main
{"_index":54,"_inner":  {"_ident":"test","pi":3.141593},"_name":"first","com::class0::_type":"type","com::class0::data":[0,1,2,3,4,5,6,7,8,9],"com::classb::_ref":"ref","com::classm1::_type":"typem1","com::classm1::pdata":[7,6,5,4,3,2,1]}
{"_index":54,"_inner":{"_ident":"test","pi":3.141593},"_name":"first","com::class0::_type":"type","com::class0::data":[0,1,2,3,22,5,6,7,8,9],"com::classb::_ref":"ref","com::classm1::_type":"typem1","com::classm1::pdata":[7,6,5,4,3,2,1]}
>:~/cjson$

通常这些实现依赖于编译器(例如 ABI 规范),并且需要外部描述才能工作(GCCXML 输出),因此不太容易集成到项目中。

原文由 JBV06 发布,翻译遵循 CC BY-SA 4.0 许可协议

jsoncons C++ 仅标头库还支持 JSON 文本和 C++ 对象之间的转换。为所有定义了 json_type_traits 的 C++ 类定义了解码和编码。已经支持标准库容器,并且 json_type_traits 可以专门用于 jsoncons 命名空间中的用户类型。

下面是一个例子:

 #include <iostream>
#include <jsoncons/json.hpp>

namespace ns {
    enum class hiking_experience {beginner,intermediate,advanced};

    class hiking_reputon
    {
        std::string rater_;
        hiking_experience assertion_;
        std::string rated_;
        double rating_;
    public:
        hiking_reputon(const std::string& rater,
                       hiking_experience assertion,
                       const std::string& rated,
                       double rating)
            : rater_(rater), assertion_(assertion), rated_(rated), rating_(rating)
        {
        }

        const std::string& rater() const {return rater_;}
        hiking_experience assertion() const {return assertion_;}
        const std::string& rated() const {return rated_;}
        double rating() const {return rating_;}
    };

    class hiking_reputation
    {
        std::string application_;
        std::vector<hiking_reputon> reputons_;
    public:
        hiking_reputation(const std::string& application,
                          const std::vector<hiking_reputon>& reputons)
            : application_(application),
              reputons_(reputons)
        {}

        const std::string& application() const { return application_;}
        const std::vector<hiking_reputon>& reputons() const { return reputons_;}
    };

} // namespace ns

// Declare the traits using convenience macros. Specify which data members need to be serialized.

JSONCONS_ENUM_TRAITS_DECL(ns::hiking_experience, beginner, intermediate, advanced)
JSONCONS_ALL_CTOR_GETTER_TRAITS(ns::hiking_reputon, rater, assertion, rated, rating)
JSONCONS_ALL_CTOR_GETTER_TRAITS(ns::hiking_reputation, application, reputons)

using namespace jsoncons; // for convenience

int main()
{

std::string data = R"(
    {
       "application": "hiking",
       "reputons": [
       {
           "rater": "HikingAsylum",
           "assertion": "advanced",
           "rated": "Marilyn C",
           "rating": 0.90
         }
       ]
    }
)";

    // Decode the string of data into a c++ structure
    ns::hiking_reputation v = decode_json<ns::hiking_reputation>(data);

    // Iterate over reputons array value
    std::cout << "(1)\n";
    for (const auto& item : v.reputons())
    {
        std::cout << item.rated() << ", " << item.rating() << "\n";
    }

    // Encode the c++ structure into a string
    std::string s;
    encode_json<ns::hiking_reputation>(v, s, indenting::indent);
    std::cout << "(2)\n";
    std::cout << s << "\n";
}

输出:

 (1)
Marilyn C, 0.9
(2)
{
    "application": "hiking",
    "reputons": [
        {
            "assertion": "advanced",
            "rated": "Marilyn C",
            "rater": "HikingAsylum",
            "rating": 0.9
        }
    ]
}

原文由 Daniel 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题