Imporve documentation and build script

This commit is contained in:
Martchus 2017-10-28 18:24:12 +02:00
parent a768408493
commit 104e362762
8 changed files with 229 additions and 135 deletions

View File

@ -16,8 +16,11 @@ set(META_APP_VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_
# set project name for IDEs like Qt Creator
project(${META_PROJECT_NAME})
# ensure testing is enabled at this level (and not only for particular sub directories)
enable_testing()
# allow bundling c++utilities
set(BUNDLED_CPP_UTILITIES_PATH OFF CACHE FILEPATH "specifies the (relative) path to the c++utilities sources for building it together with ${META_PROJECT_NAME}")
set(BUNDLED_CPP_UTILITIES_PATH OFF CACHE PATH "specifies the (relative) path to the c++utilities sources for building it together with ${META_PROJECT_NAME}")
if(NOT BUNDLED_CPP_UTILITIES_PATH)
message(STATUS "Using system c++utilities")
elseif(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${BUNDLED_CPP_UTILITIES_PATH}" OR IS_DIRECTORY "${BUNDLED_CPP_UTILITIES_PATH}")

View File

@ -1,4 +1,4 @@
# reflective-rapidjson
# Reflective RapidJSON
The main goal of this project is to provide a code generator for serializing/deserializing C++ objects to/from JSON
using Clang and RapidJSON.
@ -131,9 +131,34 @@ makes use of the `reflective-rapidjson`.
### How to build
Install all required dependencies and ensure the CMake script finds them. It is possible to build `c++utilities`
together `reflective-rapidjson` to ease the build process. The following build script makes use of this. To use
system `c++utilities`, just skip any lines with `c++utilities` in it.
together with `reflective-rapidjson` to simplify the build process. The following build script makes use of this.
To use system `c++utilities`, just skip any lines with "`c++utilities`" in the following examples.
Get sources, eg. using Git:
```
TODO
cd $SOURCES
git clone https://github.com/Martchus/cpp-utilities.git c++utilities
git clone https://github.com/Martchus/reflective-rapidjson.git
```
If you don't want to build the development version, just checkout the desired version tag.
Here is an example for building with CMake and GNU Make:
```
cd $BUILD_DIR
# generate Makefile
cmake \
-DCMAKE_BUILD_TYPE:STRING=Release \
-DCMAKE_INSTALL_PREFIX:PATH="/final/install/prefix" \
-DBUNDLED_CPP_UTILITIES_PATH:PATH="$SOURCES/c++utilities" \
"$SOURCES/reflective-rapidjson"
# build library and generators
make
# run test (optional, requires CppUnit)
make check
# generates API documentation (optional, reqquires Doxygen)
make apidoc
# install header files, libraries and generator
make install DESTDIR="/temporary/install/location"
```
Add eg. `-j$(nproc)` to `make` arguments for using all cores.

View File

@ -34,23 +34,27 @@ set(TEST_SRC_FILES
tests/jsongenerator.cpp
)
# find c++utilities
# find c++utilities and link against the library
find_package(c++utilities 4.11.0 REQUIRED)
use_cpp_utilities()
# find libclang
# find Clang for LibTooling; adding clangTooling should be sufficient as it pulls all transitive dependencies
find_package(Clang REQUIRED)
list(APPEND PRIVATE_LIBRARIES clangTooling)
# also add reflective_rapidjson
# also add reflective_rapidjson which is header-only but might pull additional include dirs for RapidJSON
list(APPEND PRIVATE_LIBRARIES reflective_rapidjson)
# trigger code generator for tests
# trigger code generator because the tests already contain structs to be (de)serialized
include(ReflectionGenerator)
add_reflection_generator_invocation(
INPUT_FILES tests/structs.h tests/cppunit.cpp
GENERATORS json
OUTPUT_LISTS TEST_HEADER_FILES
INPUT_FILES
tests/structs.h # used by test cases
tests/cppunit.cpp # just for testing multiple input files and the "empty file" case
GENERATORS
json
OUTPUT_LISTS
TEST_HEADER_FILES
)
# include modules to apply configuration

View File

@ -26,9 +26,20 @@ set(DOC_FILES
README.md
)
# find c++utilities
# find c++utilities, but only add the include dirs because we're not depending on the actual library
find_package(c++utilities 4.11.0 REQUIRED)
use_cpp_utilities()
list(APPEND PUBLIC_SHARED_INCLUDE_DIRS ${CPP_UTILITIES_INCLUDE_DIRS})
list(APPEND PUBLIC_STATIC_INCLUDE_DIRS ${CPP_UTILITIES_INCLUDE_DIRS})
list(APPEND CMAKE_MODULE_PATH ${CPP_UTILITIES_MODULE_DIRS})
# find RapidJSON, also add only the include dirs because RapidJSON is a header-only library
find_package(RapidJSON)
if(RapidJSON_FOUND)
list(APPEND PUBLIC_SHARED_INCLUDE_DIRS ${RAPIDJSON_INCLUDE_DIRS})
list(APPEND PUBLIC_STATIC_INCLUDE_DIRS ${RAPIDJSON_INCLUDE_DIRS})
else()
message(FATAL_ERROR "Unable to find RapidJSON. Since this is the only reflection application supported at this time it makes no sense to continue.")
endif()
# include modules to apply configuration
include(BasicConfig)

View File

@ -11,6 +11,7 @@
#include <rapidjson/rapidjson.h>
#include <limits>
#include <list>
#include <string>
#include <vector>

View File

@ -23,7 +23,10 @@ namespace ReflectiveRapidJSON {
template <typename Type> struct JsonSerializable;
inline RAPIDJSON_NAMESPACE::StringBuffer documentToString(RAPIDJSON_NAMESPACE::Document &document)
/*!
* \brief Serializes the specified JSON \a document.
*/
inline RAPIDJSON_NAMESPACE::StringBuffer serializeJsonDocToString(RAPIDJSON_NAMESPACE::Document &document)
{
RAPIDJSON_NAMESPACE::StringBuffer buffer;
RAPIDJSON_NAMESPACE::Writer<RAPIDJSON_NAMESPACE::StringBuffer> writer(buffer);
@ -31,7 +34,10 @@ inline RAPIDJSON_NAMESPACE::StringBuffer documentToString(RAPIDJSON_NAMESPACE::D
return buffer;
}
inline RAPIDJSON_NAMESPACE::Document parseDocumentFromString(const char *json, std::size_t jsonSize)
/*!
* \brief Parses the specified JSON string.
*/
inline RAPIDJSON_NAMESPACE::Document parseJsonDocFromString(const char *json, std::size_t jsonSize)
{
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
const RAPIDJSON_NAMESPACE::ParseResult parseRes = document.Parse(json, jsonSize);
@ -45,22 +51,35 @@ namespace Reflector {
// define functions to "push" values to a RapidJSON array or object
/*!
* \brief Pushes the \a reflectable which has a custom type to the specified array.
*/
template <typename Type,
Traits::DisableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>,
Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>>...>
void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
/*!
* \brief Pushes the \a reflectable which has a custom type to the specified object.
* \remarks The definition of this function must be provided by the code generator or Boost.Hana.
*/
template <typename Type,
Traits::DisableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>,
Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>>...>
void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
/*!
* \brief Pushes the specified integer/float/boolean to the specified array.
*/
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>>...>
inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
{
value.PushBack(reflectable, allocator);
}
/*!
* \brief Pushes the specified C-string to the specified array.
*/
template <>
inline void push<const char *>(
const char *reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
@ -68,13 +87,9 @@ inline void push<const char *>(
value.PushBack(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator);
}
template <>
inline void push<std::string>(
const std::string &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
{
value.PushBack(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator);
}
/*!
* \brief Pushes the specified constant C-string to the specified array.
*/
template <>
inline void push<const char *const &>(
const char *const &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
@ -82,6 +97,19 @@ inline void push<const char *const &>(
value.PushBack(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator);
}
/*!
* \brief Pushes the specified std::string to the specified array.
*/
template <>
inline void push<std::string>(
const std::string &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
{
value.PushBack(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator);
}
/*!
* \brief Pushes the specified iteratable (eg. std::vector, std::list) to the specified array.
*/
template <typename Type, Traits::EnableIf<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
{
@ -94,6 +122,9 @@ void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAP
value.PushBack(array, allocator);
}
/*!
* \brief Pushes the specified \a reflectable which has a custom type as member to the specified object.
*/
template <typename Type,
Traits::DisableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>,
Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>>...>
@ -106,6 +137,9 @@ inline void push(
value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), object, allocator);
}
/*!
* \brief Pushes the specified integer/float/boolean as member to the specified object.
*/
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>>...>
inline void push(
Type reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
@ -113,13 +147,9 @@ inline void push(
value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), reflectable, allocator);
}
template <>
inline void push<std::string>(const std::string &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value,
RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
{
value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator);
}
/*!
* \brief Pushes the specified C-string as member to the specified object.
*/
template <>
inline void push<const char *>(
const char *reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
@ -127,6 +157,9 @@ inline void push<const char *>(
value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator);
}
/*!
* \brief Pushes the specified constant C-string as member to the specified object.
*/
template <>
inline void push<const char *const &>(const char *const &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value,
RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
@ -134,6 +167,19 @@ inline void push<const char *const &>(const char *const &reflectable, const char
value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator);
}
/*!
* \brief Pushes the specified std::string as member to the specified object.
*/
template <>
inline void push<std::string>(const std::string &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value,
RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
{
value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator);
}
/*!
* \brief Pushes the specified iteratable without size() method as member to the specified object.
*/
template <typename Type,
Traits::EnableIf<Traits::IsIteratable<Type>, Traits::Not<Traits::HasSize<Type>>,
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
@ -148,6 +194,9 @@ void push(
value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), array, allocator);
}
/*!
* \brief Pushes the specified iteratable with size() method (eg. std::vector, std::list) as member to the specified object.
*/
template <typename Type,
Traits::EnableIf<Traits::IsIteratable<Type>, Traits::HasSize<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
void push(
@ -162,6 +211,9 @@ void push(
value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), array, allocator);
}
/*!
* \brief Pushes the \a reflectable which has a custom type to the specified array.
*/
template <typename Type,
Traits::DisableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>,
Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>>...>
@ -175,18 +227,28 @@ void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAP
// define functions to "pull" values from a RapidJSON array or object
/*!
* \brief Pulls the \a reflectable which has a custom type from the specified value.
*/
template <typename Type,
Traits::DisableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>,
Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>>...>
void pull(
Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors);
/*!
* \brief Pulls the \a reflectable which has a custom type from the specified object.
* \remarks The definition of this function must be provided by the code generator or Boost.Hana.
*/
template <typename Type,
Traits::DisableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>,
Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>>...>
void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
JsonDeserializationErrors *errors);
/*!
* \brief Pulls the \a reflectable which has a custom type from the specified value which is supposed and checked to contain an object.
*/
template <typename Type,
Traits::DisableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>,
Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>>...>
@ -201,6 +263,9 @@ void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_N
pull<Type>(reflectable, value.GetObject(), errors);
}
/*!
* \brief Pulls the integer/float/boolean from the specified value iterator which is supposed and checked to contain the right type.
*/
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>>...>
inline void pull(
Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors)
@ -215,6 +280,9 @@ inline void pull(
++value;
}
/*!
* \brief Pulls the integer/float/boolean from the specified value which is supposed and checked to contain the right type.
*/
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>>...>
inline void pull(
Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
@ -228,6 +296,9 @@ inline void pull(
reflectable = value.Get<Type>();
}
/*!
* \brief Pulls the std::string from the specified value iterator which is supposed and checked to contain a string.
*/
template <>
inline void pull<std::string>(std::string &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value,
JsonDeserializationErrors *errors)
@ -242,6 +313,9 @@ inline void pull<std::string>(std::string &reflectable, RAPIDJSON_NAMESPACE::Gen
++value;
}
/*!
* \brief Pulls the std::string from the specified value which is supposed and checked to contain a string.
*/
template <>
inline void pull<std::string>(
std::string &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
@ -255,9 +329,15 @@ inline void pull<std::string>(
reflectable = value.GetString();
}
/*!
* \brief Pulls the speciified \a reflectable which is an iteratable from the specified array. The \a reflectable is cleared before.
*/
template <typename Type, Traits::EnableIf<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
/*!
* \brief Pulls the speciified \a reflectable which is an iteratable without reserve() method from the specified value iterator which is checked to contain an array.
*/
template <typename Type,
Traits::EnableIf<Traits::IsIteratable<Type>, Traits::Not<Traits::IsReservable<Type>>,
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
@ -273,6 +353,9 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
++value;
}
/*!
* \brief Pulls the speciified \a reflectable which is an iteratable with reserve() method from the specified value iterator which is checked to contain an array.
*/
template <typename Type,
Traits::EnableIf<Traits::IsIteratable<Type>, Traits::IsReservable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors)
@ -289,6 +372,9 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
++value;
}
/*!
* \brief Pulls the speciified \a reflectable which is an iteratable without reserve() method from the specified value which is checked to contain an array.
*/
template <typename Type,
Traits::EnableIf<Traits::IsIteratable<Type>, Traits::Not<Traits::IsReservable<Type>>,
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
@ -303,6 +389,9 @@ void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::
pull(reflectable, value.GetArray(), errors);
}
/*!
* \brief Pulls the speciified \a reflectable which is an iteratable with reserve() method from the specified value which is checked to contain an array.
*/
template <typename Type,
Traits::EnableIf<Traits::IsIteratable<Type>, Traits::IsReservable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
@ -318,6 +407,9 @@ void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::
pull(reflectable, array, errors);
}
/*!
* \brief Pulls the speciified \a reflectable which is an iteratable from the specified array. The \a reflectable is cleared before.
*/
template <typename Type, Traits::EnableIf<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
{
@ -342,6 +434,11 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
}
}
/*!
* \brief Pulls the speciified member of \a reflectable which has a custom type from the specified object.
* \remarks It is checked whether the object actually contains the member. If not, the missing member is ignored. So currently all members
* are optional.
*/
template <typename Type>
inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
JsonDeserializationErrors *errors)
@ -370,44 +467,59 @@ inline void pull(Type &reflectable, const char *name, const rapidjson::GenericVa
// define functions providing high-level JSON serialization
/*!
* \brief Serializes the specified \a reflectable which has a custom type.
*/
template <typename Type, Traits::EnableIfAny<std::is_base_of<JsonSerializable<Type>, Type>>...>
RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
{
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
RAPIDJSON_NAMESPACE::Document::Object object(document.GetObject());
push(reflectable, object, document.GetAllocator());
return documentToString(document);
return serializeJsonDocToString(document);
}
/*!
* \brief Serializes the specified \a reflectable which is an integer, float or boolean.
*/
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>...>
RAPIDJSON_NAMESPACE::StringBuffer toJson(Type reflectable)
{
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kNumberType);
document.Set(reflectable, document.GetAllocator());
return documentToString(document);
return serializeJsonDocToString(document);
}
/*!
* \brief Serializes the specified \a reflectable which is an std::string.
*/
template <typename Type, Traits::EnableIfAny<std::is_same<Type, std::string>>...>
RAPIDJSON_NAMESPACE::StringBuffer toJson(const std::string &reflectable)
{
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), document.GetAllocator());
return documentToString(document);
return serializeJsonDocToString(document);
}
/*!
* \brief Serializes the specified \a reflectable which is a C-string.
*/
template <typename Type, Traits::EnableIfAny<std::is_same<Type, const char *>>...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const char *reflectable)
{
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), document.GetAllocator());
return documentToString(document);
return serializeJsonDocToString(document);
}
// define functions providing high-level JSON deserialization
/*!
* \brief Deserializes the specified JSON to \tparam Type which is a custom type.
*/
template <typename Type, Traits::EnableIfAny<std::is_base_of<JsonSerializable<Type>, Type>>...>
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
{
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
if (!doc.IsObject()) {
if (errors) {
errors->reportTypeMismatch<Type>(doc.GetType());
@ -420,10 +532,13 @@ Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors
return res;
}
/*!
* \brief Deserializes the specified JSON to \tparam Type which is an integer, float or boolean.
*/
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>...>
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors)
{
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
if (!doc.Is<Type>()) {
if (errors) {
errors->reportTypeMismatch<Type>(doc.GetType());
@ -434,10 +549,13 @@ Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors
return doc.Get<Type>();
}
/*!
* \brief Deserializes the specified JSON to \tparam Type which is a std::string.
*/
template <typename Type, Traits::EnableIfAny<std::is_same<Type, std::string>>...>
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors)
{
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
if (!doc.IsString()) {
if (errors) {
errors->reportTypeMismatch<Type>(doc.GetType());
@ -448,6 +566,9 @@ Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors
return doc.GetString();
}
/*!
* \brief Deserializes the specified JSON from an std::string to \tparam Type.
*/
template <typename Type> Type fromJson(const std::string &json)
{
return fromJson<Type>(json.data(), json.size());

View File

@ -31,11 +31,6 @@ using namespace ReflectiveRapidJSON;
// define some structs for testing serialization
struct TestObjectHana : public JsonSerializable<TestObjectHana> {
//TestObjectHana(){};
//TestObjectHana(const TestObjectHana &)
//{
// std::cout << "copied!!" << std::endl;
//};
BOOST_HANA_DEFINE_STRUCT(TestObjectHana, (int, number), (double, number2), (vector<int>, numbers), (string, text), (bool, boolean));
};
@ -50,15 +45,13 @@ struct NestingArrayHana : public JsonSerializable<NestingArrayHana> {
/// \endcond
/*!
* \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.
* \brief The JsonReflectorBoostHanaTests class tests the integration of Boost.Hana with the RapidJSON wrapper.
* \remarks In these tests, the reflection is provided through Boost.Hana so the code generator is not involved.
*/
class JSONReflectorBoostHanaTests : public TestFixture {
CPPUNIT_TEST_SUITE(JSONReflectorBoostHanaTests);
CPPUNIT_TEST(testSerializePrimitives);
class JsonReflectorBoostHanaTests : public TestFixture {
CPPUNIT_TEST_SUITE(JsonReflectorBoostHanaTests);
CPPUNIT_TEST(testSerializeSimpleObjects);
CPPUNIT_TEST(testSerializeNestedObjects);
CPPUNIT_TEST(testDeserializePrimitives);
CPPUNIT_TEST(testDeserializeSimpleObjects);
CPPUNIT_TEST(testDeserializeNestedObjects);
CPPUNIT_TEST(testHandlingTypeMismatch);
@ -79,51 +72,20 @@ public:
private:
};
CPPUNIT_TEST_SUITE_REGISTRATION(JSONReflectorBoostHanaTests);
CPPUNIT_TEST_SUITE_REGISTRATION(JsonReflectorBoostHanaTests);
void JSONReflectorBoostHanaTests::setUp()
void JsonReflectorBoostHanaTests::setUp()
{
}
void JSONReflectorBoostHanaTests::tearDown()
void JsonReflectorBoostHanaTests::tearDown()
{
}
/*!
* \brief Tests serializing strings, numbers, arrays and boolean.
*/
void JSONReflectorBoostHanaTests::testSerializePrimitives()
{
Document doc(kArrayType);
Document::AllocatorType &alloc = doc.GetAllocator();
doc.SetArray();
Document::Array array(doc.GetArray());
// string
Reflector::push<string>("foo"s, array, alloc);
Reflector::push<const char *>("bar", array, alloc);
// number
Reflector::push<int>(25, array, alloc);
Reflector::push<double>(12.5, array, alloc);
// array
Reflector::push<vector<const char *>>({ "foo1", "bar1" }, array, alloc);
Reflector::push<list<const char *>>({ "foo2", "bar2" }, array, alloc);
Reflector::push<initializer_list<const char *>>({ "foo3", "bar3" }, array, alloc);
// boolean
Reflector::push<bool>(true, array, alloc);
Reflector::push<bool>(false, array, alloc);
StringBuffer strbuf;
Writer<StringBuffer> jsonWriter(strbuf);
doc.Accept(jsonWriter);
CPPUNIT_ASSERT_EQUAL(
"[\"foo\",\"bar\",25,12.5,[\"foo1\",\"bar1\"],[\"foo2\",\"bar2\"],[\"foo3\",\"bar3\"],true,false]"s, string(strbuf.GetString()));
}
/*!
* \brief Tests serializing objects.
*/
void JSONReflectorBoostHanaTests::testSerializeSimpleObjects()
void JsonReflectorBoostHanaTests::testSerializeSimpleObjects()
{
TestObjectHana testObj;
testObj.number = 42;
@ -138,7 +100,7 @@ void JSONReflectorBoostHanaTests::testSerializeSimpleObjects()
/*!
* \brief Tests serializing nested object and arrays.
*/
void JSONReflectorBoostHanaTests::testSerializeNestedObjects()
void JsonReflectorBoostHanaTests::testSerializeNestedObjects()
{
NestingObjectHana nestingObj;
nestingObj.name = "nesting";
@ -161,43 +123,10 @@ void JSONReflectorBoostHanaTests::testSerializeNestedObjects()
string(nestingArray.toJson().GetString()));
}
/*!
* \brief Tests deserializing strings, numbers (int, float, double) and boolean.
*/
void JSONReflectorBoostHanaTests::testDeserializePrimitives()
{
Document doc(kArrayType);
doc.Parse("[\"a\", 5, 5e6, \"test\", true, 4.125, false]");
auto array = doc.GetArray().begin();
string str1, str2;
int int1 = 0;
bool bool1 = false, bool2 = true;
float float1 = 0.0;
double double1 = 0.0;
JsonDeserializationErrors errors;
Reflector::pull(str1, array, &errors);
Reflector::pull(int1, array, &errors);
Reflector::pull(float1, array, &errors);
Reflector::pull(str2, array, &errors);
Reflector::pull(bool1, array, &errors);
Reflector::pull(double1, array, &errors);
Reflector::pull(bool2, array, &errors);
CPPUNIT_ASSERT_EQUAL("a"s, str1);
CPPUNIT_ASSERT_EQUAL(5, int1);
CPPUNIT_ASSERT_EQUAL(5e6f, float1);
CPPUNIT_ASSERT_EQUAL("test"s, str2);
CPPUNIT_ASSERT_EQUAL(true, bool1);
CPPUNIT_ASSERT_EQUAL(4.125, double1);
CPPUNIT_ASSERT_EQUAL(false, bool2);
}
/*!
* \brief Tests deserializing simple objects.
*/
void JSONReflectorBoostHanaTests::testDeserializeSimpleObjects()
void JsonReflectorBoostHanaTests::testDeserializeSimpleObjects()
{
const TestObjectHana testObj(
TestObjectHana::fromJson("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}"));
@ -212,7 +141,7 @@ void JSONReflectorBoostHanaTests::testDeserializeSimpleObjects()
/*!
* \brief Tests deserializing nested objects and arrays.
*/
void JSONReflectorBoostHanaTests::testDeserializeNestedObjects()
void JsonReflectorBoostHanaTests::testDeserializeNestedObjects()
{
const NestingObjectHana nestingObj(NestingObjectHana::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,"
"\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}"));
@ -244,7 +173,7 @@ void JSONReflectorBoostHanaTests::testDeserializeNestedObjects()
/*!
* \brief Tests whether JsonDeserializationError is thrown on type mismatch.
*/
void JSONReflectorBoostHanaTests::testHandlingTypeMismatch()
void JsonReflectorBoostHanaTests::testHandlingTypeMismatch()
{
JsonDeserializationErrors errors;
NestingArrayHana::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"

View File

@ -129,11 +129,11 @@ inline void pull<NestingArray>(NestingArray &reflectable, const GenericValue<UTF
/// \endcond
/*!
* \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.
* \brief The JsonReflectorTests class tests RapidJSON wrapper which is used to ease code generation.
* \remarks In these tests, the required reflection code is provided by hand so the generator isn't involved yet.
*/
class JSONReflectorTests : public TestFixture {
CPPUNIT_TEST_SUITE(JSONReflectorTests);
class JsonReflectorTests : public TestFixture {
CPPUNIT_TEST_SUITE(JsonReflectorTests);
CPPUNIT_TEST(testSerializePrimitives);
CPPUNIT_TEST(testSerializeSimpleObjects);
CPPUNIT_TEST(testSerializeNestedObjects);
@ -161,20 +161,20 @@ public:
private:
};
CPPUNIT_TEST_SUITE_REGISTRATION(JSONReflectorTests);
CPPUNIT_TEST_SUITE_REGISTRATION(JsonReflectorTests);
void JSONReflectorTests::setUp()
void JsonReflectorTests::setUp()
{
}
void JSONReflectorTests::tearDown()
void JsonReflectorTests::tearDown()
{
}
/*!
* \brief Tests serializing strings, numbers, arrays and boolean.
*/
void JSONReflectorTests::testSerializePrimitives()
void JsonReflectorTests::testSerializePrimitives()
{
Document doc(kArrayType);
Document::AllocatorType &alloc = doc.GetAllocator();
@ -205,7 +205,7 @@ void JSONReflectorTests::testSerializePrimitives()
/*!
* \brief Tests serializing objects.
*/
void JSONReflectorTests::testSerializeSimpleObjects()
void JsonReflectorTests::testSerializeSimpleObjects()
{
TestObject testObj;
testObj.number = 42;
@ -220,7 +220,7 @@ void JSONReflectorTests::testSerializeSimpleObjects()
/*!
* \brief Tests serializing nested object and arrays.
*/
void JSONReflectorTests::testSerializeNestedObjects()
void JsonReflectorTests::testSerializeNestedObjects()
{
NestingObject nestingObj;
nestingObj.name = "nesting";
@ -246,7 +246,7 @@ void JSONReflectorTests::testSerializeNestedObjects()
/*!
* \brief Tests deserializing strings, numbers (int, float, double) and boolean.
*/
void JSONReflectorTests::testDeserializePrimitives()
void JsonReflectorTests::testDeserializePrimitives()
{
Document doc(kArrayType);
@ -279,7 +279,7 @@ void JSONReflectorTests::testDeserializePrimitives()
/*!
* \brief Tests deserializing simple objects.
*/
void JSONReflectorTests::testDeserializeSimpleObjects()
void JsonReflectorTests::testDeserializeSimpleObjects()
{
const TestObject testObj(
TestObject::fromJson("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}"));
@ -294,7 +294,7 @@ void JSONReflectorTests::testDeserializeSimpleObjects()
/*!
* \brief Tests deserializing nested objects and arrays.
*/
void JSONReflectorTests::testDeserializeNestedObjects()
void JsonReflectorTests::testDeserializeNestedObjects()
{
const NestingObject nestingObj(NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,"
"\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}"));
@ -325,7 +325,7 @@ void JSONReflectorTests::testDeserializeNestedObjects()
/*!
* \brief Tests whether RAPIDJSON_NAMESPACE::ParseResult is thrown correctly when passing invalid JSON to fromJSON().
*/
void JSONReflectorTests::testHandlingParseError()
void JsonReflectorTests::testHandlingParseError()
{
try {
NestingObject::fromJson("{\"name\":nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
@ -340,7 +340,7 @@ void JSONReflectorTests::testHandlingParseError()
/*!
* \brief Tests whether JsonDeserializationError is thrown on type mismatch.
*/
void JSONReflectorTests::testHandlingTypeMismatch()
void JsonReflectorTests::testHandlingTypeMismatch()
{
JsonDeserializationErrors errors;
NestingArray::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"