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:
parent
5d441cf5ab
commit
c94c896f6c
|
@ -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}")
|
||||
|
|
18
README.md
18
README.md
|
@ -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
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
# skel
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
|
@ -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);
|
|
@ -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()) {
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue