lundi 16 juillet 2018

serialization pattern similar to boost

I have a bunch of classes that can be parsed from and serialized to a JSON object via the following interface:

class Message
{
public:
    virtual ~Message();

    virtual void parse(const Json::Value &v) = 0;

    virtual void serialize(Json::Value &v) const = 0;
};

I would like to implement a pattern similar to boost::serialization so that I have to define only one method (void setup(...), yeah I know, that's a poor naming choice) in my objects, which works in both directions (parsing, and serializing). This has also the benefit of providing an abstraction layer, so that in future I can switch to a different serialization (YAML? BSON? CBOR?) without rewriting all the serialization code in every object.

So I did the following:

class Message2;

struct MessageFields
{
    Json::Value *outValue;
    const Json::Value *inValue;

    virtual void add(const std::string &name, bool *field) {
        *field = (*inValue)[name].asBool();
    }
    virtual void add(const std::string &name, const bool *field) {
        (*outValue)[name] = *field;
    }
    virtual void add(const std::string &name, int *field) {
        *field = (*inValue)[name].asInt();
    }
    virtual void add(const std::string &name, const int *field) {
        (*outValue)[name] = *field;
    }
    virtual void add(const std::string &name, std::string *field) {
        *field = (*inValue)[name].asString();
    }
    virtual void add(const std::string &name, const std::string *field) {
        (*outValue)[name] = *field;
    }
    ...
};

class Message2 : public Message
{
    virtual ~Message2();

    virtual void setup(MessageFields &fields) const = 0;

    virtual void parse(const Json::Value &v)
    {
        MessageFields fields;
        fields.inValue = &v;
        setup(fields);
    }

    virtual void serialize(Json::Value &v) const
    {
        MessageFields fields;
        fields.outValue = &v;
        setup(fields);
    }
};

and in my objects, instead of implementing the two methods:

// class SomeObject : public Message { public: std::string node_name; };

void SomeObject::parse(const Json::Value &v)
{
    node_name = v["node_name"].asString();
}

void SomeObject::serialize(Json::Value &v) const
{
    v["node_name"] = node_name;
}

only would have to implement:

// class SomeObject : public Message2 { public: std::string node_name; };

void SomeObject::setup(serialization::MessageFields &fields) const
{
    fields.add("node_name", &node_name);
}

except that upon finishing writing this, I realized that setup(...) is const, so the calls to MessageFields::add(...) always resolve to the const version.

To fix this I would have to write two identical versions of the setup(...) method, one const and one not, but this kind of defeats the initial purpose of writing only one method to perform the two operations.

Any idea on how to solve this?

Aucun commentaire:

Enregistrer un commentaire