That's all. When calling the json constructor with your type, your custom `to_json` method will be automatically called.
That's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called.
Likewise, when calling `get<your_type>()`, the `from_json` method will be called.
Likewise, when calling `get<your_type>()`, the `from_json` method will be called.
Some important things:
Some important things:
* Those methods **MUST** be in your type's namespace, or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined).
* Those methods **MUST** be in your type's namespace, or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined).
* When using `get<your_type>()`, `your_type`**MUST** be DefaultConstructible and CopyConstructible (There is a way to bypass those requirements described later)
* When using `get<your_type>()`, `your_type`**MUST** be [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible) and [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible). (There is a way to bypass those requirements described later.)
#### How do I convert third-party types?
#### How do I convert third-party types?
...
@@ -510,124 +517,117 @@ This requires a bit more advanced technique.
...
@@ -510,124 +517,117 @@ This requires a bit more advanced technique.
But first, let's see how this conversion mechanism works:
But first, let's see how this conversion mechanism works:
The library uses **JSON Serializers** to convert types to json.
The library uses **JSON Serializers** to convert types to json.
The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](http://en.cppreference.com/w/cpp/language/adl))
The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](http://en.cppreference.com/w/cpp/language/adl)).
It is implemented like this (simplified):
It is implemented like this (simplified):
```cpp
```cpp
template<typenameT>
template<typenameT>
structadl_serializer
structadl_serializer{
{
staticvoidto_json(json&j,constT&value){
staticvoidto_json(json&j,constT&value)
// calls the "to_json" method in T's namespace
{
}
// calls the "to_json" method in T's namespace
}
staticvoidfrom_json(constjson&j,T&value){
// same thing, but with the "from_json" method
staticvoidfrom_json(constjson&j,T&value)
}
{
// same thing, but with the "from_json" method
}
};
};
```
```
This serializer works fine when you have control over the type's namespace.
This serializer works fine when you have control over the type's namespace. However, what about `boost::optional`, or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`...
However, what about `boost::optional`, or `std::filesystem::path` (C++17)?
Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`...
To solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example:
To solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example:
```cpp
```cpp
// partial specialization (full specialization works too)
// partial specialization (full specialization works too)
opt=j.get<T>();// same as above, but with adl_serializer<T>::from_json
opt=j.get<T>();// same as above, but with
}
// adl_serializer<T>::from_json
};
}
}
};
}
}
```
```
#### How can I use `get()` for non-default constructible/non-copyable types?
#### How can I use `get()` for non-default constructible/non-copyable types?
There is a way, if your type is **MoveConstructible**.
There is a way, if your type is [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:
You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:
```cpp
```cpp
structmove_only_type{
structmove_only_type{
move_only_type()=delete;
move_only_type()=delete;
move_only_type(intii):i(ii){}
move_only_type(intii):i(ii){}
move_only_type(constmove_only_type&)=delete;
move_only_type(constmove_only_type&)=delete;
move_only_type(move_only_type&&)=default;
move_only_type(move_only_type&&)=default;
:
inti;
private:
inti;
};
};
namespacenlohmann{
namespacenlohmann{
template<>
template<>
structadl_serializer<move_only_type>
structadl_serializer<move_only_type>{
{
// note: the return type is no longer 'void',
// note: the return type is no longer 'void', and the method only takes one argument
// and the method only takes one argument
staticmove_only_typefrom_json(constjson&j)
staticmove_only_typefrom_json(constjson&j){
{
return{j.get<int>()};
return{j.get<int>()};
}
}
// Here's the catch! You must provide a to_json method!
// Here's the catch! You must provide a to_json method!
// Otherwise you will not be able to convert move_only_type to json,
// Otherwise you will not be able to convert move_only_type to json,
// since you fully specialized adl_serializer on that type
// since you fully specialized adl_serializer on that type
staticvoidto_json(json&j,move_only_typet){
staticvoidto_json(json&j,move_only_typet)
j=t.i;
{
}
j=t.i;
};
}
};
}
}
```
```
#### Can I write my own serializer? (Advanced use)
#### Can I write my own serializer? (Advanced use)
Yes. You might want to take a look at `unit-udt.cpp` in the test suite, to see a few examples.
Yes. You might want to take a look at `[unit-udt.cpp](https://github.com/nlohmann/json/blob/develop/test/src/unit-udt.cpp)` in the test suite, to see a few examples.
If you write your own serializer, you'll need to do a few things:
If you write your own serializer, you'll need to do a few things:
* use a different `basic_json` alias than nlohmann::json (the last template parameter of basic_json is the JSONSerializer)
* use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`)
* use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods
* use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods
* use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL
* use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL
Here is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL.
Here is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL.
```cpp
```cpp
// You should use void as a second template argument if you don't need compile-time checks on T
// You should use void as a second template argument
@@ -637,21 +637,19 @@ Be **very** careful when reimplementing your serializer, you can stack overflow
...
@@ -637,21 +637,19 @@ Be **very** careful when reimplementing your serializer, you can stack overflow
template<typenameT,void>
template<typenameT,void>
structbad_serializer
structbad_serializer
{
{
template<typenameJson>
template<typenameBasicJsonType>
staticvoidto_json(Json&j,constT&value)
staticvoidto_json(BasicJsonType&j,constT&value){
{
// this calls BasicJsonType::json_serializer<T>::to_json(j, value);
// this calls Json::json_serializer<T>::to_json(j, value);
// if BasicJsonType::json_serializer == bad_serializer ... oops!
// if Json::json_serializer == bad_serializer ... oops!
j=value;
j=value;
}
}
template<typenameBasicJsonType>
template<typenameJson>
staticvoidto_json(constBasicJsonType&j,T&value){
staticvoidto_json(constJson&j,T&value)
// this calls BasicJsonType::json_serializer<T>::from_json(j, value);
{
// if BasicJsonType::json_serializer == bad_serializer ... oops!
// this calls Json::json_serializer<T>::from_json(j, value);
value=j.templateget<T>();// oops!
// if Json::json_serializer == bad_serializer ... oops!
}
value=j.templateget<T>();// oops!
}
};
};
```
```
...
@@ -759,7 +757,7 @@ I deeply appreciate the help of the following people.
...
@@ -759,7 +757,7 @@ I deeply appreciate the help of the following people.
-[Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping.
-[Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping.
-[易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums.
-[易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums.
-[kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio.
-[kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio.
-[gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements.
-[gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types.
-[Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling.
-[Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling.
-[dariomt](https://github.com/dariomt) fixed some typos in the examples.
-[dariomt](https://github.com/dariomt) fixed some typos in the examples.
-[Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation.
-[Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation.
...
@@ -787,7 +785,7 @@ I deeply appreciate the help of the following people.
...
@@ -787,7 +785,7 @@ I deeply appreciate the help of the following people.
-[duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.
-[duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.
-[Damien](https://github.com/dtoma) fixed one of the last conversion warnings.
-[Damien](https://github.com/dtoma) fixed one of the last conversion warnings.
-[Thomas Braun](https://github.com/t-b) fixed a warning in a test case.
-[Thomas Braun](https://github.com/t-b) fixed a warning in a test case.
-[Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290).
-[Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types.
-[Stefan](https://github.com/5tefan) fixed a minor issue in the documentation.
-[Stefan](https://github.com/5tefan) fixed a minor issue in the documentation.
-[Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`.
-[Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`.
-[ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.
-[ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.
...
@@ -801,6 +799,9 @@ I deeply appreciate the help of the following people.
...
@@ -801,6 +799,9 @@ I deeply appreciate the help of the following people.
-[Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one.
-[Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one.
-[Daniel599](https://github.com/Daniel599) helped to get Travis execute the tests with Clang's sanitizers.
-[Daniel599](https://github.com/Daniel599) helped to get Travis execute the tests with Clang's sanitizers.
-[Jonathan Lee](https://github.com/vjon) fixed an example in the README file.
-[Jonathan Lee](https://github.com/vjon) fixed an example in the README file.
-[gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types.
-[Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio.
-[Jared Grubb](https://github.com/jaredgrubb) supported the implementation of user-defined types.
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.