Search code examples
c++cereal

Cereal - unable to deserialize a json string - unhandled exception


This is my json string

{
    "connectionString" : "MyConnectionString",
    "value" :"MyVal"
}

This is my class

        struct Settings
        {
            std::string connectionString;
            std::string value;

            template<class Archive>
            void serialize(Archive& ar)
            {
                    ar(CEREAL_NVP(connectionString),
                    CEREAL_NVP(value)
                );
            }
        };

And this is what I am doing:

            std::ifstream ifs("Settings.json");
            std::string content((std::istreambuf_iterator<char>(ifs)),(std::istreambuf_iterator<char>())); // Yes this is valid - The content gets populated
            
            Settings settings;
            {
                cereal::JSONInputArchive archive_in(ifs);
                archive_in(settings); //<<-----Exception here - Unhandled exception
            }

The above solution would works only if my json string was this (i.e) if all the json string was an object of another key.

{
    "SomeThing" :{
                "connectionString" : "MyConnectionString",
                "value" :"MyVal"
       }
}

My question is how can I make my actual json string work (without wrapping it in an object)? I currently have this in a json file

{
    "connectionString" : "MyConnectionString",
    "value" :"MyVal"
}

and I wanted to know the best approach of deserializing this into an object ?


Solution

  • The code expecting that outer object is put there by the default JSON "prologue" and "epilogue" behavior:

    https://github.com/USCiLab/cereal/blob/10d9a29c225fe9a843d043bfe9f13c5f958844dc/include/cereal/archives/json.hpp#L837

    From the documentation:

    These functions are given a reference to the active archive and a constant reference to the type being serialized. Careful specialization of prologue and epilogue allows for archives to exercise special behaviors without having to re-implement serialization functions for types. This lets us make the type support fairly generic. For example, cereal::XMLOutputArchive (<cereal/archives/xml.hpp>) makes use of these functions to start and finish nodes in its in-memory tree.

    If you add in your code an overload for your type that does nothing:

    void epilogue(cereal::JSONInputArchive&, const Settings&) { }
    void prologue(cereal::JSONInputArchive&, const Settings&) { }
    

    It won't try to parse an outer object