-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add json serialization/deserialization support for c++ generator #99
Add json serialization/deserialization support for c++ generator #99
Conversation
Awesome! Thanks a lot!! It will take me some time to look through that but it seems nice on a first glance. One question I have is, how tight is the coupling to nlohmann/json? I was never a fan of that library since it's slow in every aspect, and the only selling point was a modern interface back then when c++11 was modern. I think the decision we make now for the serializer lib will stick with us, so I would at least highlight this question since we are going to introduce dependencies. The other thing is, I wonder if we could get somehow some usage example. |
Ahhhh, yes, well, the coupling is pretty tight. hiennguyenle was using nlohmann's If we used the more flexible approach of putting the
Fair enough.
Yes, I agree - of course I tested the generated code in my own toy project - but I wasn't sure where such a project should be included in the djinni-generator repo. |
Hi, My suggestion is to use quotes instead of "<...>" to follow other headers pattern. Thanks. |
Is this with reference to the |
I have a little bit of a high workload this week and not sure how much time I am able to invest into my favorite spare time projects. But as a question and thought experiment: Do you think it would be possible to have an implementations like
and if future we might have , for example
and kind of 'hotsap' the json detail implementation at generation time We do not need an other implementation right now, but just conceptually preparing this kind of flexibility, so we can control that option in future and don't close the door for users that might use already other json frameworks in their project. |
I do not think that should change since this is a 3rd party header and should be threaded as a system header |
This makes sense to me, and isn't too onerous to do now. If more json libraries are added, it seems to me that it will be a bit ugly to continue shove them also into |
Wow! It is nice! |
Thanks for adding the flexibility option! Making it more pretty once we might have multiple json lib support is a future problem. After a first glance, I think this looks good. It would be an awesome addition to have some doc with some small usage example, or any other way that can show people how to have an easy start into using that feature. |
1e1a241
to
ff987f0
Compare
This looks good, @mutagene , thanks a lot! |
@a4z C++ JSON Serialization supportSerialization from C++ types to/from JSON is supported. This feature is currently only enabled for #include "my_record.hpp"
#include "my_record+json.hpp"
#include <iostream>
#include <nlohmann/json.hpp>
void foo(const my_record& record) {
// convert record to json object
nlohmann::json j = record;
// dump serialized string
std::cerr << j.dump(4);
// create new instance of record from json object
my_record cloned = j.get<my_record>();
} I'd be happy to add a working example except I feel that could be quite a rabbit hole as there is currently no infrastructure in this repo for adding c++ executable apps/tests. |
@a4z
vs
|
hm, don't know, if the resource gets embedded into the deliverable, and we still have 1 file to distribute, I do not have strong opinion, but I could imagine it might the be better to do it like that (as embedded resource) |
Ok; done. |
Just a note: I added the serialisation/deserialisation for flags. I had missed this before, and I guess it fell through the cracks in part because the record in the all_datatypes integration test doesn't have a flags field. I've added this for the json integration test and validated the implementation with clang 12. Whereas enums translate c++ enums into strings, flags translate into an array of strings in the resulting json. As with enums, the purpose being to create something human readable. |
I am sorry to tell you that there are now some merge conflicts. I guess the best way to solve them is to just add the changes that add scalafmt into your codebase, run the formatter over the source code, and then merge the rest of the main branch. If you need any help, please let me know. |
Adapted from hiennguyenle's work in https://github.com/hiennguyenle/finn * Allow json serializer to be specified in djinni options, with only nlohmann currrently implemented * Update documentation for json serialization * Add trivial usage example for cpp serialization/deserialization * Update to generate json+extension.hpp for nlohmann/json
afe7712
to
24f8017
Compare
Is anything else required on my end for this PR / any requests or further reservations? I'm looking forward to hopefully getting this to replace a lot of handwritten |
Sorry for being that slow at the moment @mutagene Will try to catch up asap. |
Same here, I'm planning to do a full review this week (hopefully)! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks a lot!
I did some quick tests, generating a simple record and enum, they seem to serialise and de-serialise nicely.
And I like that the enum value gets the name of the enum value in the output!
Please just check the generated records includes, I think there is no need to include the xml serialisation on that place.
If you do not use the json functionality, you should be able to not have any dependency to any json lib, only if you include the +json header, you should need that.
Otherwise I think it looks very good!
src/it/resources/expected/all_datatypes_json/cpp-headers/all_datatypes_json.hpp
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me, and is also successfully running with some local sample code that is very close to the doc. good stuff!
It would be nice if we could find some solution for the time_point, but I think it's OK to solve that in future if we can't find something good now.
Thanks a lot for this great PR!
Hi, I made time_point parser for datetime fields here: and Maybe it can help. |
Thanks Paulo! I think the topic has some potential for upfront thoughts, and this is why Alexis did right to not implement anything. imho, the question is:
and we can take the human readable date time and transform it from and to C++ Until I we have an anser for this we will take the code as it is, except anyone has an opinion that instead of implementing nothing we should do a "N/A" or so. I am fine with as it is now, and solve that in future when we might have more user feedback, |
@mutagene , a SwedenCpp user group colleague , @bigdavedev , shared that with me |
Ahh, nice - yes, that's quite lovely. |
I would like to point out that the snippet I provided relies on both |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much for this PR! I was sceptical at first but now that I tried it out and given the fact that it also supports deserialization I could even see myself (ab)using this new feature for more than just logging... ;)
I'm not sure if this has been discussed before, but I remember @freitass proposing to provide overwrites for operator<<
as well, to make logging even more convenient? This doesn't necessarily need to happen in this PR, but what do you think about the idea in general?
s"--idl src/it/resources/${idlFile}.djinni --cpp-namespace custom_namespace --cpp-json-serialization nlohmann --cpp-out $outputPath/cpp --cpp-header-out $outputPath/cpp-headers" | ||
) | ||
Then( | ||
"the generator should successfully generate just objc output and write all generate files to the given path, including headers" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"the generator should successfully generate just objc output and write all generate files to the given path, including headers" | |
"the generator should successfully generate just C++ output and write all generated files to the given path, including headers" |
I'm not sure though that this is what you want to test here? The it
call implies that this is about testing that the correct namespace is applied for the json extension?
To me it seems like testing that all expected files are generated (including the extension) has already been covered by it("Should generate json serializers for all data types")
?
Can you try to reduce the scope of this test case or be more specific in the test description (it, when, then) what this test is about, if possible? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right - the only data types that had to be tested were record, enum and flag, as their fully qualified names should appear in their corresponding adl_serializer
s.
be4db11
to
5d7fc07
Compare
- check --cpp-json-serialization; report error if invalid - narrow unit tests - add json de/serialization for date using Howard Hinnant's date.h header-only library
5d7fc07
to
6ee9912
Compare
That sounds pretty handy, but as I'm not using the |
I really would like to merge that PR already, since I think it has been long enough in the review process and I find it good. But I have one concern now, with the change that dropped in over the weekend. While it is nice, it might be unwanted. Also, this is just 1 possible implementation. Paulo showed an other one, that might be preferred by some users, and there are for sure more. (E.G, setting a user defined time zone on the date) Therefore I think the best place to provide the date implementation is the documentation, and have no json to date conversion at all. If the user wants one, adding (a small header with) the required template specialization is an easy task. All a user would have to do is basically add a
before the usage of it in , e.g. (from the docs)
and it will just work. If that happens inline, or via a header ... Therefore I seriously think the best way would be to have no implementation for
Therefore I think the date implementation is good, but should possible be in the docs. Thoughts? |
I was thinking a bit the same when I made the last commit. On the other hand, if we don't provide an implementation at all, then projects using I guess one solution could be to take @paulo-coutinho's solution and make this the default. If someone wanted to override it with the
-- although this would have to be included before |
I am super happy we have the same point of view!
That could be fine , to get a compiler error, but maybe there is one more way
Since we are in C++ land, we can always decorate something with defines to remove it 😁
and then this
is not a problem anymore I will add that as review suggestions. I think with such adoption we should be done. Great discussion leading to awesome improvements and a real powerful library feature. Thanks a lot !! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I drafted the change to make the default json date converter optional
* use simple date serializer as default, with compilation flag to disable and allow custom serializers * provide custom sample serializer in docs which uses hinnant/date library for human readable dates * add credit to hiennguyenle/finn in source
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome!
I think we are fine, if something left we can add that as extra issues for the future.
Thank you so much @mutagene , great work and great collaboration!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many thanks from me as well, @mutagene !
Your PR has been a pleasure to review. Looking forward to future collaboration! 😊
I've got some minor final feedback, but all in all this looks great!
@@ -16,6 +16,7 @@ Djinni generator parses an interface definition file and generates: | |||
- Python implementation of types | |||
- C++/CLI implementation of types | |||
- C++ code to convert between C++ and Java over JNI | |||
- C++ code to serialize/deserialize types to/from JSON |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI you may want to update the feature list on the gitpage as well: https://github.com/cross-language-cpp/cross-language-cpp.github.io/blob/main/docs/overview.md#main-features
This will show up here on the documentation website. :)
Co-authored-by: jothepro <github@jothe.pro>
Co-authored-by: jothepro <github@jothe.pro>
I could not await to merge that, so I accelerated the last things and merged :-) |
Adapted from @hiennguyenle's work in https://github.com/hiennguyenle/finn.
Unlike Hien Nguyen Le's work, this PR does not introduce a JSON type which can be marshalled across language boundaries - in this PR, the JSON serialisation is strictly used to serialise and deserialise from the c++ datatypes.
Because my purpose in creating this PR was primarily to allow human-friendly representation of DJINNI datatypes for e.g. logging, enums are serialized to strings (which correspond to their names in the IDL). In keeping with Hien Ngyuyen Le's work, the deserialisation layer is also maintained - although I'm not as clear on its use case.
This PR does not include thejson+extension.hpp
required forstd::optional
support from Hien Nguyen Le's json PR as that would have to be included in thedjinni-support-lib
.json+extension.hpp
required for serializingstd::optional
, as in Hien Nguyen Le's implementation, is produced by the generator if the c++ json extension is enabled.