Consider base classes when generating code for (de)serialization
This commit is contained in:
parent
617ee58b91
commit
3008e3ad6e
|
@ -84,9 +84,18 @@ void JSONSerializationCodeGenerator::generate(ostream &os) const
|
|||
// add push and pull functions for each class, for an example of the resulting
|
||||
// output, see ../lib/tests/jsonserializable.cpp (code under comment "pretend serialization code...")
|
||||
for (const RelevantClass &relevantClass : m_relevantClasses) {
|
||||
// write comment
|
||||
os << "// define code for (de)serializing " << relevantClass.qualifiedName << " objects\n";
|
||||
|
||||
// find relevant base classes
|
||||
const vector<const RelevantClass *> relevantBases = findRelevantBaseClasses(relevantClass);
|
||||
|
||||
// print push method
|
||||
os << "template <> inline void push<::" << relevantClass.qualifiedName << ">(const ::" << relevantClass.qualifiedName
|
||||
<< " &reflectable, ::RAPIDJSON_NAMESPACE::Value::Object &value, ::RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)\n{\n";
|
||||
for (const RelevantClass *baseClass : relevantBases) {
|
||||
os << " push(static_cast<const ::" << baseClass->qualifiedName << " &>(reflectable), value, allocator);\n";
|
||||
}
|
||||
for (const clang::FieldDecl *field : relevantClass.record->fields()) {
|
||||
os << " push(reflectable." << field->getName() << ", \"" << field->getName() << "\", value, allocator);\n";
|
||||
}
|
||||
|
@ -95,6 +104,9 @@ void JSONSerializationCodeGenerator::generate(ostream &os) const
|
|||
// print pull method
|
||||
os << "template <> inline void pull<::" << relevantClass.qualifiedName << ">(::" << relevantClass.qualifiedName
|
||||
<< " &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value)\n{\n";
|
||||
for (const RelevantClass *baseClass : relevantBases) {
|
||||
os << " pull(static_cast<::" << baseClass->qualifiedName << " &>(reflectable), value);\n";
|
||||
}
|
||||
for (const clang::FieldDecl *field : relevantClass.record->fields()) {
|
||||
os << " pull(reflectable." << field->getName() << ", \"" << field->getName() << "\", value);\n";
|
||||
}
|
||||
|
@ -106,4 +118,16 @@ void JSONSerializationCodeGenerator::generate(ostream &os) const
|
|||
"} // namespace ReflectiveRapidJSON\n";
|
||||
}
|
||||
|
||||
std::vector<const JSONSerializationCodeGenerator::RelevantClass *> JSONSerializationCodeGenerator::findRelevantBaseClasses(
|
||||
const RelevantClass &relevantClass) const
|
||||
{
|
||||
vector<const RelevantClass *> relevantBaseClasses;
|
||||
for (const RelevantClass &otherClass : m_relevantClasses) {
|
||||
if (relevantClass.record->isDerivedFrom(otherClass.record)) {
|
||||
relevantBaseClasses.push_back(&otherClass);
|
||||
}
|
||||
}
|
||||
return relevantBaseClasses;
|
||||
}
|
||||
|
||||
} // namespace ReflectiveRapidJSON
|
||||
|
|
|
@ -65,6 +65,8 @@ private:
|
|||
clang::CXXRecordDecl *record;
|
||||
};
|
||||
|
||||
std::vector<const RelevantClass *> findRelevantBaseClasses(const RelevantClass &relevantClass) const;
|
||||
|
||||
std::vector<RelevantClass> m_relevantClasses;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
namespace ReflectiveRapidJSON {
|
||||
namespace Reflector {
|
||||
|
||||
// define code for (de)serializing TestNamespace1::Person objects
|
||||
template <> inline void push<::TestNamespace1::Person>(const ::TestNamespace1::Person &reflectable, ::RAPIDJSON_NAMESPACE::Value::Object &value, ::RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
||||
{
|
||||
push(reflectable.age, "age", value, allocator);
|
||||
|
|
|
@ -34,6 +34,40 @@ struct TestStruct : public JSONSerializable<TestStruct> {
|
|||
string yetAnotherString = "bar";
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The AnotherTestStruct struct inherits from JSONSerializable and should hence have functional fromJson()
|
||||
* and toJson() methods. This is asserted in OverallTests::testInheritence();
|
||||
*/
|
||||
struct AnotherTestStruct : public JSONSerializable<AnotherTestStruct> {
|
||||
vector<string> arrayOfStrings{ "a", "b", "cd" };
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The DerivedTestStruct struct inherits from JSONSerializable and should hence have functional fromJson()
|
||||
* and toJson() methods. This is asserted in OverallTests::testInheritence();
|
||||
*/
|
||||
struct DerivedTestStruct : public TestStruct, public JSONSerializable<DerivedTestStruct> {
|
||||
bool someBool = true;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The NonSerializable struct should be ignored when used as base class because it isn't serializable.
|
||||
*/
|
||||
struct NonSerializable {
|
||||
int ignored = 25;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The MultipleDerivedTestStruct struct inherits from JSONSerializable and should hence have functional fromJson()
|
||||
* and toJson() methods. This is asserted in OverallTests::testInheritence();
|
||||
*/
|
||||
struct MultipleDerivedTestStruct : public TestStruct,
|
||||
public AnotherTestStruct,
|
||||
public NonSerializable,
|
||||
public JSONSerializable<MultipleDerivedTestStruct> {
|
||||
bool someBool = false;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The OverallTests class tests the overall functionality of the code generator (CLI and generator itself).
|
||||
*/
|
||||
|
@ -42,6 +76,8 @@ class OverallTests : public TestFixture {
|
|||
CPPUNIT_TEST(testGeneratorItself);
|
||||
CPPUNIT_TEST(testCLI);
|
||||
CPPUNIT_TEST(testIncludingGeneratedHeader);
|
||||
CPPUNIT_TEST(testSingleInheritence);
|
||||
CPPUNIT_TEST(testMultipleInheritence);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
|
@ -51,6 +87,8 @@ public:
|
|||
void testGeneratorItself();
|
||||
void testCLI();
|
||||
void testIncludingGeneratedHeader();
|
||||
void testSingleInheritence();
|
||||
void testMultipleInheritence();
|
||||
|
||||
private:
|
||||
vector<string> m_expectedCode;
|
||||
|
@ -150,6 +188,58 @@ void OverallTests::testIncludingGeneratedHeader()
|
|||
CPPUNIT_ASSERT_EQUAL(test.yetAnotherString, parsedTest.yetAnotherString);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Like testIncludingGeneratedHeader() but also tests single inheritence.
|
||||
*/
|
||||
void OverallTests::testSingleInheritence()
|
||||
{
|
||||
DerivedTestStruct test;
|
||||
test.someInt = 42;
|
||||
test.someString = "the answer";
|
||||
test.yetAnotherString = "but what was the question";
|
||||
test.someBool = false;
|
||||
const string expectedJSONForBase("{\"someInt\":42,\"someString\":\"the answer\",\"yetAnotherString\":\"but what was the question\"}");
|
||||
const string expectedJSONForDerived(
|
||||
"{\"someInt\":42,\"someString\":\"the answer\",\"yetAnotherString\":\"but what was the question\",\"someBool\":false}");
|
||||
|
||||
// test serialization
|
||||
CPPUNIT_ASSERT_EQUAL(expectedJSONForBase, string(static_cast<const JSONSerializable<TestStruct> &>(test).toJson().GetString()));
|
||||
CPPUNIT_ASSERT_EQUAL(expectedJSONForDerived, string(static_cast<const JSONSerializable<DerivedTestStruct> &>(test).toJson().GetString()));
|
||||
|
||||
// test deserialization
|
||||
const DerivedTestStruct parsedTest(JSONSerializable<DerivedTestStruct>::fromJson(expectedJSONForDerived));
|
||||
CPPUNIT_ASSERT_EQUAL(test.someInt, parsedTest.someInt);
|
||||
CPPUNIT_ASSERT_EQUAL(test.someString, parsedTest.someString);
|
||||
CPPUNIT_ASSERT_EQUAL(test.yetAnotherString, parsedTest.yetAnotherString);
|
||||
CPPUNIT_ASSERT_EQUAL(test.someBool, parsedTest.someBool);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Like testIncludingGeneratedHeader() but also tests multiple inheritence.
|
||||
*/
|
||||
void OverallTests::testMultipleInheritence()
|
||||
{
|
||||
MultipleDerivedTestStruct test;
|
||||
test.someInt = 42;
|
||||
test.someString = "the answer";
|
||||
test.yetAnotherString = "but what was the question";
|
||||
test.someBool = false;
|
||||
test.arrayOfStrings = { "array", "of", "strings" };
|
||||
const string expectedJSONForDerived("{\"someInt\":42,\"someString\":\"the answer\",\"yetAnotherString\":\"but what was the "
|
||||
"question\",\"arrayOfStrings\":[\"array\",\"of\",\"strings\"],\"someBool\":false}");
|
||||
|
||||
// test serialization
|
||||
CPPUNIT_ASSERT_EQUAL(expectedJSONForDerived, string(static_cast<const JSONSerializable<MultipleDerivedTestStruct> &>(test).toJson().GetString()));
|
||||
|
||||
// test deserialization
|
||||
const MultipleDerivedTestStruct parsedTest(JSONSerializable<MultipleDerivedTestStruct>::fromJson(expectedJSONForDerived));
|
||||
CPPUNIT_ASSERT_EQUAL(test.someInt, parsedTest.someInt);
|
||||
CPPUNIT_ASSERT_EQUAL(test.someString, parsedTest.someString);
|
||||
CPPUNIT_ASSERT_EQUAL(test.yetAnotherString, parsedTest.yetAnotherString);
|
||||
CPPUNIT_ASSERT_EQUAL(test.someBool, parsedTest.someBool);
|
||||
CPPUNIT_ASSERT_EQUAL(test.arrayOfStrings, parsedTest.arrayOfStrings);
|
||||
}
|
||||
|
||||
// include file required for reflection of TestStruct; generation of this header is triggered using
|
||||
// the CMake function add_reflection_generator_invocation()
|
||||
#include "reflection.h"
|
||||
|
|
Loading…
Reference in New Issue