Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rapidjson: add external sub-document to document

I want to serialize a nested structure to JSON using Rapidjson and I also want to be able to serialize each object separately, so any class that implements ToJson can be serialized to a JSON string.

In the following code, the Car has a Wheel member and both classes implement method ToJson, which populates a rapidjson::Document with all their members. This method is called from a function template, ToJsonString, to obtain a formatted JSON string of the passed object.

#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/stringbuffer.h"

template<typename T> std::string ToJsonString(const T &element)
{
    rapidjson::StringBuffer jsonBuffer;
    rapidjson::PrettyWriter<rapidjson::StringBuffer> jsonWriter(jsonBuffer);
    rapidjson::Document jsonDocument;
    element.ToJson(jsonDocument);
    jsonDocument.Accept(jsonWriter);

    return jsonBuffer.GetString();
}

struct Wheel
{
    std::string brand_;
    int32_t diameter_;

    void ToJson(rapidjson::Document &jsonDocument) const
    {
        jsonDocument.SetObject();
        jsonDocument.AddMember("brand_", brand_, jsonDocument.GetAllocator());
        jsonDocument.AddMember("diameter_", diameter_, jsonDocument.GetAllocator());
    }
};

struct Car
{
    std::string brand_;
    int64_t mileage_;
    Wheel wheel_;

    void ToJson(rapidjson::Document &jsonDocument) const
    {
        jsonDocument.SetObject();
        jsonDocument.AddMember("brand_", brand_, jsonDocument.GetAllocator());
        jsonDocument.AddMember("mileage_", mileage_, jsonDocument.GetAllocator());

        rapidjson::Document jsonSubDocument;
        wheel_.ToJson(jsonSubDocument);
        jsonDocument.AddMember("wheel_", rapidjson::kNullType, jsonDocument.GetAllocator());
        jsonDocument["wheel_"].CopyFrom(jsonSubDocument, jsonDocument.GetAllocator());
    }
};

As you can see, Car::ToJson calls Wheel::ToJson in order to obtain the description of Wheel and to add it as a sub-object, but I couldn't think of an acceptable solution to do this due to allocation management (I have also read the other questions).

The workaround that I found is to add a member in Car's jsonDocument with a random field value (in this case rapidjson::kNullType) and after that, to CopyFrom the Wheel's corresponding document.

How can I do this?

like image 438
Alexandru Irimiea Avatar asked Dec 24 '22 13:12

Alexandru Irimiea


1 Answers

This turned out to be more simple than I thought. From GitHub (issue 436):

The easiest solution to avoid the copy is to reuse the allocator of the outer document:

rapidjson::Document jsonSubDocument(&jsonDocument.GetAllocator());
wheel_.ToJson(jsonSubDocument);
jsonDocument.AddMember("wheel_", jsonSubDocument, jsonDocument.GetAllocator());
like image 157
Alexandru Irimiea Avatar answered Dec 27 '22 10:12

Alexandru Irimiea