Tencent / rapidjson

A fast JSON parser/generator for C++ with both SAX/DOM style API
http://rapidjson.org/
Other
14.26k stars 3.53k forks source link

Stringify/parse C++ objects like in JavaScript's JSON.stringify()/JSON.parse() #888

Closed spotlesscoder closed 6 years ago

spotlesscoder commented 7 years ago

As I don't want to code the whole serialization / deserialation of an object with many members by handling every value for that member, I want to have achieve this by calling one method. I would not like to do implement this for every class member because a) It takes too much time to implement b) Takes much effort to maintain if a class gets new members etc.

See this example: https://stackoverflow.com/questions/8220130/converting-c-class-to-json There is an answer (https://stackoverflow.com/a/19974486/4397899) that says ThorsSerializer would be able to do something like that, at least something more beautiful like handling every member value manually in code.

Is something similar to either JavaScript's JSON.stringify()/JSON.parse() or the way ThorsSerializer does it possible with rapidjson?

Best regards

StilesCrisis commented 7 years ago

C++ lacks struct reflection capabilities and fixing this is outside the scope of the Rapidjson project IMO.

If you look at the example you posted, ThorsSerializer requires an explicit macro to be used so you can manually list every class member. It's NOT automatic. This would be cumbersome for structs with many members. You could certainly write a macro like this for Rapidjson but I do not think it accomplishes your goal.

You might want to look at this Stackoverflow question, it has some useful insights that would be applicable to your app and could integrate with Rapidjson. http://stackoverflow.com/questions/41453/how-can-i-add-reflection-to-a-c-application

spotlesscoder commented 7 years ago

Thanks for the quick and helpful reply. I tried the code from the first answer. Unfortunately I am getting errors like "C2977 'boost::add_const': too many template arguments"

I googeled a bit. It might have to do with variadic templates. As I am using Visual Studio 2015 (MSVC14 compiler) it might have to do with this issue: https://stackoverflow.com/questions/8274588/c2977-stdtuple-too-many-template-arguments-msvc11

I tried to set _VARIADIC_MAX=10; for the preprocessor but it didn't help. I'm still a beginner in C++. Do you have an idea?

StilesCrisis commented 7 years ago

If you're a C++ beginner, trying to simulate reflection with boost and templates is probably a bad way to be spending your time; that's jumping in at the very deep end of the pool on a deep problem that doesn't have an elegant solution yet. Unfortunately I don't really have good advice for you (maybe try C# instead...??). Your best bet is to just write the serialization functions.

StilesCrisis commented 7 years ago

At any rate I don't think this is a Rapidjson issue to be fixed; it's a very well known C++ language weakness without a simple workaround. I would recommend closing this issue.

spotlesscoder commented 7 years ago

Unfortunately, I have to use C++. Thanks anyways

jgaa commented 7 years ago

I may (shamelessly) mention my own restc-cpp library, that does allow serialization of C++ objects directly to/from json.The serialization / deserialization is implemented as a template library, using rapidjson behind the scenes.

https://github.com/jgaa/restc-cpp

StilesCrisis commented 7 years ago

I do not really see how this addresses the question. There's no reflection here. You need to create a normal struct and then add a parallel structure which fakes the reflection: BOOST_FUSION_ADAPT_STRUCT( Post, (int, userId) (int, id) (string, title) (string, body) )

This makes sense because, as I said in the beginning, C++ doesn't offer reflection. But your library doesn't address the question at all.

jgaa commented 7 years ago

Sorry. I read the question as the op was looking for a convenient way to serialize C++ objects without having to code the serialization manually for each object. It's correct that C++ does not offer refection - and it's an absolute constraint in this context. I think QT partially solves this, and there are other solutions as well. However, the BOOST_FUSION_ADAPT_STRUCT is the most lightweight and generally available work-around I have found. What my library does, is to take it from there and do the serialization both ways, recursively if required. (I have seen a solution for C++ reflection solved in one of the largest software companies in the world, implemented in a way that required man-years of coding and hundreds of hours spent every year in maintenance.)

Doing C++ serialization with rapidjson for specific C++ classes is easy. Doing it in a generic way, supporting all the three major C++ compliers (yes Microsoft, I am looking at you), is hard, even with the fake reflection that boost::fusion provides. I spent the time to solve that problem, using template meta-programming and rapidjson, and with the fake reflection - I achieve to make C++ json serialization trivial.

spotlesscoder commented 7 years ago

From the first look this is exactly what I want.

I will report how it works when I can build restc-cpp

spotlesscoder commented 6 years ago

Switched to another library. But I think I made it work with rapidjson, too. Quite long ago already so I don't remember exactly

miloyip commented 6 years ago

Please check if #1138 is useful for you. Comments are welcome.

spotlesscoder commented 6 years ago

Sorry. Don't have time for that at the moment

xyz347 commented 6 years ago

try this https://github.com/xyz347/x2struct

Martchus commented 6 years ago

Or try Reflective RapidJSON which can either use Boost.Hana or a Clang-based code generator to generate (de)serialization code. Note that the project is still experimental.

spotlesscoder commented 6 years ago

OK, thanks. Issue is resolved for me now :) Having other projects on my Agenda now

nicktrandafil commented 6 years ago

Take a look https://github.com/nicktrandafil/rproject