Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON deserialization C++

I want to deserialize JSON file to an object(class) using C++. I've looked at rapidjson library and I made each class have a deserialize method with the root as parameter, so it can deserialize itself. It looks like this:

void PoliceOfficer::Deserialize(rapidjson::Value& root)
{
if (root.IsObject())
{
    if (root.HasMember("name"))
    {
        if (root["name"].IsString())
        {
            name = root["name"].GetString();
        }
    }

    if (root.HasMember("maxHealth"))
    {
        if (root["maxHealth"].IsNumber())
        {
            maxHealth = (float)root["maxHealth"].GetDouble();
        }
    }

    if (root.HasMember("skills"))
    {
        rapidjson::Value& skills = root["skills"];
        if (skills.IsArray())
        {
            for (rapidjson::SizeType i = 0; i < skills.Size(); i++)
            {
                Skill tempSkill;

                tempSkill.Deserialize(skills[i]);

                m_skills.push_back(tempSkill);
            }
        }
    }
}
}

But this seems like a lot of work. You'd have to implement this method in all the classes you want to deserialize themselves. So I was wondering if there's any way to do this automatically, something like the following line of code(JSON.NET):

 Movie m = JsonConvert.DeserializeObject<Movie>(json);

so I don't have to write deserialize method for all the classes. Is the way I'm doing it the only way to do it? I'm using rapidjson, but I'm open for trying another library.

I hope the question makes sense :)

Thank you in advance!

like image 409
user3071028 Avatar asked Dec 14 '25 02:12

user3071028


1 Answers

To deal with a problem like the you are having a possible solution concentrate all infos in a single function where you make the mapping structure fields <---> entries in the json/xml/ini file. Something like this:

struct abc_t
{
    int a ;
    string b ;
} ;

void serialize(serializer_t &serializer, abc_t &abc)
{
    serializer.exx(abc.a, "abc") ;
    serializer.exx(abc.b, "b") ;
}

The problem is how to write this serializer. The solution can be an abstract class like this:

class serializer_t
{
public:
    virtual ~serializer_t(void) {}
    virtual void exx(int &value, const char *tag) = 0 ;
    virtual void exx(string &value, const char *tag) = 0 ;
} ;

then you will have two derived classes, a serializer_writer_t that implements the writing and a serializer_reader_t implementing the reading.

Another possibility is a static polymorphism: this means making the original void serialize(serializer_t &serializer, abc_t &abc) a template function. If you have a composite object then you need to apply this strategy to each sub-object.

Give a look at boost.serialization: you will find a deep discussion about all the trade offs involved in this task

like image 119
marom Avatar answered Dec 16 '25 17:12

marom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!