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?
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());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With