Refactor RapidJSON wrapper

* Move all JSON related files into own directory
* Move helper for error handling in own header
* Remove some leftovers from debugging
* Rename classes, use Json instead of JSON
This commit is contained in:
Martchus 2017-10-28 16:23:39 +02:00
parent 5d441cf5ab
commit c94c896f6c
17 changed files with 350 additions and 402 deletions

View File

@ -27,7 +27,7 @@ else()
message(FATAL_ERROR "Specified directory for c++utilities sources \"${BUNDLED_CPP_UTILITIES_PATH}\" does not exist.")
endif()
# add header-only library containing JSONSerializable and helper for using RapidJSON
# add header-only library containing JsonSerializable and helper for using RapidJSON
add_subdirectory(lib)
# allow inclusion of CMake modules from that lib in other parts of the project
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/lib/cmake/modules" "${CMAKE_MODULE_PATH}")

View File

@ -13,21 +13,21 @@ generator.
## Usage
This example shows how the library can be used to make a `struct` serializable:
```
#include <reflective-rapidjson/jsonserializable.h>
#include <reflective-rapidjson/json/serializable.h>
// define structures, eg.
struct TestObject : public JSONSerializable<TestObject> {
struct TestObject : public JsonSerializable<TestObject> {
int number;
double number2;
vector<int> numbers;
string text;
bool boolean;
};
struct NestingObject : public JSONSerializable<NestingObject> {
struct NestingObject : public JsonSerializable<NestingObject> {
string name;
TestObject testObj;
};
struct NestingArray : public JSONSerializable<NestingArray> {
struct NestingArray : public JsonSerializable<NestingArray> {
string name;
vector<TestObject> testObjects;
};
@ -75,10 +75,10 @@ to the sources of your target. Of course this can be skipped if not required/wan
The same example as above. However, this time Boost.Hana is used - so it doesn't require invoking the generator.
```
#include "<reflective-rapidjson/jsonserializable-boosthana.h>
#include "<reflective-rapidjson/json/serializable-boosthana.h>
// define structures using BOOST_HANA_DEFINE_STRUCT, eg.
struct TestObject : public JSONSerializable<TestObject> {
struct TestObject : public JsonSerializable<TestObject> {
BOOST_HANA_DEFINE_STRUCT(TestObject,
(int, number),
(double, number2),
@ -87,13 +87,13 @@ struct TestObject : public JSONSerializable<TestObject> {
(bool, boolean)
);
};
struct NestingObject : public JSONSerializable<NestingObject> {
struct NestingObject : public JsonSerializable<NestingObject> {
BOOST_HANA_DEFINE_STRUCT(NestingObject,
(string, name),
(TestObject, testObj)
);
};
struct NestingArray : public JSONSerializable<NestingArray> {
struct NestingArray : public JsonSerializable<NestingArray> {
BOOST_HANA_DEFINE_STRUCT(NestingArray,
(string, name),
(vector<TestObject>, testObjects)
@ -108,7 +108,7 @@ cout << "JSON: " << obj.toJson().GetString();
const auto obj = NestingArray::fromJson(...);
```
So the usage remains the same.
So beside the `BOOST_HANA_DEFINE_STRUCT` macro, the usage remains the same.
## Install instructions

View File

@ -1 +0,0 @@
# skel

View File

@ -1,6 +1,6 @@
#include "./codegenerator.h"
#include "../lib/jsonserializable.h"
#include "../lib/json/serializable.h"
#include <c++utilities/application/global.h>
@ -58,8 +58,8 @@ void JSONSerializationCodeGenerator::addDeclaration(clang::Decl *decl)
if (!record->hasDefinition()) {
return;
}
// add classes derived from any instantiation of "ReflectiveRapidJSON::JSONSerializable"
if (inheritsFromInstantiationOf(record, JSONSerializable<void>::qualifiedName)) {
// add classes derived from any instantiation of "ReflectiveRapidJSON::JsonSerializable"
if (inheritsFromInstantiationOf(record, JsonSerializable<void>::qualifiedName)) {
m_relevantClasses.emplace_back(record->getQualifiedNameAsString(), record);
}
break;
@ -105,7 +105,8 @@ 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, JSONParseErrors "
<< " &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value, "
"JsonDeserializationErrors "
"*errors)\n{\n"
" // pull base classes\n";
for (const RelevantClass *baseClass : relevantBases) {

View File

@ -48,7 +48,7 @@ inline CodeFactory &CodeGenerator::factory() const
/*!
* \brief The JSONSerializationCodeGenerator class generates code for JSON (de)serialization
* of objects inheriting from an instantiation of JSONSerializable.
* of objects inheriting from an instantiation of JsonSerializable.
*/
class JSONSerializationCodeGenerator : public CodeGenerator {
public:

View File

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

View File

@ -9,7 +9,7 @@ template <> inline void push<::TestNamespace1::Person>(const ::TestNamespace1::P
push(reflectable.age, "age", value, allocator);
push(reflectable.alive, "alive", value, allocator);
}
template <> inline void pull<::TestNamespace1::Person>(::TestNamespace1::Person &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value, JSONParseErrors *errors)
template <> inline void pull<::TestNamespace1::Person>(::TestNamespace1::Person &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
{
// pull base classes
// set error context for current record

View File

@ -159,7 +159,7 @@ void OverallTests::testSingleInheritence()
CPPUNIT_ASSERT_EQUAL(expectedJSONForDerived, string(as<DerivedTestStruct>(test).toJson().GetString()));
// test deserialization
const DerivedTestStruct parsedTest(JSONSerializable<DerivedTestStruct>::fromJson(expectedJSONForDerived));
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);
@ -184,7 +184,7 @@ void OverallTests::testMultipleInheritence()
CPPUNIT_ASSERT_EQUAL(expectedJSONForDerived, string(as<MultipleDerivedTestStruct>(test).toJson().GetString()));
// test deserialization
const MultipleDerivedTestStruct parsedTest(JSONSerializable<MultipleDerivedTestStruct>::fromJson(expectedJSONForDerived));
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);

View File

@ -1,7 +1,7 @@
#ifndef REFLECTIVE_RAPIDJSON_TESTS_STRUCTS_H
#define REFLECTIVE_RAPIDJSON_TESTS_STRUCTS_H
#include "../../lib/jsonserializable.h"
#include "../../lib/json/serializable.h"
#include <deque>
#include <list>
@ -12,37 +12,37 @@ using namespace std;
using namespace ReflectiveRapidJSON;
/*!
* \brief The TestStruct struct inherits from JSONSerializable and should hence have functional fromJson()
* \brief The TestStruct struct inherits from JsonSerializable and should hence have functional fromJson()
* and toJson() methods. This is asserted in OverallTests::testIncludingGeneratedHeader();
*/
struct TestStruct : public JSONSerializable<TestStruct> {
struct TestStruct : public JsonSerializable<TestStruct> {
int someInt = 0;
string someString = "foo";
string yetAnotherString = "bar";
};
/*!
* \brief The NestedTestStruct struct inherits from JSONSerializable and should hence have functional fromJson()
* \brief The NestedTestStruct struct inherits from JsonSerializable and should hence have functional fromJson()
* and toJson() methods. This is asserted in OverallTests::testNesting();
*/
struct NestedTestStruct : public JSONSerializable<NestedTestStruct> {
struct NestedTestStruct : public JsonSerializable<NestedTestStruct> {
list<vector<TestStruct>> nested;
deque<double> deq;
};
/*!
* \brief The AnotherTestStruct struct inherits from JSONSerializable and should hence have functional fromJson()
* \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> {
struct AnotherTestStruct : public JsonSerializable<AnotherTestStruct> {
vector<string> arrayOfStrings{ "a", "b", "cd" };
};
/*!
* \brief The DerivedTestStruct struct inherits from JSONSerializable and should hence have functional fromJson()
* \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> {
struct DerivedTestStruct : public TestStruct, public JsonSerializable<DerivedTestStruct> {
bool someBool = true;
};
@ -54,13 +54,13 @@ struct NonSerializable {
};
/*!
* \brief The MultipleDerivedTestStruct struct inherits from JSONSerializable and should hence have functional fromJson()
* \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> {
public JsonSerializable<MultipleDerivedTestStruct> {
bool someBool = false;
};

View File

@ -5,9 +5,10 @@ set(META_PROJECT_TYPE library)
# add project files
set(HEADER_FILES
jsonreflector.h
jsonreflector-boosthana.h
jsonserializable.h
json/reflector.h
json/reflector-boosthana.h
json/serializable.h
json/errorhandling.h
)
set(SRC_FILES
)

190
lib/json/errorhandling.h Normal file
View File

@ -0,0 +1,190 @@
#ifndef REFLECTIVE_RAPIDJSON_JSON_ERROR_HANDLING_H
#define REFLECTIVE_RAPIDJSON_JSON_ERROR_HANDLING_H
/*!
* \file errorhandling.h
* \brief Contains helper for error handling when deserializing JSON files.
*/
#include <c++utilities/conversion/types.h>
#include <c++utilities/misc/traits.h>
#include <rapidjson/rapidjson.h>
#include <list>
#include <string>
#include <vector>
namespace ReflectiveRapidJSON {
/*!
* \brief The JsonDeserializationErrorKind enum specifies which kind of error happend when populating variables from parsing results.
*/
enum class JsonDeserializationErrorKind : byte {
TypeMismatch,
};
/*!
* \brief The JsonType enum specifies the JSON data type.
* \remarks This is currently only used for error handling to propagate expected and actual types in case of a mismatch.
*/
enum class JsonType : byte {
Null,
Number,
Bool,
String,
Array,
Object,
};
template <typename Type,
Traits::EnableIf<Traits::Not<std::is_same<Type, bool>>, Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>>>...>
constexpr JsonType jsonType()
{
return JsonType::Number;
}
template <typename Type, Traits::EnableIfAny<std::is_same<Type, bool>>...> constexpr JsonType jsonType()
{
return JsonType::Bool;
}
template <typename Type, Traits::EnableIfAny<Traits::IsString<Type>, Traits::IsCString<Type>>...> constexpr JsonType jsonType()
{
return JsonType::String;
}
template <typename Type, Traits::EnableIf<Traits::IsIteratable<Type>, Traits::Not<Traits::IsString<Type>>>...> constexpr JsonType jsonType()
{
return JsonType::Array;
}
template <typename Type,
Traits::DisableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, Traits::IsString<Type>, Traits::IsCString<Type>,
Traits::IsIteratable<Type>>...>
constexpr JsonType jsonType()
{
return JsonType::Object;
}
/*!
* \brief Maps the type info provided by RapidJSON to JsonType.
*/
constexpr JsonType jsonType(RAPIDJSON_NAMESPACE::Type type)
{
switch (type) {
case RAPIDJSON_NAMESPACE::kNullType:
return JsonType::Null;
case RAPIDJSON_NAMESPACE::kFalseType:
case RAPIDJSON_NAMESPACE::kTrueType:
return JsonType::Bool;
case RAPIDJSON_NAMESPACE::kObjectType:
return JsonType::Object;
case RAPIDJSON_NAMESPACE::kArrayType:
return JsonType::Array;
case RAPIDJSON_NAMESPACE::kStringType:
return JsonType::String;
case RAPIDJSON_NAMESPACE::kNumberType:
return JsonType::Number;
default:
return JsonType::Null;
}
}
/*!
* \brief The JsonDeserializationError struct describes any errors of fromJson() except such caused by invalid JSON.
*/
struct JsonDeserializationError {
JsonDeserializationError(JsonDeserializationErrorKind kind, JsonType expectedType, JsonType actualType, const char *record,
const char *member = nullptr, std::size_t index = noIndex);
/// \brief Which kind of error occured.
JsonDeserializationErrorKind kind;
/// \brief The expected type (might not be relevant for all error kinds).
JsonType expectedType;
/// \brief The actual type (might not be relevant for all error kinds).
JsonType actualType;
/// \brief The name of the class or struct which was being processed when the error was ascertained.
const char *record;
/// \brief The name of the member which was being processed when the error was ascertained.
const char *member;
/// \brief The index in the array which was being processed when the error was ascertained.
std::size_t index;
/// \brief Indicates no array was being processed when the error occured.
static constexpr std::size_t noIndex = std::numeric_limits<std::size_t>::max();
};
/*!
* \brief Constructs a new JsonDeserializationError.
* \remarks Supposed to be called by JsonDeserializationErrors::reportTypeMismatch() and similar methods of JsonDeserializationErrors.
*/
inline JsonDeserializationError::JsonDeserializationError(
JsonDeserializationErrorKind kind, JsonType expectedType, JsonType actualType, const char *record, const char *member, std::size_t index)
: kind(kind)
, expectedType(expectedType)
, actualType(actualType)
, record(record)
, member(member)
, index(index)
{
}
/*!
* \brief The JsonDeserializationErrors struct can be passed to fromJson() for error handling.
*
* When passed to fromJson() and an error occurs, a JsonDeserializationError is added to this object.
* If throwOn is set, the JsonDeserializationError is additionally thrown making the error fatal.
*
* \remarks Errors due to invalid JSON always lead to a RAPIDJSON_NAMESPACE::ParseResult object being thrown. So this
* only concerns errors listed in JsonDeserializationErrorKind.
*/
struct JsonDeserializationErrors : public std::vector<JsonDeserializationError> {
JsonDeserializationErrors();
template <typename ExpectedType> void reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType);
/// \brief The name of the class or struct which is currently being processed.
const char *currentRecord;
/// \brief The name of the member (in currentRecord) which is currently being processed.
const char *currentMember;
/// \brief The index in the array which is currently processed.
std::size_t currentIndex;
/// \brief The list of fatal error types in form of flags.
enum class ThrowOn : unsigned char { None = 0, TypeMismatch = 0x1 } throwOn;
};
/*!
* \brief Creates an empty JsonDeserializationErrors object with default context and no errors considered fatal.
*/
inline JsonDeserializationErrors::JsonDeserializationErrors()
: currentRecord("[document]")
, currentMember(nullptr)
, currentIndex(JsonDeserializationError::noIndex)
, throwOn(ThrowOn::None)
{
}
/*!
* \brief Combines to ThrowOn values.
*/
constexpr JsonDeserializationErrors::ThrowOn operator|(JsonDeserializationErrors::ThrowOn lhs, JsonDeserializationErrors::ThrowOn rhs)
{
return static_cast<JsonDeserializationErrors::ThrowOn>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs));
}
/*!
* \brief Reports a type missmatch between \tparam ExpectedType and \a presentType within the current context.
*/
template <typename ExpectedType> inline void JsonDeserializationErrors::reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType)
{
emplace_back(
JsonDeserializationErrorKind::TypeMismatch, jsonType<ExpectedType>(), jsonType(presentType), currentRecord, currentMember, currentIndex);
if (static_cast<unsigned char>(throwOn) & static_cast<unsigned char>(ThrowOn::TypeMismatch)) {
throw back();
}
}
} // namespace ReflectiveRapidJSON
#endif // REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H

View File

@ -2,7 +2,7 @@
#define REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_BOOST_HANA_H
/*!
* \file jsonreflector-boosthana.h
* \file reflector-boosthana.h
* \brief Contains generic functions relying on Boost.Hana which can replace the code which would
* otherwise had to be generated.
* \remarks
@ -12,7 +12,7 @@
* modifying the actual object.
*/
#include "./jsonreflector.h"
#include "./reflector.h"
// TODO: find out which header files are actually relevant rather than including the master
#include <boost/hana.hpp>
@ -37,7 +37,8 @@ void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Object &value, RA
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, JSONParseErrors *errors)
void pull(
Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors)
{
boost::hana::for_each(boost::hana::keys(reflectable), [&reflectable, &value, &errors](auto key) {
pull(boost::hana::at_key(reflectable, key), boost::hana::to<char const *>(key), value, errors);
@ -47,7 +48,8 @@ void pull(Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPA
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, JSONParseErrors *errors)
void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
JsonDeserializationErrors *errors)
{
boost::hana::for_each(boost::hana::keys(reflectable), [&reflectable, &value, &errors](auto key) {
pull(boost::hana::at_key(reflectable, key), boost::hana::to<char const *>(key), value, errors);

View File

@ -2,7 +2,7 @@
#define REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H
/*!
* \file jsonreflector.h
* \file reflector.h
* \brief Contains functions to (de)serialize basic types such as int, double, bool, std::string,
* std::vector, ... with RapidJSON.
*/
@ -11,185 +11,17 @@
#include <c++utilities/misc/traits.h>
#include <rapidjson/document.h>
#include <rapidjson/pointer.h>
#include <rapidjson/rapidjson.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <list>
#include <string>
#include <vector>
#include "./errorhandling.h"
namespace ReflectiveRapidJSON {
template <typename Type> struct JSONSerializable;
/*!
* \brief The JSONParseErrorKind enum specifies which kind of error happend when populating variables from parsing results.
*/
enum class JSONParseErrorKind : byte {
TypeMismatch,
};
/*!
* \brief The JSONType enum specifies the JSON data type.
* \remarks This is currently only used for error handling to propagate expected and actual types in case of a mismatch.
*/
enum class JSONType : byte {
Null,
Number,
Bool,
String,
Array,
Object,
};
template <typename Type,
Traits::EnableIf<Traits::Not<std::is_same<Type, bool>>, Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>>>...>
constexpr JSONType jsonType()
{
return JSONType::Number;
}
template <typename Type, Traits::EnableIfAny<std::is_same<Type, bool>>...> constexpr JSONType jsonType()
{
return JSONType::Bool;
}
template <typename Type, Traits::EnableIfAny<Traits::IsString<Type>, Traits::IsCString<Type>>...> constexpr JSONType jsonType()
{
return JSONType::String;
}
template <typename Type, Traits::EnableIf<Traits::IsIteratable<Type>, Traits::Not<Traits::IsString<Type>>>...> constexpr JSONType jsonType()
{
return JSONType::Array;
}
template <typename Type,
Traits::DisableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, Traits::IsString<Type>, Traits::IsCString<Type>,
Traits::IsIteratable<Type>>...>
constexpr JSONType jsonType()
{
return JSONType::Object;
}
/*!
* \brief Maps the type info provided by RapidJSON to JSONType.
*/
constexpr JSONType jsonType(RAPIDJSON_NAMESPACE::Type type)
{
switch (type) {
case RAPIDJSON_NAMESPACE::kNullType:
return JSONType::Null;
case RAPIDJSON_NAMESPACE::kFalseType:
case RAPIDJSON_NAMESPACE::kTrueType:
return JSONType::Bool;
case RAPIDJSON_NAMESPACE::kObjectType:
return JSONType::Object;
case RAPIDJSON_NAMESPACE::kArrayType:
return JSONType::Array;
case RAPIDJSON_NAMESPACE::kStringType:
return JSONType::String;
case RAPIDJSON_NAMESPACE::kNumberType:
return JSONType::Number;
default:
return JSONType::Null;
}
}
/*!
* \brief The JSONParseError struct describes any errors of fromJson() except such caused by invalid JSON.
*/
struct JSONParseError {
JSONParseError(JSONParseErrorKind kind, JSONType expectedType, JSONType actualType, const char *record, const char *member = nullptr,
std::size_t index = noIndex);
/// \brief Which kind of error occured.
JSONParseErrorKind kind;
/// \brief The expected type (might not be relevant for all error kinds).
JSONType expectedType;
/// \brief The actual type (might not be relevant for all error kinds).
JSONType actualType;
/// \brief The name of the class or struct which was being processed when the error was ascertained.
const char *record;
/// \brief The name of the member which was being processed when the error was ascertained.
const char *member;
/// \brief The index in the array which was being processed when the error was ascertained.
std::size_t index;
/// \brief Indicates no array was being processed when the error occured.
static constexpr std::size_t noIndex = std::numeric_limits<std::size_t>::max();
};
/*!
* \brief Constructs a new JSONParseError.
* \remarks Supposed to be called by JSONParseErrors::reportTypeMismatch() and similar methods of JSONParseErrors.
*/
inline JSONParseError::JSONParseError(
JSONParseErrorKind kind, JSONType expectedType, JSONType actualType, const char *record, const char *member, std::size_t index)
: kind(kind)
, expectedType(expectedType)
, actualType(actualType)
, record(record)
, member(member)
, index(index)
{
}
/*!
* \brief The JSONParseErrors struct can be passed to fromJson() for error handling.
*
* When passed to fromJson() and an error occurs, a JSONParseError is added to this object.
* If throwOn is set, the JSONParseError is additionally thrown making the error fatal.
*
* \remarks Errors due to invalid JSON always lead to a RAPIDJSON_NAMESPACE::ParseResult object being thrown. So this
* only concerns errors listed in JSONParseErrorKind.
*/
struct JSONParseErrors : public std::vector<JSONParseError> {
JSONParseErrors();
template <typename ExpectedType> void reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType);
/// \brief The name of the class or struct which is currently being processed.
const char *currentRecord;
/// \brief The name of the member (in currentRecord) which is currently being processed.
const char *currentMember;
/// \brief The index in the array which is currently processed.
std::size_t currentIndex;
/// \brief The list of fatal error types in form of flags.
enum class ThrowOn : unsigned char { None = 0, TypeMismatch = 0x1 } throwOn;
};
/*!
* \brief Creates an empty JSONParseErrors object with default context and no errors considered fatal.
*/
inline JSONParseErrors::JSONParseErrors()
: currentRecord("[document]")
, currentMember(nullptr)
, currentIndex(JSONParseError::noIndex)
, throwOn(ThrowOn::None)
{
}
/*!
* \brief Combines to ThrowOn values.
*/
constexpr JSONParseErrors::ThrowOn operator|(JSONParseErrors::ThrowOn lhs, JSONParseErrors::ThrowOn rhs)
{
return static_cast<JSONParseErrors::ThrowOn>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs));
}
/*!
* \brief Reports a type missmatch between \tparam ExpectedType and \a presentType within the current context.
*/
template <typename ExpectedType> inline void JSONParseErrors::reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType)
{
emplace_back(JSONParseErrorKind::TypeMismatch, jsonType<ExpectedType>(), jsonType(presentType), currentRecord, currentMember, currentIndex);
if (static_cast<unsigned char>(throwOn) & static_cast<unsigned char>(ThrowOn::TypeMismatch)) {
throw back();
}
}
template <typename Type> struct JsonSerializable;
inline RAPIDJSON_NAMESPACE::StringBuffer documentToString(RAPIDJSON_NAMESPACE::Document &document)
{
@ -346,17 +178,19 @@ void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAP
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, JSONParseErrors *errors);
void pull(
Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors);
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, JSONParseErrors *errors);
void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
JsonDeserializationErrors *errors);
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>> &value, JSONParseErrors *errors)
void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
{
if (!value.IsObject()) {
if (errors) {
@ -368,7 +202,8 @@ void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_N
}
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, JSONParseErrors *errors)
inline void pull(
Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors)
{
if (!value->Is<Type>()) {
if (errors) {
@ -381,7 +216,8 @@ inline void pull(Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_
}
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, JSONParseErrors *errors)
inline void pull(
Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
{
if (!value.Is<Type>()) {
if (errors) {
@ -393,8 +229,8 @@ inline void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPI
}
template <>
inline void pull<std::string>(
std::string &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JSONParseErrors *errors)
inline void pull<std::string>(std::string &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value,
JsonDeserializationErrors *errors)
{
if (!value->IsString()) {
if (errors) {
@ -408,7 +244,7 @@ inline void pull<std::string>(
template <>
inline void pull<std::string>(
std::string &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JSONParseErrors *errors)
std::string &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
{
if (!value.IsString()) {
if (errors) {
@ -420,12 +256,12 @@ inline void pull<std::string>(
}
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, JSONParseErrors *errors);
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
template <typename Type,
Traits::EnableIf<Traits::IsIteratable<Type>, Traits::Not<Traits::IsReservable<Type>>,
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JSONParseErrors *errors)
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors)
{
if (!value->IsArray()) {
if (errors) {
@ -439,7 +275,7 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
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, JSONParseErrors *errors)
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors)
{
if (!value->IsArray()) {
if (errors) {
@ -456,7 +292,7 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
template <typename Type,
Traits::EnableIf<Traits::IsIteratable<Type>, Traits::Not<Traits::IsReservable<Type>>,
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JSONParseErrors *errors)
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
{
if (!value.IsArray()) {
if (errors) {
@ -469,7 +305,7 @@ void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::
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, JSONParseErrors *errors)
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
{
if (!value.IsArray()) {
if (errors) {
@ -483,7 +319,7 @@ void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::
}
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, JSONParseErrors *errors)
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
{
// clear previous contents of the array
reflectable.clear();
@ -502,13 +338,13 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
// clear error context
if (errors) {
errors->currentIndex = JSONParseError::noIndex;
errors->currentIndex = JsonDeserializationError::noIndex;
}
}
template <typename Type>
inline void pull(
Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value, JSONParseErrors *errors)
inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
JsonDeserializationErrors *errors)
{
// find member
auto member = value.FindMember(name);
@ -534,7 +370,7 @@ inline void pull(
// define functions providing high-level JSON serialization
template <typename Type, Traits::EnableIfAny<std::is_base_of<JSONSerializable<Type>, 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);
@ -568,8 +404,8 @@ template <typename Type, Traits::EnableIfAny<std::is_same<Type, const char *>>..
// define functions providing high-level JSON deserialization
template <typename Type, Traits::EnableIfAny<std::is_base_of<JSONSerializable<Type>, Type>>...>
Type fromJson(const char *json, std::size_t jsonSize, JSONParseErrors *errors = nullptr)
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));
if (!doc.IsObject()) {
@ -585,7 +421,7 @@ Type fromJson(const char *json, std::size_t jsonSize, JSONParseErrors *errors =
}
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>...>
Type fromJson(const char *json, std::size_t jsonSize, JSONParseErrors *errors)
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors)
{
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
if (!doc.Is<Type>()) {
@ -599,7 +435,7 @@ Type fromJson(const char *json, std::size_t jsonSize, JSONParseErrors *errors)
}
template <typename Type, Traits::EnableIfAny<std::is_same<Type, std::string>>...>
Type fromJson(const char *json, std::size_t jsonSize, JSONParseErrors *errors)
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors)
{
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
if (!doc.IsString()) {

View File

@ -2,12 +2,12 @@
#define REFLECTIVE_RAPIDJSON_JSON_SERIALIZABLE_H
/*!
* \file jsonserializable.h
* \brief Contains only the definiation of the JSONSerializable template class which makes the reflection
* \file serializable.h
* \brief Contains only the definiation of the JsonSerializable template class which makes the reflection
* accessible. The actual implementation is found in jsonreflector.h and generated files.
*/
#include "./jsonreflector.h"
#include "./reflector.h"
#include <rapidjson/document.h>
@ -16,26 +16,26 @@
namespace ReflectiveRapidJSON {
/*!
* \brief The JSONSerializable class provides the CRTP-base for (de)serializable objects.
* \brief The JsonSerializable class provides the CRTP-base for (de)serializable objects.
*/
template <typename Type> struct JSONSerializable {
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, JSONParseErrors *errors = nullptr);
static Type fromJson(const char *json, JSONParseErrors *errors = nullptr);
static Type fromJson(const std::string &json, JSONParseErrors *errors = nullptr);
static Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr);
static Type fromJson(const char *json, JsonDeserializationErrors *errors = nullptr);
static Type fromJson(const std::string &json, JsonDeserializationErrors *errors = nullptr);
static constexpr const char *qualifiedName = "ReflectiveRapidJSON::JSONSerializable";
static constexpr const char *qualifiedName = "ReflectiveRapidJSON::JsonSerializable";
};
/*!
* \brief Pushes the object to the specified RapidJSON array.
*/
template <typename Type> void JSONSerializable<Type>::push(RAPIDJSON_NAMESPACE::Value &container)
template <typename Type> void JsonSerializable<Type>::push(RAPIDJSON_NAMESPACE::Value &container)
{
return Reflector::push<Type>(*this, container);
}
@ -43,7 +43,7 @@ template <typename Type> void JSONSerializable<Type>::push(RAPIDJSON_NAMESPACE::
/*!
* \brief Pushes the object to the specified RapidJSON object as a member with the specified \a name.
*/
template <typename Type> void JSONSerializable<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);
}
@ -52,7 +52,7 @@ template <typename Type> void JSONSerializable<Type>::push(RAPIDJSON_NAMESPACE::
* \brief Converts the object to its JSON representation.
* \remarks To obtain a string from the returned buffer, just use its GetString() method.
*/
template <typename Type> RAPIDJSON_NAMESPACE::StringBuffer JSONSerializable<Type>::toJson() const
template <typename Type> RAPIDJSON_NAMESPACE::StringBuffer JsonSerializable<Type>::toJson() const
{
return Reflector::toJson<Type>(static_cast<const Type &>(*this));
}
@ -60,7 +60,7 @@ template <typename Type> RAPIDJSON_NAMESPACE::StringBuffer JSONSerializable<Type
/*!
* \brief Constructs a new object from the specified JSON.
*/
template <typename Type> Type JSONSerializable<Type>::fromJson(const char *json, std::size_t jsonSize, JSONParseErrors *errors)
template <typename Type> Type JsonSerializable<Type>::fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors)
{
return Reflector::fromJson<Type>(json, jsonSize, errors);
}
@ -68,7 +68,7 @@ template <typename Type> Type JSONSerializable<Type>::fromJson(const char *json,
/*!
* \brief Constructs a new object from the specified JSON.
*/
template <typename Type> Type JSONSerializable<Type>::fromJson(const char *json, JSONParseErrors *errors)
template <typename Type> Type JsonSerializable<Type>::fromJson(const char *json, JsonDeserializationErrors *errors)
{
return Reflector::fromJson<Type>(json, std::strlen(json), errors);
}
@ -76,7 +76,7 @@ template <typename Type> Type JSONSerializable<Type>::fromJson(const char *json,
/*!
* \brief Constructs a new object from the specified JSON.
*/
template <typename Type> Type JSONSerializable<Type>::fromJson(const std::string &json, JSONParseErrors *errors)
template <typename Type> Type JsonSerializable<Type>::fromJson(const std::string &json, JsonDeserializationErrors *errors)
{
return Reflector::fromJson<Type>(json.data(), json.size(), errors);
}
@ -84,18 +84,18 @@ template <typename Type> Type JSONSerializable<Type>::fromJson(const std::string
/*!
* \brief Helps to disambiguate when inheritance is used.
*/
template <typename Type, Traits::EnableIf<std::is_base_of<JSONSerializable<Type>, Type>>...> JSONSerializable<Type> &as(Type &serializable)
template <typename Type, Traits::EnableIf<std::is_base_of<JsonSerializable<Type>, Type>>...> JsonSerializable<Type> &as(Type &serializable)
{
return static_cast<JSONSerializable<Type> &>(serializable);
return static_cast<JsonSerializable<Type> &>(serializable);
}
/*!
* \brief Helps to disambiguate when inheritance is used.
*/
template <typename Type, Traits::EnableIf<std::is_base_of<JSONSerializable<Type>, Type>>...>
const JSONSerializable<Type> &as(const Type &serializable)
template <typename Type, Traits::EnableIf<std::is_base_of<JsonSerializable<Type>, Type>>...>
const JsonSerializable<Type> &as(const Type &serializable)
{
return static_cast<const JSONSerializable<Type> &>(serializable);
return static_cast<const JsonSerializable<Type> &>(serializable);
}
} // namespace ReflectiveRapidJSON

View File

@ -1,56 +0,0 @@
#ifndef REFLECTIVE_RAPIDJSON_REFLECTABLE_H
#define REFLECTIVE_RAPIDJSON_REFLECTABLE_H
#include "./reflect.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);
};
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_REFLECTABLE_H

View File

@ -1,5 +1,5 @@
#include "../jsonreflector-boosthana.h"
#include "../jsonserializable.h"
#include "../json/reflector-boosthana.h"
#include "../json/serializable.h"
#include <c++utilities/conversion/stringbuilder.h>
#include <c++utilities/conversion/stringconversion.h>
@ -30,7 +30,7 @@ using namespace ReflectiveRapidJSON;
/// \cond
// define some structs for testing serialization
struct TestObjectHana : public JSONSerializable<TestObjectHana> {
struct TestObjectHana : public JsonSerializable<TestObjectHana> {
//TestObjectHana(){};
//TestObjectHana(const TestObjectHana &)
//{
@ -39,11 +39,11 @@ struct TestObjectHana : public JSONSerializable<TestObjectHana> {
BOOST_HANA_DEFINE_STRUCT(TestObjectHana, (int, number), (double, number2), (vector<int>, numbers), (string, text), (bool, boolean));
};
struct NestingObjectHana : public JSONSerializable<NestingObjectHana> {
struct NestingObjectHana : public JsonSerializable<NestingObjectHana> {
BOOST_HANA_DEFINE_STRUCT(NestingObjectHana, (string, name), (TestObjectHana, testObj));
};
struct NestingArrayHana : public JSONSerializable<NestingArrayHana> {
struct NestingArrayHana : public JsonSerializable<NestingArrayHana> {
BOOST_HANA_DEFINE_STRUCT(NestingArrayHana, (string, name), (vector<TestObjectHana>, testObjects));
};
@ -176,7 +176,7 @@ void JSONReflectorBoostHanaTests::testDeserializePrimitives()
bool bool1 = false, bool2 = true;
float float1 = 0.0;
double double1 = 0.0;
JSONParseErrors errors;
JsonDeserializationErrors errors;
Reflector::pull(str1, array, &errors);
Reflector::pull(int1, array, &errors);
Reflector::pull(float1, array, &errors);
@ -242,11 +242,11 @@ void JSONReflectorBoostHanaTests::testDeserializeNestedObjects()
}
/*!
* \brief Tests whether JSONParseError is thrown on type mismatch.
* \brief Tests whether JsonDeserializationError is thrown on type mismatch.
*/
void JSONReflectorBoostHanaTests::testHandlingTypeMismatch()
{
JSONParseErrors errors;
JsonDeserializationErrors errors;
NestingArrayHana::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"
"\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3."
"141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}",
@ -257,9 +257,9 @@ void JSONReflectorBoostHanaTests::testHandlingTypeMismatch()
"\"test\",\"boolean\":false}}",
&errors);
CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Number, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::String, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL("number"s, string(errors.front().member));
CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors.front().record));
errors.clear();
@ -268,23 +268,23 @@ void JSONReflectorBoostHanaTests::testHandlingTypeMismatch()
"\"test\",\"boolean\":false}}",
&errors);
CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Array, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::Number, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL("numbers"s, string(errors.front().member));
CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors.front().record));
errors.clear();
NestingObjectHana::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors);
CPPUNIT_ASSERT_EQUAL(2_st, errors.size());
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JSONType::String, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::Array, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL("name"s, string(errors.front().member));
CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors.front().record));
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors.back().kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Object, errors.back().expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::String, errors.back().actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.back().kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors.back().expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.back().actualType);
CPPUNIT_ASSERT_EQUAL("testObj"s, string(errors.back().member));
CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors.back().record));
errors.clear();
@ -295,26 +295,26 @@ void JSONReflectorBoostHanaTests::testHandlingTypeMismatch()
"141592653589793,\"numbers\":[1,2,3,4,\"bar\"],\"text\":\"test\",\"boolean\":false}]}",
&errors));
CPPUNIT_ASSERT_EQUAL(3_st, errors.size());
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors[0].kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Object, errors[0].expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::Number, errors[0].actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[0].kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[0].expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[0].actualType);
CPPUNIT_ASSERT_EQUAL("testObjects"s, string(errors[0].member));
CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors[0].record));
CPPUNIT_ASSERT_EQUAL(0_st, errors[0].index);
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors[1].kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Object, errors[1].expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::String, errors[1].actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[1].kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[1].expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[1].actualType);
CPPUNIT_ASSERT_EQUAL(2_st, errors[1].index);
CPPUNIT_ASSERT_EQUAL("testObjects"s, string(errors[1].member));
CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors[1].record));
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors[2].kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Number, errors[2].expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::String, errors[2].actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[2].kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[2].expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[2].actualType);
CPPUNIT_ASSERT_EQUAL("numbers"s, string(errors[2].member));
CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors[2].record));
CPPUNIT_ASSERT_EQUAL(4_st, errors[2].index);
errors.clear();
errors.throwOn = JSONParseErrors::ThrowOn::TypeMismatch;
CPPUNIT_ASSERT_THROW(NestingObjectHana::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors), JSONParseError);
errors.throwOn = JsonDeserializationErrors::ThrowOn::TypeMismatch;
CPPUNIT_ASSERT_THROW(NestingObjectHana::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors), JsonDeserializationError);
}

View File

@ -1,5 +1,5 @@
#include "../jsonreflector.h"
#include "../jsonserializable.h"
#include "../json/reflector.h"
#include "../json/serializable.h"
#include <c++utilities/conversion/stringbuilder.h>
#include <c++utilities/conversion/stringconversion.h>
@ -30,7 +30,7 @@ using namespace ReflectiveRapidJSON;
/// \cond
// define some structs for testing serialization
struct TestObject : public JSONSerializable<TestObject> {
struct TestObject : public JsonSerializable<TestObject> {
int number;
double number2;
vector<int> numbers;
@ -38,12 +38,12 @@ struct TestObject : public JSONSerializable<TestObject> {
bool boolean;
};
struct NestingObject : public JSONSerializable<NestingObject> {
struct NestingObject : public JsonSerializable<NestingObject> {
string name;
TestObject testObj;
};
struct NestingArray : public JSONSerializable<NestingArray> {
struct NestingArray : public JsonSerializable<NestingArray> {
string name;
vector<TestObject> testObjects;
};
@ -73,7 +73,8 @@ template <> inline void push<NestingArray>(const NestingArray &reflectable, Valu
push(reflectable.testObjects, "testObjects", value, allocator);
}
template <> inline void pull<TestObject>(TestObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JSONParseErrors *errors)
template <>
inline void pull<TestObject>(TestObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
{
const char *previousRecord;
if (errors) {
@ -90,7 +91,8 @@ template <> inline void pull<TestObject>(TestObject &reflectable, const GenericV
}
}
template <> inline void pull<NestingObject>(NestingObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JSONParseErrors *errors)
template <>
inline void pull<NestingObject>(NestingObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
{
const char *previousRecord;
if (errors) {
@ -104,7 +106,8 @@ template <> inline void pull<NestingObject>(NestingObject &reflectable, const Ge
}
}
template <> inline void pull<NestingArray>(NestingArray &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JSONParseErrors *errors)
template <>
inline void pull<NestingArray>(NestingArray &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
{
const char *previousRecord;
if (errors) {
@ -131,7 +134,6 @@ template <> inline void pull<NestingArray>(NestingArray &reflectable, const Gene
*/
class JSONReflectorTests : public TestFixture {
CPPUNIT_TEST_SUITE(JSONReflectorTests);
CPPUNIT_TEST(experiment);
CPPUNIT_TEST(testSerializePrimitives);
CPPUNIT_TEST(testSerializeSimpleObjects);
CPPUNIT_TEST(testSerializeNestedObjects);
@ -169,33 +171,6 @@ void JSONReflectorTests::tearDown()
{
}
/*!
* \brief Not a real test, just some assertions for experimenting with the RapidJSON library.
*/
void JSONReflectorTests::experiment()
{
Document doc(kArrayType);
Document::AllocatorType &alloc = doc.GetAllocator();
/*
doc.PushBack(25, alloc);
doc.PushBack(26, alloc);
doc.SetObject();
doc.AddMember(StringRef("test"), 27, alloc);
StringBuffer strbuf;
Writer<StringBuffer> jsonWriter(strbuf);
doc.Accept(jsonWriter);
*/
doc.Parse("[\"a\", 5, \"test\", \"7\"]");
GenericValue<UTF8<>>::Array a = doc.GetArray();
CPPUNIT_ASSERT_EQUAL("a"s, string(a[0].GetString()));
CPPUNIT_ASSERT_EQUAL(5, a[1].GetInt());
//CPPUNIT_ASSERT_EQUAL(5, a[2].GetInt());
//CPPUNIT_ASSERT_EQUAL(7, a[3].GetInt());
}
/*!
* \brief Tests serializing strings, numbers, arrays and boolean.
*/
@ -283,7 +258,7 @@ void JSONReflectorTests::testDeserializePrimitives()
bool bool1 = false, bool2 = true;
float float1 = 0.0;
double double1 = 0.0;
JSONParseErrors errors;
JsonDeserializationErrors errors;
Reflector::pull(str1, array, &errors);
Reflector::pull(int1, array, &errors);
Reflector::pull(float1, array, &errors);
@ -363,11 +338,11 @@ void JSONReflectorTests::testHandlingParseError()
}
/*!
* \brief Tests whether JSONParseError is thrown on type mismatch.
* \brief Tests whether JsonDeserializationError is thrown on type mismatch.
*/
void JSONReflectorTests::testHandlingTypeMismatch()
{
JSONParseErrors errors;
JsonDeserializationErrors errors;
NestingArray::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"
"\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3."
"141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}",
@ -378,9 +353,9 @@ void JSONReflectorTests::testHandlingTypeMismatch()
"\"test\",\"boolean\":false}}",
&errors);
CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Number, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::String, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL("number"s, string(errors.front().member));
CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors.front().record));
errors.clear();
@ -389,23 +364,23 @@ void JSONReflectorTests::testHandlingTypeMismatch()
"\"test\",\"boolean\":false}}",
&errors);
CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Array, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::Number, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL("numbers"s, string(errors.front().member));
CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors.front().record));
errors.clear();
NestingObject::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors);
CPPUNIT_ASSERT_EQUAL(2_st, errors.size());
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JSONType::String, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::Array, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().actualType);
CPPUNIT_ASSERT_EQUAL("name"s, string(errors.front().member));
CPPUNIT_ASSERT_EQUAL("NestingObject"s, string(errors.front().record));
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors.back().kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Object, errors.back().expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::String, errors.back().actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.back().kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors.back().expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.back().actualType);
CPPUNIT_ASSERT_EQUAL("testObj"s, string(errors.back().member));
CPPUNIT_ASSERT_EQUAL("NestingObject"s, string(errors.back().record));
errors.clear();
@ -416,26 +391,26 @@ void JSONReflectorTests::testHandlingTypeMismatch()
"141592653589793,\"numbers\":[1,2,3,4,\"bar\"],\"text\":\"test\",\"boolean\":false}]}",
&errors));
CPPUNIT_ASSERT_EQUAL(3_st, errors.size());
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors[0].kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Object, errors[0].expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::Number, errors[0].actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[0].kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[0].expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[0].actualType);
CPPUNIT_ASSERT_EQUAL("testObjects"s, string(errors[0].member));
CPPUNIT_ASSERT_EQUAL("NestingArray"s, string(errors[0].record));
CPPUNIT_ASSERT_EQUAL(0_st, errors[0].index);
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors[1].kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Object, errors[1].expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::String, errors[1].actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[1].kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[1].expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[1].actualType);
CPPUNIT_ASSERT_EQUAL(2_st, errors[1].index);
CPPUNIT_ASSERT_EQUAL("testObjects"s, string(errors[1].member));
CPPUNIT_ASSERT_EQUAL("NestingArray"s, string(errors[1].record));
CPPUNIT_ASSERT_EQUAL(JSONParseErrorKind::TypeMismatch, errors[2].kind);
CPPUNIT_ASSERT_EQUAL(JSONType::Number, errors[2].expectedType);
CPPUNIT_ASSERT_EQUAL(JSONType::String, errors[2].actualType);
CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[2].kind);
CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[2].expectedType);
CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[2].actualType);
CPPUNIT_ASSERT_EQUAL("numbers"s, string(errors[2].member));
CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors[2].record));
CPPUNIT_ASSERT_EQUAL(4_st, errors[2].index);
errors.clear();
errors.throwOn = JSONParseErrors::ThrowOn::TypeMismatch;
CPPUNIT_ASSERT_THROW(NestingObject::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors), JSONParseError);
errors.throwOn = JsonDeserializationErrors::ThrowOn::TypeMismatch;
CPPUNIT_ASSERT_THROW(NestingObject::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors), JsonDeserializationError);
}