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