Header-only extension library for nlohmann/json.
- Adds
NLOHMANN_SERIALIZE
andNLOHMANN_SERIALIZE_STRICT
macros, which defines and reflects member variables in one macro, it also allows for default / non-default values in one macro (basically a mix ofNLOHMANN_DEFINE_TYPE_INTRUSIVE
andNLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULTS
- Adds serialization / deserialization for
std::optional
andstd::variant
- uses
boost/preprocessor
to generate the reflected members and functions.
In my work I require often to serialize, deserialize classes, nlohmann::json
has the NLOHMANN_DEFINE_TYPE*
macros for that to quickly reflect elements of a class.
The problem here is that I often forget to add a variable to the reflected set, which then results in errors I have to track down (minor issue just don't forget to do it).
The bigger problem is that the classes either support all values as defaults or no values as defaults. You should be able to supply some variables with defaults, and some should be required during deserialization. I incorporated this in my macro.
Another feature I am missing is the serialization of std::variant
and std::optional
, so I have implemented those based on this, there was also another issue for std::variant
, but I can't find it (basically just want to say that someone else did the hardcore work).
Also I wanted to play with boost/preprocessor
:)
Check the tests for more usage examples.
#include <nlohmann/json_ext.hpp>
struct serialize_me_daddy
{
NLOHMANN_SERIALIZE(serialize_me_daddy,
(int, required) /* no default value here */
(int, optional, 42) /* with default value */
)
};
int main()
{
// json macro also allows you to directly create a json
auto j1 = JSON({"required": 1337});
auto obj1 = j1.get<serialize_me_daddy>();
auto j2 = JSON({"optional": 43});
// this will fail, because 'required' is not given
// auto obj2 = j2.get<serialize_me_daddy>();
}
Will error out if you have more variables present in the json than on the class itself.
NLOHMANN_SERIALIZE_STRICT
, will store the reflected keys.
In from_json
it will check whether every key in the json is also present in the reflected set of keys.
This is particularly useful when you serialize a std::variant
.
struct TypeA
{
NLOHMANN_SERIALIZE_STRICT(TypeA,
(int, a)
);
};
struct TypeB
{
NLOHMANN_SERIALIZE_STRICT(TypeB,
(int, a)
(int, b)
);
};
using TypeAB = std::variant<TypeA, TypeB>;
using TypeBA = std::variant<TypeB, TypeA>;
auto j1 = JSON({"a": 1})
j1.get<TypeAB>() // will be TypeA
j1.get<TypeBA>() // will be TypeA
auto j2 = JSON({"a": 1, "b": 2})
j2.get<TypeAB>() // will be TypeB
j2.get<TypeBA>() // will be TypeB
There is still an edge case left, which can probably not be fixed, at least not with the deserialization I use.
struct StrictTypeIntersectionA
{
NLOHMANN_SERIALIZE_STRICT(StrictTypeIntersectionA,
(int, a)
)
};
struct StrictTypeIntersectionB
{
NLOHMANN_SERIALIZE_STRICT(StrictTypeIntersectionB,
(int, a)
(int, b, 2)
)
};
using StrictTypeIntersectionAB = std::variant<StrictTypeIntersectionA, StrictTypeIntersectionB>;
using StrictTypeIntersectionBA = std::variant<StrictTypeIntersectionB, StrictTypeIntersectionA>;
auto j = JSON({"a":1});
j.get<StrictTypeIntersectionAB>(); // will result in StrictTypeIntersectionA
j.get<StrictTypeIntersectionBA>(); // will result in StrictTypeIntersectionB
sudo apt install -y libboost-dev cmake gcc
# this library also expects that you have `nlohmann/json.hpp` in your include directories
# on Arch
paru -Sy nlohmann-json boost cmake gcc
make test
- maybe fix variant with optional value case, but probably impossible to do that
- fix the edge case for variants
- no counting done anymore
improve the counting of the supplied members, currently done at runtime, but all this information is available at compile time - improve the serialization interface, it is possible to supply just a one dimensional array as in:
(int, a)(int, b)
instead of((int, a))((int b))