DonerSerializer is a C++14 header-only library that provides you a simple interface to serialize/deserialize your class data in a few lines of code.
Internally it uses:
Built-in types
std::int32_t
std::uint32_t
std::int64_t
std::uint64_t
float
double
bool
Std containers
std::string
std::vector
std::list
std::map
std::unordered_map
You can acquire stable releases here.
Alternatively, you can check out the current development version with:
git clone https://github.com/Donerkebap13/DonerSerializer.git
You can contact me directly via email. Also, if you have any suggestion or you find any bug, please don't hesitate to create a new Issue.
If you decide to start using DonerSerializer in your project, I'll be glad to hear about it and post it here in the main page as an example!
DonerSerializer uses DonerReflection macros to expose your class data.
namespace Foo
{
struct Bar
{
int m_int;
float m_float;
std::string m_char;
}
}
// IMPORTANT!!
// It is mandatory that this macro calls happen always outside of any namespace
DONER_DEFINE_REFLECTION_DATA(Foo::Bar,
DONER_ADD_NAMED_VAR_INFO(m_int, "intFoo"),
DONER_ADD_NAMED_VAR_INFO(m_float, "floatBar"),
DONER_ADD_NAMED_VAR_INFO(m_char, "charMander")
)
As simple as that. Those macros will define a struct containing all the registered members info for that class. As the comment say, this calls should be done outside of any namespace. Otherwise it won't work. Also, if you don't care about how each member is called in the json, you can use the following macro instead:
DONER_DEFINE_REFLECTION_DATA(Foo::Bar,
DONER_ADD_VAR_INFO(m_int),
DONER_ADD_VAR_INFO(m_float),
DONER_ADD_VAR_INFO(m_char)
)
The name in this case will be the same as the variable name.
In order to access protected/private members, you need to use the following macro:
namespace Foo
{
class Bar
{
DONER_DECLARE_OBJECT_AS_REFLECTABLE(Bar)
private:
int m_int;
float m_float;
std::string m_char;
}
}
// IMPORTANT!!
// It is mandatory that this macro calls happen always outside of any namespace
DONER_DEFINE_REFLECTION_DATA(Foo::Bar,
DONER_ADD_NAMED_VAR_INFO(m_int, "intFoo"),
DONER_ADD_NAMED_VAR_INFO(m_float, "floatBar"),
DONER_ADD_NAMED_VAR_INFO(m_char, "charMander")
)
By doing this you allow DonerSerializer to access private members information.
DonerSerializer doesn't support inheritance per se. If you want to serialize class members inherited from its upper class, you need to do as follows:
class Foo
{
protected:
int m_int;
}
class Bar : public Foo
{
DONER_DECLARE_OBJECT_AS_REFLECTABLE(Bar)
private:
float m_float;
}
DONER_DEFINE_REFLECTION_DATA(Bar,
DONER_ADD_VAR_INFO(m_int),
DONER_ADD_VAR_INFO(m_float)
)
Even if the upper class have some reflection data defined, this information is not transitive, so you need to re-declare it for any children class.
You just need to use DonerSerializer::CJsonSerializer
CFoo foo;
foo.m_int = 1337;
DonerSerializer::CJsonSerializer serializer;
serializer.Serialize(foo);
std::string result = serializer.GetJsonString(); // value is {"m_int": 1337}
You can also get the rapidjson::Document
with all the contents:
rapidjson::Document& document = serializer.GetJsonDocument();
If you rather prefer to use your own rapidjson::Document
, you can use the static method Serialize
:
CFoo foo;
foo.m_int = 1337;
rapidjson::Document document;
// ...
// Any changes to document
// ...
DonerSerializer::CJsonSerializer::Serialize(foo, document);
You just need to load the json and use the static method CJsonDeserializer::Deserialize
CFoo foo;
DonerSerializer::CJsonDeserializer::Deserialize(foo, "{\"m_int\": 1337}");
// foo.m_int == 1337
You can also specify a specific rapidjson::Value
to deserialize data from:
rapidjson::Value value;
// ...
// Fill value with some data
// ...
CFoo foo;
DonerSerializer::CJsonDeserializer::Deserialize(foo, value);
In order to serialize you own classes, you just need to inherit from DonerSerialization::ISerializable
and to define the desired reflection data as mentioned above
class Foo : DonerSerialization::ISerializable
{
DONER_DECLARE_OBJECT_AS_REFLECTABLE(Foo)
protected:
int m_int;
}
DONER_DEFINE_REFLECTION_DATA(Foo,
DONER_ADD_VAR_INFO(m_int)
)
// ...
class Bar : public Foo
{
DONER_DECLARE_OBJECT_AS_REFLECTABLE(Bar)
private:
Foo m_foo;
}
DONER_DEFINE_REFLECTION_DATA(Bar,
DONER_ADD_VAR_INFO(m_foo)
)
A thirdparty type is a type defined in any external library, where you can't change the implementation of the types to make them usable by DonerSerializer.
To achieve this, you can specialize CDeserializationResolver::CDeserializationResolverType<>
and CSerializationResolver::CSerializationResolverType<>
. Here's an example on how to do it for SFML
sf::Vector2f
:
namespace DonerSerializer
{
template <>
class CDeserializationResolver::CDeserializationResolverType<sf::Vector2f>
{
public:
static void Apply(sf::Vector2f& value, const rapidjson::Value& att)
{
if (att.IsArray())
{
value = sf::Vector2f(att[0].GetFloat(), att[1].GetFloat());
}
}
};
template <>
class CSerializationResolver::CSerializationResolverType<sf::Vector2f>
{
public:
static void Apply(const char* name, const sf::Vector2f& value, rapidjson::Document& root)
{
rapidjson::Value array(rapidjson::kArrayType);
CSerializationResolver::CSerializationResolverType<float>::SerializeToJsonArray(array, value.x, root.GetAllocator());
CSerializationResolver::CSerializationResolverType<float>::SerializeToJsonArray(array, value.y, root.GetAllocator());
root.AddMember(rapidjson::GenericStringRef<char>(name), array, root.GetAllocator());
}
static void SerializeToJsonArray(rapidjson::Value& root, const sf::Vector2f& value, rapidjson::Document::AllocatorType& allocator)
{
rapidjson::Value array(rapidjson::kArrayType);
CSerializationResolver::CSerializationResolverType<float>::SerializeToJsonArray(array, value.x, allocator);
CSerializationResolver::CSerializationResolverType<float>::SerializeToJsonArray(array, value.y, allocator);
root.PushBack(array, allocator);
}
};
}