Skip to content

Commit 0d325fd

Browse files
EinarsNGslowriot
authored andcommitted
Add ONLY_SERIALIZE for NLOHMANN_DEFINE_DERIVED_TYPE_* macros (nlohmann#4562)
1 parent 8d1f75b commit 0d325fd

File tree

6 files changed

+96
-11
lines changed

6 files changed

+96
-11
lines changed

docs/mkdocs/docs/api/macros/nlohmann_define_derived_type.md

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
<h1>NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT,
2-
NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT</h1>
2+
NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE,
3+
NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE</h1>
34

45
```cpp
5-
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(type, base_type, member...) // (1)
6-
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(type, base_type, member...) // (2)
6+
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(type, base_type, member...) // (1)
7+
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(type, base_type, member...) // (2)
8+
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(type, base_type, member...) // (3)
79

8-
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(type, base_type, member...) // (3)
9-
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, base_type, member...) // (4)
10+
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(type, base_type, member...) // (4)
11+
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, base_type, member...) // (5)
12+
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(type, base_type, member...) // (6)
1013
```
1114
1215
These macros can be used to simplify the serialization/deserialization of derived types if you want to use a JSON
1316
object as serialization and want to use the member variable names as object keys in that object.
1417
15-
- Macros 1 and 2 are to be defined **inside** the class/struct to create code for.
18+
- Macros 1, 2 and 3 are to be defined **inside** the class/struct to create code for.
1619
Like [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](nlohmann_define_type_intrusive.md), they can access private members.
17-
- Macros 3 and 4 are to be defined **outside** the class/struct to create code for, but **inside** its namespace.
20+
- Macros 4, 5 and 6 are to be defined **outside** the class/struct to create code for, but **inside** its namespace.
1821
Like [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](nlohmann_define_type_non_intrusive.md),
1922
they **cannot** access private members.
2023
@@ -48,14 +51,20 @@ friend void to_json(nlohmann::json&, const type&);
4851
friend void from_json(const nlohmann::json&, type&);
4952
```
5053

51-
Macros 3 and 4 add two functions to the namespace which take care of the serialization and deserialization:
54+
Macros 4 and 5 add two functions to the namespace which take care of the serialization and deserialization:
5255

5356
```cpp
5457
void to_json(nlohmann::json&, const type&);
5558
void from_json(const nlohmann::json&, type&);
5659
```
5760
58-
In both cases they call the `to_json`/`from_json` functions of the base type
61+
Macros 3 and 6 add one function to the namespace which take care of the serialization only:
62+
63+
```cpp
64+
void to_json(nlohmann::json&, const type&);
65+
```
66+
67+
In first two cases cases they call the `to_json`/`from_json` functions of the base type
5968
before serializing/deserializing the members of the derived type:
6069

6170
```cpp
@@ -73,12 +82,24 @@ void from_json(const nlohmann::json& j, B& b) {
7382
}
7483
```
7584
85+
In the third case only `to_json` will be called:
86+
87+
```cpp
88+
class A { /* ... */ };
89+
class B : public A { /* ... */ };
90+
91+
void to_json(nlohmann::json& j, const B& b) {
92+
nlohmann::to_json(j, static_cast<const A&>(b));
93+
// ...
94+
}
95+
```
96+
7697
## Notes
7798

7899
!!! info "Prerequisites"
79100

80-
- Macros 1 and 2 have the same prerequisites of NLOHMANN_DEFINE_TYPE_INTRUSIVE.
81-
- Macros 3 and 3 have the same prerequisites of NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE.
101+
- Macros 1, 2 and 3 have the same prerequisites of NLOHMANN_DEFINE_TYPE_INTRUSIVE.
102+
- Macros 4, 5 and 6 have the same prerequisites of NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE.
82103
- Serialization/deserialization of base types must be defined.
83104

84105
!!! warning "Implementation limits"

docs/mkdocs/docs/features/macros.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,10 @@ See [full documentation of `JSON_USE_IMPLICIT_CONVERSIONS`](../api/macros/json_u
102102

103103
## `NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(type, base_type, member...)`
104104
## `NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(type, base_type, member...)`
105+
## `NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(type, base_type, member...)`
105106
## `NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(type, base_type, member...)`
106107
## `NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, base_type, member...)`
108+
## `NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(type, base_type, member...)`
107109

108110
## `NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)`
109111

docs/mkdocs/mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,10 @@ nav:
287287
- 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON': api/macros/json_use_legacy_discarded_value_comparison.md
288288
- 'NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE': api/macros/nlohmann_define_derived_type.md
289289
- 'NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT': api/macros/nlohmann_define_derived_type.md
290+
- 'NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_derived_type.md
290291
- 'NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE': api/macros/nlohmann_define_derived_type.md
291292
- 'NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT': api/macros/nlohmann_define_derived_type.md
293+
- 'NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_derived_type.md
292294
- 'NLOHMANN_DEFINE_TYPE_INTRUSIVE': api/macros/nlohmann_define_type_intrusive.md
293295
- 'NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT': api/macros/nlohmann_define_type_intrusive.md
294296
- 'NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE': api/macros/nlohmann_define_type_non_intrusive.md

include/nlohmann/detail/macro_scope.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,9 @@
442442
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
443443
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
444444

445+
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \
446+
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
447+
445448
/*!
446449
@brief macro
447450
@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE
@@ -455,6 +458,9 @@
455458
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
456459
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
457460

461+
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \
462+
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
463+
458464
// inspired from https://stackoverflow.com/a/26745591
459465
// allows to call any std function as if (e.g. with begin):
460466
// using std::begin; begin(x);

single_include/nlohmann/json.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2809,6 +2809,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP
28092809
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
28102810
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
28112811

2812+
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \
2813+
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
2814+
28122815
/*!
28132816
@brief macro
28142817
@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE
@@ -2822,6 +2825,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP
28222825
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
28232826
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
28242827

2828+
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \
2829+
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
2830+
28252831
// inspired from https://stackoverflow.com/a/26745591
28262832
// allows to call any std function as if (e.g. with begin):
28272833
// using std::begin; begin(x);

tests/src/unit-udt_macro.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,32 @@ class person_without_default_constructor_2
440440

441441
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(person_without_default_constructor_2, name, age)
442442

443+
class derived_person_only_serialize_public : public person_without_default_constructor_1
444+
{
445+
public:
446+
std::string hair_color;
447+
448+
derived_person_only_serialize_public(std::string name_, int age_, std::string hair_color_)
449+
: person_without_default_constructor_1(std::move(name_), age_)
450+
, hair_color(std::move(hair_color_))
451+
{}
452+
};
453+
454+
NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(derived_person_only_serialize_public, person_without_default_constructor_1, hair_color)
455+
456+
class derived_person_only_serialize_private : person_without_default_constructor_1
457+
{
458+
private:
459+
std::string hair_color;
460+
public:
461+
derived_person_only_serialize_private(std::string name_, int age_, std::string hair_color_)
462+
: person_without_default_constructor_1(std::move(name_), age_)
463+
, hair_color(std::move(hair_color_))
464+
{}
465+
466+
NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(derived_person_only_serialize_private, person_without_default_constructor_1, hair_color)
467+
};
468+
443469
} // namespace persons
444470

445471
TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE", T, // NOLINT(readability-math-missing-parentheses)
@@ -657,3 +683,25 @@ TEST_CASE_TEMPLATE("Serialization of non-default-constructible classes via NLOHM
657683
}
658684
}
659685
}
686+
687+
TEST_CASE_TEMPLATE("Serialization of non-default-constructible classes via NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE and NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE", T, // NOLINT(readability-math-missing-parentheses)
688+
persons::derived_person_only_serialize_public,
689+
persons::derived_person_only_serialize_private)
690+
{
691+
SECTION("derived person only serialize")
692+
{
693+
{
694+
// serialization of a single object
695+
T person{"Erik", 1, "brown"};
696+
CHECK(json(person).dump() == "{\"age\":1,\"hair_color\":\"brown\",\"name\":\"Erik\"}");
697+
698+
// serialization of a container with objects
699+
std::vector<T> const two_persons
700+
{
701+
{"Erik", 1, "brown"},
702+
{"Kyle", 2, "black"}
703+
};
704+
CHECK(json(two_persons).dump() == "[{\"age\":1,\"hair_color\":\"brown\",\"name\":\"Erik\"},{\"age\":2,\"hair_color\":\"black\",\"name\":\"Kyle\"}]");
705+
}
706+
}
707+
}

0 commit comments

Comments
 (0)