netheril96 / StaticJSON

Fast, direct and static typed parsing of JSON with C++

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add support for RapidJSON DOM members

ecorm opened this issue · comments

I would find it useful to be able to deserialize the "static" part of a JSON object into a C++ struct, but still have access to members of complex, dynamic types. For example, for this JSON definition:

{
    "name": "Record",
    "members":
    [
        ["std::string", "id", {"required": true}],
        ["unsigned long", "revision"],
        ["rapidjson::Document", "document"]
    ]
}

the resulting C++ struct would look like this:

struct Record
{
    std::string key;
    unsigned long revision;
    rapidjson::Document document;
};

The document member above would allow me to treat the "document" sub-object as a dynamic JSON value.

See Tencent/rapidjson#147.

But this is still doable. I can write my own handler, bypassing the internals of rapidjson. But I need to know if there are any other types that you think should be supported as dynamic JSON objects. That way, I may come up with a more general approach so it can be extended easily.

Implemented in 253eabf, along with to_document and from_document.

Thank you, it's working nicely so far. I had attempted to write my own SAXEventHandler, but yours is much nicer. :-)

With regards to other dynamic types that can model JSON, you might consider:

  • recursive boost::variant
  • composite boost::any

For the boost::variant approach, I've seen forum postings where they say boost::container helps them get around the problem of standard containers not supporting incomplete types.

If I try to parse into a std::vector<Record> (see first post for an example of Record), I get the following error:

.../autojsoncxx/array_types.hpp:57: error: use of deleted function 'Record& operator=(Record&&)'
             current = ElementType();
                     ^
.../record.hpp:30: 'Record& operator=(Record&&)' is implicitly deleted because the default definition would be ill-formed:
struct Record {
       ^

I'm guessing that Record's move assignment operator was implicitly deleted because in rapidjson::Document, it is also implicitly deleted. rapidjson::Document currently does not support move semantics. See Tencent/rapidjson#123.

I was able to work around this problem by parsing into a std::vector<std::unique_ptr<Record>>. Is it possible for autojsoncxx to provide some workaround that doesn't force the Record to be dynamically allocated by std::unique_ptr?

Instead of wasting time on workarounds, I decided to go ahead and implement move semantics for rapidjson::Document. I should be making a pull request to RapidJSON's maintainer in the next few days.

Fix on my part is not possible, because if this line is fixed, you will still get a compile time error when the element is inserted into the container. Both push_back and emplace_back requires the element type to be MoveConstructible or CopyConstructible because they may expand the vector.

Smart pointers and patching rapidjson::Document are indeed the only two recourses.

I case anyone's interested, the RapidJSON pull request is now pending: Tencent/rapidjson#173

My pull request has been merged in Tencent/rapidjson@1950efd.

rapidjson::GenericDocument now supports move semantics!

@ecorm

struct Record
{
    std::string key;
    unsigned long revision;
    rapidjson::Document document;
};

Are you sure this class can be handled by autojsoncxx? I didn't specialize SAXEventHandler or Serializer for unsigned long types.

That Record struct wasn't the actual one I used for testing; it was a simplified one I "made up" for discussion purposes. The one I'm actually using has an integer type autojsoncxx recognizes.