13

I'm trying to create a json using rapidjson and I am having some unexpected problems with generating a proper output.

I'm creating and populating a document like this:

Document d;
d.SetObject();

rapidjson::Document::AllocatorType& allocator = d.GetAllocator();

size_t sz = allocator.Size();

d.AddMember("version",  1, allocator);
d.AddMember("testId",   2, allocator);
d.AddMember("group",    3, allocator);
d.AddMember("order",    4, allocator);

Value tests(kArrayType);
Value obj(kObjectType);
Value val(kObjectType);

obj.AddMember("id", 1, allocator);

string description = "a description";
val.SetString(description.c_str(), static_cast<SizeType>(description.length()), allocator);
obj.AddMember("description", val, allocator);

string help = "some help";
val.SetString(help.c_str(), static_cast<SizeType>(help.length()), allocator);
obj.AddMember("help", val, allocator);

string workgroup = "a workgroup";
val.SetString(workgroup.c_str(), static_cast<SizeType>(workgroup.length()), allocator);
obj.AddMember("workgroup", val, allocator);

val.SetBool(true);
obj.AddMember("online", val, allocator);

tests.PushBack(obj, allocator);
d.AddMember("tests", tests, allocator);

// Convert JSON document to string
rapidjson::StringBuffer strbuf;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(strbuf);
d.Accept(writer);

When I run this code, I'm expecting to obtain this json:

{
    "version": 1,
    "testId": 2,
    "group": 3,
    "order": 4,
    "tests": [
        {
            "id": 1,
            "description": "a description",
            "help": "some help",
            "workgroup": "a workgroup",
            "online": true
        }
    ]
}

but the actual generated output is...

{
    "version": 1,
    "testId": 2,
    "group": 3,
    "order": 4,
    "tests": [
        {
            "id": 1,
            "description": "a description",
            "help": "some help",
            "workgroup": "a workgroup",
            "online": tr{
    "version": 1,
    "testId": 2,
    "group": 3,
    "order": 4,
    "tests": [
        {
            "id": 1,
            "description": "a description",
            "help": "some help",
            "workgroup": "a workgroup",
            "online": true
        }
    ]
}

Any ideas?

André Moreira
  • 1,669
  • 4
  • 21
  • 35
  • Do you have to do that ``allocator`` magic? Or are there also overloads where you can build the DOM without them? My gut tells me, this looks a bit off. – BitTickler Mar 01 '16 at 16:17
  • Apart from that, you re-use the same ``val`` instance multiple times. Maybe this is a non-use-case. – BitTickler Mar 01 '16 at 16:21
  • From what I can tell, I can only remove the allocator from the SetString calls and that has no effect. About reusing val, I had already tried without reusing it and the result is the same as well. – André Moreira Mar 01 '16 at 16:30
  • That being said, if I remove one of the entries in the json creation I get what I would expect, which seems to point to the allocator, but this is the only way I have seen this being used in the documentation. – André Moreira Mar 01 '16 at 16:31
  • Within 2 hours I created my own tiny JSON builder code, which allows cool document composition and has none of the cryptic elements of the code you show here. Admitted, it is not optimized for speed, it is using recursion, which could be an issue for huge documents (stack overflow). But if all you want is to write some readable c++ json object construction code, I would use my 2 hour effort rather than some library. I can post it somewhere if you are interested. – BitTickler Mar 01 '16 at 19:11
  • Just in case... and I wanted to test gist for a while now: https://gist.github.com/ruffianeo/58f8c64cbbefc41dec8f – BitTickler Mar 01 '16 at 20:27
  • Two hours well spent ;). The app I'm working in already uses rapidjson for handling loading json files and it stands to reason that it should be able to do something as simple as this without any problem. I did think about writing something simple for the output part (you already saved me that time), but I'm a stickler for understanding what the problem is so I'll keep on it for bit more. – André Moreira Mar 02 '16 at 08:26
  • Hi. I am the author of RapidJSON. I just tried to run your code and it runs perfectly. `strbuf.GetString()` returns the results as you expected. – Milo Yip Mar 02 '16 at 10:21
  • @Candag Your solution is interesting but it does not handle many standard of JSON, such as string escaping, number syntax, etc. RapidJSON's DOM API may be difficult to use, compared to many libraries, due to some design decisions for performance and memory considerations. RapidJSON also supports [JSON Pointer](http://rapidjson.org/md_doc_pointer.html) to manipulate DOM. – Milo Yip Mar 02 '16 at 10:25
  • Hello Milo and thanks for taking the time to answer. I tried the same example in a standalone application and it works as expected. But when I run the same code as part of my application, I get that weird output. To rule out memory corruption, this code is the first thing I'm running in InitInstance() (this is an MFC application). So I'm either breaking the document when I am adding members or it's causing an issue with the Writer. BTW the same example with Writer instead produces a valid output, but will fail if I add more members. – André Moreira Mar 02 '16 at 11:03
  • @Milo you are probably talking about the code that BitTickler wrote. – André Moreira Mar 02 '16 at 11:04
  • My guess would be some other part of your application corrupts either your stack or your heap or whatever memory. – BitTickler Mar 02 '16 at 19:16
  • This was the greatest question ever. Very useful to me. I wish I could up-vote it twice. – Michele Apr 19 '17 at 12:39

1 Answers1

6

In the end I managed to track the problem down to the way I was outputing the string with OutputDebugString in VS. If I saved the resulting string (given by GetString()), the output was as expected!

Foiled by the debug trap I was!

André Moreira
  • 1,669
  • 4
  • 21
  • 35