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.
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).
* 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?
...
...
@@ -510,124 +517,117 @@ This requires a bit more advanced technique.
But first, let's see how this conversion mechanism works:
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):
```cpp
template<typenameT>
structadl_serializer
{
staticvoidto_json(json&j,constT&value)
{
// calls the "to_json" method in T's namespace
}
staticvoidfrom_json(constjson&j,T&value)
{
// same thing, but with the "from_json" method
}
structadl_serializer{
staticvoidto_json(json&j,constT&value){
// calls the "to_json" method in T's namespace
}
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.
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`...
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`...
To solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example:
```cpp
// partial specialization (full specialization works too)
#### How can I use `get()` for non-default constructible/non-copyable types?
There is a way, if your type is **MoveConstructible**.
You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:
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:
```cpp
structmove_only_type{
move_only_type()=delete;
move_only_type(intii):i(ii){}
move_only_type(constmove_only_type&)=delete;
move_only_type(move_only_type&&)=default;
:
inti;
move_only_type()=delete;
move_only_type(intii):i(ii){}
move_only_type(constmove_only_type&)=delete;
move_only_type(move_only_type&&)=default;
private:
inti;
};
namespacenlohmann{
template<>
structadl_serializer<move_only_type>
{
// note: the return type is no longer 'void', and the method only takes one argument
staticmove_only_typefrom_json(constjson&j)
{
return{j.get<int>()};
}
// Here's the catch! You must provide a to_json method!
// Otherwise you will not be able to convert move_only_type to json,
// since you fully specialized adl_serializer on that type
staticvoidto_json(json&j,move_only_typet)
{
j=t.i;
}
};
template<>
structadl_serializer<move_only_type>{
// note: the return type is no longer 'void',
// and the method only takes one argument
staticmove_only_typefrom_json(constjson&j){
return{j.get<int>()};
}
// Here's the catch! You must provide a to_json method!
// Otherwise you will not be able to convert move_only_type to json,
// since you fully specialized adl_serializer on that type
staticvoidto_json(json&j,move_only_typet){
j=t.i;
}
};
}
```
#### 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:
* 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 `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.
```cpp
// You should use void as a second template argument if you don't need compile-time checks on T
@@ -637,21 +637,19 @@ Be **very** careful when reimplementing your serializer, you can stack overflow
template<typenameT,void>
structbad_serializer
{
template<typenameJson>
staticvoidto_json(Json&j,constT&value)
{
// this calls Json::json_serializer<T>::to_json(j, value);
// if Json::json_serializer == bad_serializer ... oops!
j=value;
}
template<typenameJson>
staticvoidto_json(constJson&j,T&value)
{
// this calls Json::json_serializer<T>::from_json(j, value);
// if Json::json_serializer == bad_serializer ... oops!
value=j.templateget<T>();// oops!
}
template<typenameBasicJsonType>
staticvoidto_json(BasicJsonType&j,constT&value){
// this calls BasicJsonType::json_serializer<T>::to_json(j, value);
// if BasicJsonType::json_serializer == bad_serializer ... oops!
j=value;
}
template<typenameBasicJsonType>
staticvoidto_json(constBasicJsonType&j,T&value){
// this calls BasicJsonType::json_serializer<T>::from_json(j, value);
// if BasicJsonType::json_serializer == bad_serializer ... oops!
value=j.templateget<T>();// oops!
}
};
```
...
...
@@ -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.
-[易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums.
-[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.
-[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.
...
...
@@ -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.
-[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.
-[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.
-[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.
...
...
@@ -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.
-[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.
-[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.