-
-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
Allow default values for NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE #2819
Conversation
…DEFINE_TYPE_NON_INTRUSIVE
It failed unit test "unit-udt_macro.cpp" as line 256 expects an exception is thrown. No idea if this behavior should be changed. |
This would be a breaking change, hence the tests fail. Best would be to introduce a new macro, though I'm not sure what a good name could be. |
This change also requires that the destination type be default constructible, which I believe is explicitly not a requirement currently. |
…NE_TYPE_NON_INTRUSIVE; added new macros NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
Changes to old macros are reverted and new macros are added witih passed unit tests, which are
|
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.
…MANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT accordingly
Done. |
@@ -291,6 +296,10 @@ | |||
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ | |||
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } | |||
|
|||
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ | |||
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ | |||
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } |
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 was thinking that having default_obj
be const static
would save constructing and destructing this object on every pass through the function, but there could be reasons that users wouldn't want that. I suppose that this is just something that users will need to be aware of.
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.
Making it const static
sounds a good idea. Any specific reason for not wanting that?
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.
Nothing in general, just could be specific use cases where having a long-lived one of these would be a problem for people.
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.
Thinking about this, I also think having a long-lived object to be surprising.
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.
nlohmann_json_t
is already default constructed. The WITH_DEFAULT
macros can just not set it if the key is missing, and then no Type default_obj;
is needed.
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.
That's not necessarily true. We ran into situations recently where to_json
was called on a json
object that already had a value, and the functions didn't clear it properly, resulting in a memory leak.
doc/mkdocs/docs/features/macros.md
Outdated
@@ -79,6 +79,10 @@ The first parameter is the name of the class/struct, and all remaining parameter | |||
|
|||
See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example. | |||
|
|||
## `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...)` | |||
|
|||
This macro is similar to `NLOHMANN_DEFINE_TYPE_INTRUSIVE` but will throw no exceptions. When converting JSON object to type object, if any field is missing in JSON object, it will use default value constructed by the type itself. |
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'm thinking this should call out that it requires that the type be default constructible and that it constructs an object inside the from_json()
function. I think it may also still throw exceptions if the types don't match.
Perhaps something like this:
This macro is similar to NLOHMANN_DEFINE_TYPE_INTRUSIVE
. It will not throw an exception in from_json()
due to a missing value in the JSON, but can throw due to a mismatched type. In order to support that it requires that the type be default constructible. The from_json()
function default constructs an object and uses its values as the defaults when calling the value()
function.
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.
Sounds better, thanks. Already updated.
…OHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
|
||
In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. | ||
In all macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. You can read more docs about them starting from [here](https://github.com/nlohmann/json/blob/develop/doc/mkdocs/docs/features/macros.md#nlohmann_define_type_intrusivetype-member). |
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.
In all macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. You can read more docs about them starting from [here](https://github.com/nlohmann/json/blob/develop/doc/mkdocs/docs/features/macros.md#nlohmann_define_type_intrusivetype-member). | |
In all macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. You can read more docs about them starting from [here](macros.md#nlohmann_define_type_intrusivetype-member). |
doc/mkdocs/docs/features/macros.md
Outdated
@@ -79,6 +79,10 @@ The first parameter is the name of the class/struct, and all remaining parameter | |||
|
|||
See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example. | |||
|
|||
## `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...)` | |||
|
|||
This macro is similar to `NLOHMANN_DEFINE_TYPE_INTRUSIVE`. It will not throw an exception in `from_json()` due to a missing value in the JSON, but can throw due to a mismatched type. In order to support that it requires that the type be default constructible. The `from_json()` function default constructs an object and uses its values as the defaults when calling the `value()` function. |
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 macro is similar to `NLOHMANN_DEFINE_TYPE_INTRUSIVE`. It will not throw an exception in `from_json()` due to a missing value in the JSON, but can throw due to a mismatched type. In order to support that it requires that the type be default constructible. The `from_json()` function default constructs an object and uses its values as the defaults when calling the `value()` function. | |
This macro is similar to `NLOHMANN_DEFINE_TYPE_INTRUSIVE`. It will not throw an exception in `from_json()` due to a missing value in the JSON object, but can throw due to a mismatched type. In order to support that it requires that the type be default constructible. The `from_json()` function default constructs an object and uses its values as the defaults when calling the `value()` function. |
doc/mkdocs/docs/features/macros.md
Outdated
@@ -88,6 +92,10 @@ The first parameter is the name of the class/struct, and all remaining parameter | |||
|
|||
See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example. | |||
|
|||
## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, member...)` | |||
|
|||
This macro is similar to `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`. It will not throw an exception in `from_json()` due to a missing value in the JSON, but can throw due to a mismatched type. In order to support that it requires that the type be default constructible. The `from_json()` function default constructs an object and uses its values as the defaults when calling the `value()` function. |
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 macro is similar to `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`. It will not throw an exception in `from_json()` due to a missing value in the JSON, but can throw due to a mismatched type. In order to support that it requires that the type be default constructible. The `from_json()` function default constructs an object and uses its values as the defaults when calling the `value()` function. | |
This macro is similar to `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`. It will not throw an exception in `from_json()` due to a missing value in the JSON object, but can throw due to a mismatched type. In order to support that it requires that the type be default constructible. The `from_json()` function default constructs an object and uses its values as the defaults when calling the `value()` function. |
|
||
- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for. | ||
- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members. | ||
- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for. |
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.
It would be good to add a comment about the difference to the previous macros.
Furthermore, the order should be.
- NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
- NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
- NLOHMANN_DEFINE_TYPE_INTRUSIVE
- NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT
@@ -291,6 +296,10 @@ | |||
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ | |||
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } | |||
|
|||
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ | |||
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ | |||
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } |
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.
It might be safer to add nlohmann_json_
as prefix to default_obj
to avoid name clashes.
@@ -59,6 +59,42 @@ class person_with_private_data | |||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name, metadata) | |||
}; | |||
|
|||
class person_with_private_data_2 |
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.
Do you actually test how JSON objects with missing values are serialized?
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.
Test added.
Why is this PR still not merged yet after so many days? All including docs are already editted as sugguested. |
Because this is a side project of mine and i did not find the time to check your last changes. |
I messed up the CI lately, I'm sorry. Can you please update to the latest |
Do you mean I make an empty commit to trigger the CI? |
Just update your branch and commit the changes. |
I was surprised to find this just as I made my own macro for pretty much the same thing. I'd love for this to get merged in. Here was my attempt on it
|
* ♻️ split Unicode tests
* 🔥 clean CMake files and Makefile * 💡 update documentation
I'm confused - did you update to the latest develop branch? |
Yes, I pulled latest develop branch, and rebased. |
I am confused, because the diff now shows me changes in 51 files. 🤔 |
I still have no idea that if this works or not. But from the README.md that macro does'nt work at all. Or is it in progress ? |
No, this PR is not yet merged. |
Hey @harry75369, can you please fix the branch by updating it to the latest develop branch? |
Any update on this? I really like the macros for backward compatibility. Please let me know if there's anything I can help with to get it merged. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Still not merged? Those macros are really usefull! |
The PR needs to be rebased. Can you do this, @harry75369 ? |
Hi Nils! |
Can be closed as #3143 is merged. Thanks a lot everybody! |
These two macros use
json::at
for deserializing from json to obj, but it will throw exceptions and is not good for backward-compatibility if the struct adds new fields but the json is still unchanged.This simple patch uses the default value from struct type (the type should be default constructible), and use
json::value
to set default value if some fileds is missing in json value. Hope it helps.Pull request checklist
Read the Contribution Guidelines for detailed information.
include/nlohmann
directory, runmake amalgamate
to create the single-header filesingle_include/nlohmann/json.hpp
. The whole process is described here.