-
-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to deserialize array with derived objects #716
Comments
I am not sure what you want to do exactly, but this may be helpful: #include <iostream>
#include <fstream>
#include <array>
#include "json.hpp"
using json = nlohmann::json;
class systembase
{
public:
std::string type;
std::string name;
};
void from_json(const json& j, systembase& sb) {
sb.type = j.at("type");
sb.name = j.at("name");
}
class settings {
public:
std::vector<systembase> systems;
};
void from_json(const json& j, settings& s) {
const json& sj = j.at("systems");
s.systems.resize(sj.size());
std::copy(sj.begin(), sj.end(), s.systems.begin());
}
int main() {
std::string text = R"(
{
"systems": [
{
"type": "system1",
"name": "system_1",
"special_param_1": 1
},
{
"type": "system2",
"name": "system_2",
"special_param_2": "Value2"
},
{
"type": "system3",
"name": "system_3",
"special_param_3": 3.0,
"special_param_3_1": "Value_3"
}
]
}
)";
json j = json::parse(text);
settings s = j;
} |
Than I have only deserilized the systembaseclass with parameter type and name. But I have not deserialized the derived classes with the special parameter I solved it now in this way
|
Thanks for checking back! |
Hi... you closed... ok so you also the opinion thats the best/only solution? |
I have no real opinion on this. If it works for you, then it's OK. If not, are there issues left? |
Looks good to me. |
I think its not possible to determine the type of derived class automaticaly. So the way with the switch was the only solution for me. |
The to_json method for the sake of completeness
|
Sorry if I am reopening a can of worms… I have a similar issue, a base class, and two derived classes. The base class handles the bulk of the serialization, and the derived classes have some unique properties which also need to be serialized. The difference in perspective is that there will be more derived classes down the road, which might include “user defined” classes. Generally it would be messy for the base class to have to know about all the potential derived classes (e.g. in a big switch statement as in MattiasEppler’s to_json example above). I already have a solution to the basic functionality I need. I define a virtual function on the base class ( So I am not stuck, but it would be more convenient if I could use |
@theodelrieu to the rescue... |
Maybe my desired use case is supported by the existing implementation. Say I have a base class with an inheritable serialization method, lets call it class Fruit
{
virtual void to_json_helper(json& j)
{
j = {{"edible", true}, {“contains_seeds”, true}};
}
static void to_json(json& j, const Fruit& f) { f.to_json_helper(j); };
}; Then a derived class would look like: class Kumquat : public Fruit
{
void to_json_helper(json& j) override
{
Fruit::to_json_helper(j);
j["vitamin_c"] = true;
}
static void to_json(json& j, const Kumquat& k) { k.to_json_helper(j); };
}; However, I guess if I have a generic j.push_back(fruit); // uses Fruit::to_json() not Kumquat::to_json(). |
I did think a bit about it, and there's a way to achieve this with CRTP. Here is a full working example: #include <iostream>
#include <nlohmann/json.hpp>
using nlohmann::json;
template <typename T>
struct Base
{
int a{1};
};
template <typename T>
struct Derived : Base<Derived<T>>
{
int b{2};
};
struct Final : Derived<Final>
{
int c{3};
};
template <typename T>
void to_json(json& j, Base<T> const& b)
{
j["value"] = b.a;
::nlohmann::to_json(j["derived"], static_cast<T const&>(b));
}
template <typename T>
void to_json(json& j, Derived<T> const& d)
{
j["value"] = d.b;
::nlohmann::to_json(j["final"], static_cast<T const&>(d));
}
void to_json(json& j, Final const& f)
{
j["value"] = f.c;
}
template <typename T>
void print_json(Base<T> const& val)
{
json j = val;
std::cout << j.dump(2) << std::endl;
}
template <typename T>
void print_json(Derived<T> const& val)
{
print_json(static_cast<Base<Derived<T>> const&>(val));
}
template <typename T>
void print_json(T const& val)
{
print_json(static_cast<Derived<T> const&>(val));
}
int main(int argc, char const *argv[])
{
Final f;
print_json(f);
} Note that: Final f;
json j = f; // will only call to_json(json, Final);
j = static_cast<Derived<Final> const&>(f); // to_json(json, Derived<Final>);
j = static_cast<Base<Derived<Final>> const&>(f); //to_json(json, Base<Derived<Final> const&>); I've hidden those static_cast in the The good thing here is that you don't have to rely on virtual functions, users still write |
Thank you @theodelrieu for the suggestion, and for introducing me to the “curiously recurring template pattern” of which I had never heard! |
No problem :) |
I take a look at your example. Whats the difference. You also have to know about the derived class in the base class You have to know that something is derived from base.
This is also working. Without knowing something about the derived class in base to_json method.
But what about the from_json method: |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
@nlohmann the example you provided on Aug 28, 2017, Can you tell me how can I access the member of the class systembase? |
With code void from_json(const json& j, systembase& sb) {
sb.type = j.at("type");
sb.name = j.at("name");
} you store a systembase s;
s.name = "foo";
s.type = "bar";
json j = s;
{"name": "foo", "type": "bar"} |
What if I just have to read the value and not write it? As I'm receiving Json from other source and I just have to fill it in class. |
Then you need to implement a |
It is a little confusing. But I'll figure it out. |
Just |
Can you tell me how can I write to_json if I have a nested json? { How can I get the value of Id with value 2? |
It was easy, this is how I did it |
Hi
I need to deserialize a array that have derived objects.
so in my from_json I have to do what? Sorry but I do not realy know how to solve this.
I started with:
The text was updated successfully, but these errors were encountered: