Rename Reflectable -> JSONSerializable

This allows to provide multiple independently
functional reflection features by simply using
different base classes for them.
This commit is contained in:
Martchus 2017-10-23 00:41:10 +02:00
parent 888feee3f4
commit 4a8ebc99a3
10 changed files with 101 additions and 64 deletions

View File

@ -5,17 +5,16 @@ set(META_PROJECT_TYPE library)
# add project files # add project files
set(HEADER_FILES set(HEADER_FILES
reflect.h jsonreflector.h
reflectable.h jsonserializable.h
) )
set(SRC_FILES set(SRC_FILES
reflect.cpp
) )
set(TEST_HEADER_FILES set(TEST_HEADER_FILES
) )
set(TEST_SRC_FILES set(TEST_SRC_FILES
tests/cppunit.cpp tests/cppunit.cpp
tests/reflector.cpp tests/jsonreflector.cpp
) )
set(DOC_FILES set(DOC_FILES
README.md README.md

View File

@ -1,5 +1,5 @@
#ifndef REFLECTIVE_RAPIDJSON_REFLECT_H #ifndef REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H
#define REFLECTIVE_RAPIDJSON_REFLECT_H #define REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H
#include <c++utilities/conversion/types.h> #include <c++utilities/conversion/types.h>
#include <c++utilities/misc/traits.h> #include <c++utilities/misc/traits.h>
@ -27,7 +27,7 @@ constexpr ErrorFlags operator|(ErrorFlags lhs, ErrorFlags rhs)
return static_cast<ErrorFlags>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs)); return static_cast<ErrorFlags>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs));
} }
template <typename Type> struct Reflectable; template <typename Type> struct JSONSerializable;
inline RAPIDJSON_NAMESPACE::StringBuffer documentToString(RAPIDJSON_NAMESPACE::Document &document) inline RAPIDJSON_NAMESPACE::StringBuffer documentToString(RAPIDJSON_NAMESPACE::Document &document)
{ {
@ -226,7 +226,7 @@ inline void pull(Type &reflectable, const char *name, const rapidjson::GenericVa
// define functions providing high-level JSON serialization // define functions providing high-level JSON serialization
template <typename Type, Traits::EnableIfAny<std::is_base_of<Reflectable<Type>, Type>>...> template <typename Type, Traits::EnableIfAny<std::is_base_of<JSONSerializable<Type>, Type>>...>
RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable) RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
{ {
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
@ -260,7 +260,7 @@ template <typename Type, Traits::EnableIfAny<std::is_same<Type, const char *>>..
// define functions providing high-level JSON deserialization // define functions providing high-level JSON deserialization
template <typename Type, Traits::EnableIfAny<std::is_base_of<Reflectable<Type>, Type>>...> Type fromJson(const char *json, std::size_t jsonSize) template <typename Type, Traits::EnableIfAny<std::is_base_of<JSONSerializable<Type>, Type>>...> Type fromJson(const char *json, std::size_t jsonSize)
{ {
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
document.Parse(json, jsonSize); document.Parse(json, jsonSize);
@ -290,19 +290,6 @@ template <typename Type> Type fromJson(const std::string &json)
} }
} // namespace Reflector } // namespace Reflector
} // namespace ReflectiveRapidJSON } // namespace ReflectiveRapidJSON
#define REFLECT(Type) \ #endif // REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H
namespace Reflector { \
template <> \
void push<Type>(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); \
template <> \
void add<Type>( \
const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); \
template <> std::string toJson<Type>(const Type &reflectable); \
template <> Type fromJson<Type>(const char *json, std::size_t jsonSize); \
template <> Type fromJson<Type>(const std::string &json); \
}
#endif // REFLECTIVE_RAPIDJSON_REFLECT_H

58
lib/jsonserializable.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef REFLECTIVE_RAPIDJSON_JSON_SERIALIZABLE_H
#define REFLECTIVE_RAPIDJSON_JSON_SERIALIZABLE_H
#include "./jsonreflector.h"
#include <rapidjson/document.h>
#include <string>
namespace ReflectiveRapidJSON {
template <typename Type> struct JSONSerializable {
// RapidJSON-level API
void push(RAPIDJSON_NAMESPACE::Value &container);
void push(RAPIDJSON_NAMESPACE::Value &container, const char *name);
// high-level API
RAPIDJSON_NAMESPACE::StringBuffer toJson() const;
static Type fromJson(const char *json, std::size_t jsonSize);
static Type fromJson(const char *json);
static Type fromJson(const std::string &json);
static constexpr const char *qualifiedName = "ReflectiveRapidJSON::JSONSerializable";
};
template <typename Type> void JSONSerializable<Type>::push(RAPIDJSON_NAMESPACE::Value &container)
{
return Reflector::push<Type>(*this, container);
}
template <typename Type> void JSONSerializable<Type>::push(RAPIDJSON_NAMESPACE::Value &container, const char *name)
{
return Reflector::push<Type>(*this, name, container);
}
template <typename Type> RAPIDJSON_NAMESPACE::StringBuffer JSONSerializable<Type>::toJson() const
{
return Reflector::toJson<Type>(static_cast<const Type &>(*this));
}
template <typename Type> Type JSONSerializable<Type>::fromJson(const char *json, std::size_t jsonSize)
{
return Reflector::fromJson<Type>(json, jsonSize);
}
template <typename Type> Type JSONSerializable<Type>::fromJson(const char *json)
{
return Reflector::fromJson<Type>(json, std::strlen(json));
}
template <typename Type> Type JSONSerializable<Type>::fromJson(const std::string &json)
{
return Reflector::fromJson<Type>(json.data(), json.size());
}
} // namespace ReflectiveRapidJSON
#endif // REFLECTIVE_RAPIDJSON_JSON_SERIALIZABLE_H

View File

@ -1,10 +0,0 @@
#include "./reflect.h"
using namespace RAPIDJSON_NAMESPACE;
namespace ReflectiveRapidJSON {
namespace Reflector {
}
} // namespace ReflectiveRapidJSON

View File

@ -9,7 +9,7 @@
namespace ReflectiveRapidJSON { namespace ReflectiveRapidJSON {
template <typename Type> struct Reflectable { template <typename Type> struct JSONSerializable {
// RapidJSON-level API // RapidJSON-level API
void push(RAPIDJSON_NAMESPACE::Value &container); void push(RAPIDJSON_NAMESPACE::Value &container);
void push(RAPIDJSON_NAMESPACE::Value &container, const char *name); void push(RAPIDJSON_NAMESPACE::Value &container, const char *name);
@ -21,32 +21,32 @@ template <typename Type> struct Reflectable {
static Type fromJson(const std::string &json); static Type fromJson(const std::string &json);
}; };
template <typename Type> void Reflectable<Type>::push(RAPIDJSON_NAMESPACE::Value &container) template <typename Type> void JSONSerializable<Type>::push(RAPIDJSON_NAMESPACE::Value &container)
{ {
return Reflector::push<Type>(*this, container); return Reflector::push<Type>(*this, container);
} }
template <typename Type> void Reflectable<Type>::push(RAPIDJSON_NAMESPACE::Value &container, const char *name) template <typename Type> void JSONSerializable<Type>::push(RAPIDJSON_NAMESPACE::Value &container, const char *name)
{ {
return Reflector::push<Type>(*this, name, container); return Reflector::push<Type>(*this, name, container);
} }
template <typename Type> RAPIDJSON_NAMESPACE::StringBuffer Reflectable<Type>::toJson() const template <typename Type> RAPIDJSON_NAMESPACE::StringBuffer JSONSerializable<Type>::toJson() const
{ {
return Reflector::toJson<Type>(static_cast<const Type &>(*this)); return Reflector::toJson<Type>(static_cast<const Type &>(*this));
} }
template <typename Type> Type Reflectable<Type>::fromJson(const char *json, std::size_t jsonSize) template <typename Type> Type JSONSerializable<Type>::fromJson(const char *json, std::size_t jsonSize)
{ {
return Reflector::fromJson<Type>(json, jsonSize); return Reflector::fromJson<Type>(json, jsonSize);
} }
template <typename Type> Type Reflectable<Type>::fromJson(const char *json) template <typename Type> Type JSONSerializable<Type>::fromJson(const char *json)
{ {
return Reflector::fromJson<Type>(json, std::strlen(json)); return Reflector::fromJson<Type>(json, std::strlen(json));
} }
template <typename Type> Type Reflectable<Type>::fromJson(const std::string &json) template <typename Type> Type JSONSerializable<Type>::fromJson(const std::string &json)
{ {
return Reflector::fromJson<Type>(json.data(), json.size()); return Reflector::fromJson<Type>(json.data(), json.size());
} }

View File

@ -1,6 +1,5 @@
#include "../reflectable.h" #include "../jsonreflector.h"
#include "../jsonserializable.h"
#include "resources/config.h"
#include <c++utilities/conversion/stringbuilder.h> #include <c++utilities/conversion/stringbuilder.h>
#include <c++utilities/conversion/stringconversion.h> #include <c++utilities/conversion/stringconversion.h>
@ -31,7 +30,7 @@ using namespace ReflectiveRapidJSON;
/// \cond /// \cond
// define some structs for testing serialization // define some structs for testing serialization
struct TestObject : public Reflectable<TestObject> { struct TestObject : public JSONSerializable<TestObject> {
int number; int number;
double number2; double number2;
vector<int> numbers; vector<int> numbers;
@ -39,12 +38,12 @@ struct TestObject : public Reflectable<TestObject> {
bool boolean; bool boolean;
}; };
struct NestingObject : public Reflectable<NestingObject> { struct NestingObject : public JSONSerializable<NestingObject> {
string name; string name;
TestObject testObj; TestObject testObj;
}; };
struct NestingArray : public Reflectable<NestingArray> { struct NestingArray : public JSONSerializable<NestingArray> {
string name; string name;
vector<TestObject> testObjects; vector<TestObject> testObjects;
}; };
@ -104,8 +103,8 @@ template <> inline void pull<NestingArray>(NestingArray &reflectable, const Gene
* \brief The ReflectorTests class tests RapidJSON wrapper which is used to ease code generation. * \brief The ReflectorTests class tests RapidJSON wrapper which is used to ease code generation.
* \remarks In this tests, no reflection or code generation is involved yet. * \remarks In this tests, no reflection or code generation is involved yet.
*/ */
class ReflectorTests : public TestFixture { class JSONReflectorTests : public TestFixture {
CPPUNIT_TEST_SUITE(ReflectorTests); CPPUNIT_TEST_SUITE(JSONReflectorTests);
CPPUNIT_TEST(experiment); CPPUNIT_TEST(experiment);
CPPUNIT_TEST(testSerializePrimitives); CPPUNIT_TEST(testSerializePrimitives);
CPPUNIT_TEST(testSerializeSimpleObjects); CPPUNIT_TEST(testSerializeSimpleObjects);
@ -130,20 +129,20 @@ public:
private: private:
}; };
CPPUNIT_TEST_SUITE_REGISTRATION(ReflectorTests); CPPUNIT_TEST_SUITE_REGISTRATION(JSONReflectorTests);
void ReflectorTests::setUp() void JSONReflectorTests::setUp()
{ {
} }
void ReflectorTests::tearDown() void JSONReflectorTests::tearDown()
{ {
} }
/*! /*!
* \brief Not a real test, just some assertions for experimenting with the RapidJSON library. * \brief Not a real test, just some assertions for experimenting with the RapidJSON library.
*/ */
void ReflectorTests::experiment() void JSONReflectorTests::experiment()
{ {
Document doc(kArrayType); Document doc(kArrayType);
Document::AllocatorType &alloc = doc.GetAllocator(); Document::AllocatorType &alloc = doc.GetAllocator();
@ -170,7 +169,7 @@ void ReflectorTests::experiment()
/*! /*!
* \brief Tests serializing strings, numbers, arrays and boolean. * \brief Tests serializing strings, numbers, arrays and boolean.
*/ */
void ReflectorTests::testSerializePrimitives() void JSONReflectorTests::testSerializePrimitives()
{ {
Document doc(kArrayType); Document doc(kArrayType);
Document::AllocatorType &alloc = doc.GetAllocator(); Document::AllocatorType &alloc = doc.GetAllocator();
@ -201,7 +200,7 @@ void ReflectorTests::testSerializePrimitives()
/*! /*!
* \brief Tests serializing objects. * \brief Tests serializing objects.
*/ */
void ReflectorTests::testSerializeSimpleObjects() void JSONReflectorTests::testSerializeSimpleObjects()
{ {
TestObject testObj; TestObject testObj;
testObj.number = 42; testObj.number = 42;
@ -216,7 +215,7 @@ void ReflectorTests::testSerializeSimpleObjects()
/*! /*!
* \brief Tests serializing nested object and arrays. * \brief Tests serializing nested object and arrays.
*/ */
void ReflectorTests::testSerializeNestedObjects() void JSONReflectorTests::testSerializeNestedObjects()
{ {
NestingObject nestingObj; NestingObject nestingObj;
nestingObj.name = "nesting"; nestingObj.name = "nesting";
@ -242,7 +241,7 @@ void ReflectorTests::testSerializeNestedObjects()
/*! /*!
* \brief Tests deserializing strings, numbers (int, float, double) and boolean. * \brief Tests deserializing strings, numbers (int, float, double) and boolean.
*/ */
void ReflectorTests::testDeserializePrimitives() void JSONReflectorTests::testDeserializePrimitives()
{ {
Document doc(kArrayType); Document doc(kArrayType);
@ -274,7 +273,7 @@ void ReflectorTests::testDeserializePrimitives()
/*! /*!
* \brief Tests deserializing simple objects. * \brief Tests deserializing simple objects.
*/ */
void ReflectorTests::testDeserializeSimpleObjects() void JSONReflectorTests::testDeserializeSimpleObjects()
{ {
const TestObject testObj( const TestObject testObj(
TestObject::fromJson("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}")); TestObject::fromJson("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}"));
@ -289,7 +288,7 @@ void ReflectorTests::testDeserializeSimpleObjects()
/*! /*!
* \brief Tests deserializing nested objects and arrays. * \brief Tests deserializing nested objects and arrays.
*/ */
void ReflectorTests::testDeserializeNestedObjects() void JSONReflectorTests::testDeserializeNestedObjects()
{ {
const NestingObject nestingObj(NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793," const NestingObject nestingObj(NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,"
"\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}")); "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}"));

View File

@ -45,5 +45,6 @@ include(WindowsResources)
include(AppTarget) include(AppTarget)
include(TestTarget) include(TestTarget)
include(ShellCompletion) include(ShellCompletion)
include(Doxygen)
include(ConfigHeader) include(ConfigHeader)

View File

@ -1,6 +1,8 @@
#include "./generator.h" #include "./generator.h"
#include "./frontendaction.h" #include "./frontendaction.h"
#include "../lib/jsonserializable.h"
#include <c++utilities/application/global.h> #include <c++utilities/application/global.h>
#include <c++utilities/conversion/stringbuilder.h> #include <c++utilities/conversion/stringbuilder.h>
@ -62,8 +64,8 @@ void JSONSerializationCodeGenerator::addDeclaration(clang::Decl *decl)
if (!record->hasDefinition()) { if (!record->hasDefinition()) {
return; return;
} }
// add classes derived from any instantiation of "ReflectiveRapidJSON::Reflectable" // add classes derived from any instantiation of "ReflectiveRapidJSON::JSONSerializable"
if (inheritsFromInstantiationOf(record, "ReflectiveRapidJSON::Reflectable")) { if (inheritsFromInstantiationOf(record, JSONSerializable<void>::qualifiedName)) {
m_relevantClasses.emplace_back(record->getQualifiedNameAsString(), record); m_relevantClasses.emplace_back(record->getQualifiedNameAsString(), record);
} }
break; break;
@ -86,7 +88,7 @@ void JSONSerializationCodeGenerator::generate(ostream &os) const
"namespace Reflector {\n"; "namespace Reflector {\n";
// add push and pull functions for each class, for an example of the resulting // add push and pull functions for each class, for an example of the resulting
// output, see ../lib/tests/reflector.cpp (code under comment "pretend serialization code...") // output, see ../lib/tests/jsonserializable.cpp (code under comment "pretend serialization code...")
for (const RelevantClass &relevantClass : m_relevantClasses) { for (const RelevantClass &relevantClass : m_relevantClasses) {
// print push method // print push method
os << "template <> inline void push<::" << relevantClass.qualifiedName << ">(const " << relevantClass.qualifiedName os << "template <> inline void push<::" << relevantClass.qualifiedName << ">(const " << relevantClass.qualifiedName

View File

@ -36,7 +36,8 @@ inline CodeGenerator::CodeGenerator()
} }
/*! /*!
* \brief The JSONSerializationCodeGenerator class generates code for JSON (de)serialization. * \brief The JSONSerializationCodeGenerator class generates code for JSON (de)serialization
* of objects inheriting from an instantiation of JSONSerializable.
*/ */
class JSONSerializationCodeGenerator : public CodeGenerator { class JSONSerializationCodeGenerator : public CodeGenerator {
public: public:

View File

@ -2,13 +2,13 @@
#define SOME_STRUCTS_H #define SOME_STRUCTS_H
//#include <string> //#include <string>
#include "../../lib/reflectable.h" #include "../../lib/jsonserializable.h"
namespace TestNamespace1 { namespace TestNamespace1 {
#define SOME_MACRO #define SOME_MACRO
struct Person : public ReflectiveRapidJSON::Reflectable<Person> struct Person : public ReflectiveRapidJSON::JSONSerializable<Person>
{ {
SOME_MACRO SOME_MACRO
//std::string name; //std::string name;