I have a class that expects an nlohmann::json
object as its first constructor parameter. I've implemented to_json
and from_json
for my class, but from_json
doesn't get called (unless I call it explicitly) and the default deserialization just puts the entire object into the json
parameter. Here is some example code.
#include <iostream>
#include "nlohmann/json.hpp"
using json = nlohmann::json;
class ExampleClass
{
public:
ExampleClass(json data = json::object(), std::string some_string = "") : m_Data(data), m_String(some_string) {}
~ExampleClass() {}
json m_Data;
std::string m_String;
};
void to_json(json& j, const ExampleClass& example)
{
j = json{ {"Data", example.m_Data}, {"String", example.m_String} };
}
void from_json(const json& j, ExampleClass& example)
{
j.at("Data").get_to(example.m_Data);
j.at("String").get_to(example.m_String);
}
int main()
{
ExampleClass example(json{ {"key", "value"} }, "here's a string");
std::cout << json(example) << std::endl; // {"Data":{"key":"value"},"String":"here's a string"}
ExampleClass example_two = json::parse("{\"Data\":{\"key\":\"value\"},\"String\":\"here's a string\"}");
std::cout << json(example_two) << std::endl; // {"Data":{"Data":{"key":"value"},"String":"here's a string"},"String":""}
ExampleClass example_three;
from_json(json::parse("{\"Data\":{\"key\":\"value\"},\"String\":\"here's a string\"}"), example_three);
std::cout << json(example_three) << std::endl; // {"Data":{"key":"value"},"String":"here's a string"}
}
As you can see, explicitly calling the from_json
method that I wrote works fine, but I've read you're not supposed to do that. I've used this pattern for dozens of classes elsewhere in my project and only came across this problem with classes that need a json
object as their first (or only) constructor parameter. Putting a non-json parameter first makes everything work fine, but I don't understand what I'm doing wrong that this doesn't work for me.
The issue is that you don't actually want to call the constructor in the case of example_two
. As such, you should make your constructor explicit
to avoid accidental calls.
class ExampleClass
{
public:
explicit ExampleClass(json data = json::object(), std::string some_string = "") : m_Data(data), m_String(some_string) {}
~ExampleClass() {}
json m_Data;
std::string m_String;
};