# Arbitrary Type Conversions Every type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines: ```cpp namespace ns { // a simple struct to model a person struct person { std::string name; std::string address; int age; }; } // namespace ns ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; // convert to JSON: copy each value into the JSON object json j; j["name"] = p.name; j["address"] = p.address; j["age"] = p.age; // ... // convert from JSON: copy each value from the JSON object ns::person p { j["name"].get(), j["address"].get(), j["age"].get() }; ``` It works, but that's quite a lot of boilerplate... Fortunately, there's a better way: ```cpp // create a person ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60}; // conversion: person -> json json j = p; std::cout << j << std::endl; // {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} // conversion: json -> person auto p2 = j.get(); // that's it assert(p == p2); ``` ## Basic usage To make this work with one of your types, you only need to provide two functions: ```cpp using json = nlohmann::json; namespace ns { void to_json(json& j, const person& p) { j = json{ {"name", p.name}, {"address", p.address}, {"age", p.age} }; } void from_json(const json& j, person& p) { j.at("name").get_to(p.name); j.at("address").get_to(p.address); j.at("age").get_to(p.age); } } // namespace ns ``` That's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called. Likewise, when calling `get()` or `get_to(your_type&)`, the `from_json` method will be called. Some important things: * Those methods **MUST** be in your type's namespace (which can be the global 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 available (e.g., proper headers must be included) everywhere you use these conversions. Look at [#1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. * When using `get()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) * In function `from_json`, use function [`at()`](../api/basic_json/at.md) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. ## 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 to make your life easier as long as you want to use a JSON object as serialization. The macros are following the naming pattern, and you can choose the macro based on the needed features: - All the macros start with `NLOHMANN_DEFINE`. - If you want a macro for the derived object, use the [`DERIVED_TYPE`](../api/macros/nlohmann_define_derived_type.md) variant, otherwise use `TYPE`. - The `DERIVED_TYPE` variant requires an additional parameter of a base type, which should have the `to_json`/`from_json` functions defined. For instance, with a macro of its own. - If you need access to the private fields use [`INTRUSIVE`](../api/macros/nlohmann_define_type_intrusive.md) variant, otherwise use [`NON_INTRUSIVE`](../api/macros/nlohmann_define_type_non_intrusive.md). - The `INTRUSIVE` macro should be defined **inside** the target class/struct, `NON_INTRUSIVE` should be defined within the same namespace. - If you want to deserialize the incomplete JSONs, use the `WITH_DEFAULTS` variant, which will use the default values for the member variables absent in JSON, the variant without `WITH_DEFAULTS` will raise an exception. - If you do not need deserialization at all and only interested in `to_json` function, you can use the `ONLY_SERIALIZE` variant. - If you want to use the custom JSON names for member variables, use [`WITH_NAMES`](../api/macros/nlohmann_define_type_with_names.md) variant, otherwise the JSON name of the variable will be the same as its regular name. For all the macros, the first parameter is the name of the class/struct. The `DERIVED_TYPE` macros require a second parameter of a base class. All the remaining parameters name the member variables. The `WITH_NAMES` macros require a JSON name before each of the variables. | Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro | |------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------| |
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_INTRUSIVE**](../api/macros/nlohmann_define_type_intrusive.md) | |
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_type_intrusive.md) | |
:octicons-check-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE**](../api/macros/nlohmann_define_type_intrusive.md) | |
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE**](../api/macros/nlohmann_define_type_non_intrusive.md) | |
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_type_non_intrusive.md) | |
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE**](../api/macros/nlohmann_define_type_non_intrusive.md) | For _derived_ classes and structs, use the following macros | Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro | |------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------| |
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE**](../api/macros/nlohmann_define_derived_type.md) | |
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_derived_type.md) | |
:octicons-check-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE**](../api/macros/nlohmann_define_derived_type.md) | |
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE**](../api/macros/nlohmann_define_derived_type.md) | |
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_derived_type.md) | |
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE**](../api/macros/nlohmann_define_derived_type.md) | !!! info "Implementation limits" - The current macro implementations are 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. - For the `WITH_NAMES` variants the limit is halved to 31 member variables. ??? example The `to_json`/`from_json` functions for the `person` struct above can be created with: ```cpp namespace ns { NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) } ``` 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` is needed: ```cpp namespace ns { class address { private: std::string street; int housenumber; int postcode; public: NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode) }; } ``` 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) }; } ``` !!! warning "Overriding conversions for natively-supported types" The library already provides built-in `to_json`/`from_json` conversions for STL containers such as `std::vector`, `std::array`, and `std::map`. Defining your own free-function `to_json`/`from_json` overload for one of these container types directly (instead of for your own type) can conflict with the built-in overload during overload resolution, producing compiler errors ("no matching overloaded function", "call is ambiguous") that vary by compiler and library version. If you need different conversion behavior for a container type the library already handles, wrap it in your own type (or use `adl_serializer` specialization, as shown [above](#how-do-i-convert-third-party-types) for `boost::optional`) instead of trying to re-specialize `to_json`/`from_json` for the container type itself. !!! warning "Raw C-style arrays" Members declared as raw C-style arrays (e.g., `char buf[1024]`) do not round-trip safely through `NLOHMANN_DEFINE_TYPE_*` macros or the default (de)serializers: `to_json` serializes any `char` array as a JSON *string* (matching the `std::string`-constructible overload), but the `from_json` overload for fixed-size arrays expects a JSON *array* and iterates it element-wise, which fails with a `type_error` when given a string. Use `std::string`, `std::array`, or a manually written `to_json`/`from_json` pair for such members instead. !!! note "Macros and `nlohmann::ordered_json`" The `NLOHMANN_DEFINE_TYPE_*`/`NLOHMANN_DEFINE_DERIVED_TYPE_*` macros are generic over any `basic_json` specialization, including `nlohmann::ordered_json`. Simply use `ordered_json` as the target type and members are serialized in declaration order -- no separate macro or extra code is needed. ```cpp namespace ns { NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) } ns::person p{"Ned Flanders", "744 Evergreen Terrace", 60}; nlohmann::ordered_json j = p; // keys appear in declaration order: name, address, age ``` !!! note "No macro for non-default-constructible types" There is currently no `NLOHMANN_DEFINE_TYPE_*`-style macro for types that are not [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). This is not an intentional omission of documentation -- no such macro exists yet; see [How can I use `get()` for non-default constructible/non-copyable types?](#how-can-i-use-get-for-non-default-constructiblenon-copyable-types) for the manual pattern to use instead. ## How do I convert third-party types? This requires a bit more advanced technique. But first, let us 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](https://en.cppreference.com/w/cpp/language/adl)). It is implemented like this (simplified): ```cpp template struct adl_serializer { static void to_json(json& j, const T& value) { // calls the "to_json" method in T's namespace } static void from_json(const json& 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`... 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) NLOHMANN_JSON_NAMESPACE_BEGIN template struct adl_serializer> { static void to_json(json& j, const boost::optional& opt) { if (opt == boost::none) { j = nullptr; } else { j = *opt; // this will call adl_serializer::to_json which will // find the free function to_json in T's namespace! } } static void from_json(const json& j, boost::optional& opt) { if (j.is_null()) { opt = boost::none; } else { opt = j.get(); // same as above, but with // adl_serializer::from_json } } }; NLOHMANN_JSON_NAMESPACE_END ``` !!! note "ABI compatibility" Use [`NLOHMANN_JSON_NAMESPACE_BEGIN`](../api/macros/nlohmann_json_namespace_begin.md) and `NLOHMANN_JSON_NAMESPACE_END` instead of `#!cpp namespace nlohmann { }` in code which may be linked with different versions of this library. ## How can I use `get()` for non-default constructible/non-copyable types? There is a way if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload: ```cpp struct move_only_type { move_only_type() = delete; move_only_type(int ii): i(ii) {} move_only_type(const move_only_type&) = delete; move_only_type(move_only_type&&) = default; int i; }; namespace nlohmann { template <> struct adl_serializer { // note: the return type is no longer 'void', and the method only takes // one argument static move_only_type from_json(const json& j) { return {j.get()}; } // 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 static void to_json(json& j, move_only_type t) { j = t.i; } }; } ``` ## Why can't I convert to/from `std::any`? `std::any` is intentionally excluded from `get()`/generic conversion support, so `get()` and containers like `std::map` fail to compile by design -- there is no way to know, from a `json` value alone, which concrete type to store inside the `std::any`. To work with heterogeneous JSON values, dispatch on the value's type manually and construct the `std::any` (or extract from it) yourself: ```cpp std::any value_to_any(const json& j) { if (j.is_boolean()) { return j.get(); } if (j.is_number_integer()) { return j.get(); } if (j.is_number_float()) { return j.get(); } if (j.is_string()) { return j.get(); } // ... handle other types (arrays, objects) as needed for your use case return {}; } json any_to_json(const std::any& a) { if (a.type() == typeid(bool)) { return std::any_cast(a); } if (a.type() == typeid(int)) { return std::any_cast(a); } if (a.type() == typeid(double)) { return std::any_cast(a); } if (a.type() == typeid(std::string)) { return std::any_cast(a); } return nullptr; } ``` ## Why does serializing a `std::map`/`std::unordered_map` with non-string keys produce an array? A `std::map`/`std::unordered_map` whose key type is not string-like (e.g., `std::map`) is serialized as a JSON *array* of 2-element `[key, value]` arrays, not as a JSON object -- JSON object keys must be strings, so the library cannot represent an integer-keyed map as an object. ```cpp std::map m{{1, "one"}, {2, "two"}}; json j = m; // j is [[1,"one"],[2,"two"]], not {"1":"one","2":"two"} ``` ## Why does `std::wstring` convert or dump incorrectly? The library assumes UTF-8 encoding internally, so `std::wstring` is not supported out of the box -- see the FAQ entry on [wide string handling](../home/faq.md#wide-string-handling) for why, and for a UTF-8 conversion recipe. ## Can I write my own serializer? (Advanced use) Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-udt.cpp) in the test suite, to see a few examples. If you write your own serializer, you will 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 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 template::type> struct less_than_32_serializer { template static void to_json(BasicJsonType& j, T value) { // we want to use ADL, and call the correct to_json overload using nlohmann::to_json; // this method is called by adl_serializer, // this is where the magic happens to_json(j, value); } template static void from_json(const BasicJsonType& j, T& value) { // same thing here using nlohmann::from_json; from_json(j, value); } }; ``` Be **very** careful when reimplementing your serializer, you can stack overflow if you don't pay attention: ```cpp template struct bad_serializer { template static void to_json(BasicJsonType& j, const T& value) { // this calls BasicJsonType::json_serializer::to_json(j, value); // if BasicJsonType::json_serializer == bad_serializer ... oops! j = value; } template static void from_json(const BasicJsonType& j, T& value) { // this calls BasicJsonType::json_serializer::from_json(j, value); // if BasicJsonType::json_serializer == bad_serializer ... oops! value = j.template get(); // oops! } }; ```