Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -839,9 +839,9 @@ Some important things:

#### Simplify your life with macros

If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. There are [**several macros**](https://json.nlohmann.me/features/arbitrary_types/#simplify-your-life-with-macros) to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object.
If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. There are [**several macros**](https://json.nlohmann.me/api/macros/#serializationdeserialization-macros) to make your life easier as long as you want to use a dedicated DTO for JSON serialization.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is a "dedicated DTO"?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's a "JSON object"? :) Same thing. But I will revert the terminology. When I tried to reword it "JSON" appeared too often, so I wanted to use something else.


Which macro to choose depends on whether private member variables need to be accessed, a deserialization is needed, missing values should yield an error or should be replaced by default values, and if derived classes are used. See [this overview to choose the right one for your use case](https://json.nlohmann.me/api/macros/#serializationdeserialization-macros).
Which macro to choose depends on whether private member variables need to be accessed, a deserialization is needed, missing values should yield an error or should be replaced by default values, and if derived classes are used. See [this overview to choose the right one for your use case](https://json.nlohmann.me/features/arbitrary_types/#simplify-your-life-with-macros).

##### Example usage of macros

Expand All @@ -853,6 +853,18 @@ namespace ns {
}
```

If you want to inherit the `person` struct and add a field to it, it can be done with:

```cpp
namespace ns {
struct person_derived : person {
std:string email;
};

NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(person_derived, person, email)
}
```

Here is another example with private members, where [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/) is needed:

```cpp
Expand All @@ -869,6 +881,24 @@ namespace ns {
}
```

Or in case if you use some naming convention that you do not want to expose to JSON:

```cpp
namespace ns {
class address {
private:
std::string m_street;
int m_housenumber;
int m_postcode;

public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_NAMES(address, "street", m_street,
"housenumber", m_housenumber,
"postcode", m_postcode)
};
}
```

#### How do I convert third-party types?

This requires a bit more advanced technique. But first, let's see how this conversion mechanism works:
Expand Down
25 changes: 25 additions & 0 deletions docs/mkdocs/docs/api/macros/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,28 @@ header. See also the [macro overview page](../../features/macros.md).
a derived class; uses default values
- [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE**](nlohmann_define_derived_type.md) - serialize a derived
class
- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize/deserialize a non-derived class
with private members; uses custom names
- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize/deserialize a
non-derived class with private members; uses default values; uses custom names
- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize a non-derived class
with private members; uses custom names
- [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize/deserialize a non-derived
class; uses custom names
- [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize/deserialize a
non-derived class; uses default values; uses custom names
- [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize a
non-derived class; uses custom names

- [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize/deserialize a derived class
with private members; uses custom names
- [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize/deserialize a
derived class with private members; uses default values; uses custom names
- [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize a derived
class with private members; uses custom names
- [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize/deserialize a derived
class; uses custom names
- [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize/deserialize
a derived class; uses default values; uses custom names
- [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize a derived
class
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Summary:
: name of the base type (class, struct) `type` is derived from

`member` (in)
: name of the member variable to serialize/deserialize; up to 64 members can be given as comma-separated list
: name of the member variable to serialize/deserialize; up to 63 members can be given as comma-separated list

## Default definition

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Summary:
: name of the type (class, struct) to serialize/deserialize

`member` (in)
: name of the member variable to serialize/deserialize; up to 64 members can be given as comma-separated list
: name of the member variable to serialize/deserialize; up to 63 members can be given as comma-separated list

## Default definition

Expand All @@ -60,8 +60,8 @@ See examples below for the concrete generated code.

!!! warning "Implementation limits"

- The current implementation is limited to at most 64 member variables. If you want to serialize/deserialize types
with more than 64 member variables, you need to define the `to_json`/`from_json` functions manually.
- The current implementation is limited to at most 63 member variables. If you want to serialize/deserialize types
with more than 63 member variables, you need to define the `to_json`/`from_json` functions manually.

## Examples

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Summary:
: name of the type (class, struct) to serialize/deserialize

`member` (in)
: name of the (public) member variable to serialize/deserialize; up to 64 members can be given as comma-separated list
: name of the (public) member variable to serialize/deserialize; up to 63 members can be given as comma-separated list

## Default definition

Expand Down Expand Up @@ -61,8 +61,8 @@ See examples below for the concrete generated code.

!!! warning "Implementation limits"

- The current implementation is limited to at most 64 member variables. If you want to serialize/deserialize types
with more than 64 member variables, you need to define the `to_json`/`from_json` functions manually.
- The current implementation is limited to at most 63 member variables. If you want to serialize/deserialize types
with more than 63 member variables, you need to define the `to_json`/`from_json` functions manually.

## Examples

Expand Down
73 changes: 73 additions & 0 deletions docs/mkdocs/docs/api/macros/nlohmann_define_type_with_names.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# The Named Conversion Macros
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API pages always have the name of the function/macros as title.


```cpp
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_NAMES(type, "json_member_name", member...)
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(type, "json_member_name", member...)
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES(type, "json_member_name", member...)
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES(type, "json_member_name", member...)
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(type, "json_member_name", member...)
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES(type, "json_member_name", member...)
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_NAMES(type, base_type, "json_member_name", member...)
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(type, base_type, "json_member_name", member...)
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES(type, base_type, "json_member_name", member...)
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_NAMES(type, base_type, "json_member_name", member...)
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(type, base_type, "json_member_name", member...)
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES(type, base_type, "json_member_name", member...)
```
These macros can be used in case you want to use the custom names for the member variables in the resulting JSON.
They behave exactly as their non-`WITH_NAMES` counterparts, but require an additional parameter for each member variable
which will be used in JSON. Both serialization and deserialization will only use the custom names for JSON, the names of
the member variables themselves will be ignored.
Using the named conversion macros will halve the maximum number of member variables from 63 to 31.
For further information please refer to the corresponding macros without `WITH_NAMES`.
## Parameters
`type` (in)
: name of the type (class, struct) to serialize/deserialize
`base_type` (in)
: name of the base type (class, struct) `type` is derived from (used only in `DEFINE_DERIVED_TYPE` macros)
`json_member_name` (in)
: json name that will be used for the next member variable
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"json" -> "JSON"?

What is a "json name"?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How else would you call "a name which will be used for the corresponding value inside the JSON"?

Copy link
Contributor

@gregmarr gregmarr Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How else would you call "a name which will be used for the corresponding value inside the JSON"?

The string that will be used as the name [in the object] for the next value.

Could probably exclude the part in square brackets.

`member` (in)
: name of the member variable to serialize/deserialize
## Examples
??? example "Example (1): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES"
Consider the following complete example:
```cpp hl_lines="16"
--8<-- "examples/nlohmann_define_type_non_intrusive_with_names_macro.cpp"
```
Output:
```json
--8<-- "examples/nlohmann_define_type_non_intrusive_with_names_macro.output"
```
Notes:
- `ns::person` is default-constructible. This is a requirement for using the macro.
- `ns::person` has only public member variables. This makes `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES` applicable.
- The macro `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES` is used _outside_ the class, but _inside_ its namespace `ns`.
- A missing key "age" in the deserialization yields an exception. To fall back to the default value,
`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES` can be used.
The macro is equivalent to:
```cpp hl_lines="16 17 18 19 20 21 22 23 24 25 26 27 28"
--8<-- "examples/nlohmann_define_type_non_intrusive_with_names_explicit.cpp"
```
## Version history
1. Added in version 3.11.x.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;
using namespace nlohmann::literals;

namespace ns
{
struct person
{
std::string name;
std::string address;
int age;
};

template <typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int >= 0>
void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t) {
nlohmann_json_j["json_name"] = nlohmann_json_t.name;
nlohmann_json_j["json_address"] = nlohmann_json_t.address;
nlohmann_json_j["json_age"] = nlohmann_json_t.age;
}

template <typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int >= 0>
void from_json(const BasicJsonType& nlohmann_json_j, person& nlohmann_json_t) {
nlohmann_json_j.at("json_name").get_to(nlohmann_json_t.name);
nlohmann_json_j.at("json_address").get_to(nlohmann_json_t.address);
nlohmann_json_j.at("json_age").get_to(nlohmann_json_t.age);
}
} // namespace ns

int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};

// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;

// deserialization: json -> person
json j2 = R"({"json_address": "742 Evergreen Terrace", "json_age": 40, "json_name": "Homer Simpson"})"_json;
auto p2 = j2.template get<ns::person>();

// incomplete deserialization:
json j3 = R"({"json_address": "742 Evergreen Terrace", "json_name": "Maggie Simpson"})"_json;
try
{
auto p3 = j3.template get<ns::person>();
}
catch (const json::exception& e)
{
std::cout << "deserialization failed: " << e.what() << std::endl;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
serialization: {"json_address":"744 Evergreen Terrace","json_age":60,"json_name":"Ned Flanders"}
deserialization failed: [json.exception.out_of_range.403] key 'json_age' not found
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;
using namespace nlohmann::literals;

namespace ns
{
struct person
{
std::string name;

Check notice on line 11 in docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_names_macro.cpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_names_macro.cpp#L11

struct member 'person::name' is never used.
std::string address;

Check notice on line 12 in docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_names_macro.cpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_names_macro.cpp#L12

struct member 'person::address' is never used.
int age;

Check notice on line 13 in docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_names_macro.cpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_names_macro.cpp#L13

struct member 'person::age' is never used.
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES(person, "json_name", name, "json_address", address, "json_age", age)
} // namespace ns

int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};

// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;

// deserialization: json -> person
json j2 = R"({"json_address": "742 Evergreen Terrace", "json_age": 40, "json_name": "Homer Simpson"})"_json;
auto p2 = j2.template get<ns::person>();

// incomplete deserialization:
json j3 = R"({"json_address": "742 Evergreen Terrace", "json_name": "Maggie Simpson"})"_json;
try
{
auto p3 = j3.template get<ns::person>();
}
catch (const json::exception& e)
{
std::cout << "deserialization failed: " << e.what() << std::endl;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
serialization: {"json_address":"744 Evergreen Terrace","json_age":60,"json_name":"Ned Flanders"}
deserialization failed: [json.exception.out_of_range.403] key 'json_age' not found
Loading
Loading