Improve error handling
* Throw ParseResult when parsing error occurs * Silence type mismatch or missing members for now
This commit is contained in:
parent
97f1dc57cf
commit
1b1d07ef8c
|
@ -43,6 +43,16 @@ inline RAPIDJSON_NAMESPACE::StringBuffer documentToString(RAPIDJSON_NAMESPACE::D
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline RAPIDJSON_NAMESPACE::Document parseDocumentFromString(const char *json, std::size_t jsonSize)
|
||||||
|
{
|
||||||
|
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
|
||||||
|
const RAPIDJSON_NAMESPACE::ParseResult parseRes = document.Parse(json, jsonSize);
|
||||||
|
if (parseRes.IsError()) {
|
||||||
|
throw parseRes;
|
||||||
|
}
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Reflector {
|
namespace Reflector {
|
||||||
|
|
||||||
// define functions to "push" values to a RapidJSON array or object
|
// define functions to "push" values to a RapidJSON array or object
|
||||||
|
@ -192,12 +202,18 @@ template <typename Type,
|
||||||
Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>>...>
|
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)
|
void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value)
|
||||||
{
|
{
|
||||||
|
if (!value.IsObject()) {
|
||||||
|
return; // TODO: handle type mismatch
|
||||||
|
}
|
||||||
pull<Type>(reflectable, value.GetObject());
|
pull<Type>(reflectable, value.GetObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>>...>
|
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>>...>
|
||||||
inline void pull(Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value)
|
inline void pull(Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value)
|
||||||
{
|
{
|
||||||
|
if (!value->Is<Type>()) {
|
||||||
|
return; // TODO: handle type mismatch
|
||||||
|
}
|
||||||
reflectable = value->Get<Type>();
|
reflectable = value->Get<Type>();
|
||||||
++value;
|
++value;
|
||||||
}
|
}
|
||||||
|
@ -205,18 +221,27 @@ 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>>...>
|
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)
|
inline void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value)
|
||||||
{
|
{
|
||||||
|
if (!value.Is<Type>()) {
|
||||||
|
return; // TODO: handle type mismatch
|
||||||
|
}
|
||||||
reflectable = value.Get<Type>();
|
reflectable = value.Get<Type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline void pull<std::string>(std::string &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value)
|
inline void pull<std::string>(std::string &reflectable, RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value)
|
||||||
{
|
{
|
||||||
|
if (!value->IsString()) {
|
||||||
|
return; // TODO: handle type mismatch
|
||||||
|
}
|
||||||
reflectable = value->GetString();
|
reflectable = value->GetString();
|
||||||
++value;
|
++value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline void pull<std::string>(std::string &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value)
|
template <> inline void pull<std::string>(std::string &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value)
|
||||||
{
|
{
|
||||||
|
if (!value.IsString()) {
|
||||||
|
return; // TODO: handle type mismatch
|
||||||
|
}
|
||||||
reflectable = value.GetString();
|
reflectable = value.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,6 +253,9 @@ template <typename Type,
|
||||||
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
|
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
|
||||||
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value)
|
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value)
|
||||||
{
|
{
|
||||||
|
if (!value->IsArray()) {
|
||||||
|
return; // TODO: handle type mismatch
|
||||||
|
}
|
||||||
pull(reflectable, value->GetArray());
|
pull(reflectable, value->GetArray());
|
||||||
++value;
|
++value;
|
||||||
}
|
}
|
||||||
|
@ -236,6 +264,9 @@ template <typename Type,
|
||||||
Traits::EnableIf<Traits::IsIteratable<Type>, Traits::IsReservable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
|
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)
|
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value)
|
||||||
{
|
{
|
||||||
|
if (!value->IsArray()) {
|
||||||
|
return; // TODO: handle type mismatch
|
||||||
|
}
|
||||||
auto array = value->GetArray();
|
auto array = value->GetArray();
|
||||||
reflectable.reserve(array.Size());
|
reflectable.reserve(array.Size());
|
||||||
pull(reflectable, array);
|
pull(reflectable, array);
|
||||||
|
@ -247,6 +278,9 @@ template <typename Type,
|
||||||
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
|
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
|
||||||
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value)
|
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value)
|
||||||
{
|
{
|
||||||
|
if (!value.IsArray()) {
|
||||||
|
return; // TODO: handle type mismatch
|
||||||
|
}
|
||||||
pull(reflectable, value.GetArray());
|
pull(reflectable, value.GetArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +288,9 @@ template <typename Type,
|
||||||
Traits::EnableIf<Traits::IsIteratable<Type>, Traits::IsReservable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
|
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)
|
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value)
|
||||||
{
|
{
|
||||||
|
if (!value.IsArray()) {
|
||||||
|
return; // TODO: handle type mismatch
|
||||||
|
}
|
||||||
auto array = value.GetArray();
|
auto array = value.GetArray();
|
||||||
reflectable.reserve(array.Size());
|
reflectable.reserve(array.Size());
|
||||||
pull(reflectable, array);
|
pull(reflectable, array);
|
||||||
|
@ -274,6 +311,10 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value)
|
inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value)
|
||||||
{
|
{
|
||||||
|
auto member = value.FindMember(name);
|
||||||
|
if (member == value.MemberEnd()) {
|
||||||
|
return; // TODO: handle member missing
|
||||||
|
}
|
||||||
pull<Type>(reflectable, value.FindMember(name)->value);
|
pull<Type>(reflectable, value.FindMember(name)->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,26 +356,35 @@ template <typename Type, Traits::EnableIfAny<std::is_same<Type, const char *>>..
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIfAny<std::is_base_of<JSONSerializable<Type>, Type>>...> Type fromJson(const char *json, std::size_t jsonSize)
|
template <typename Type, Traits::EnableIfAny<std::is_base_of<JSONSerializable<Type>, Type>>...> Type fromJson(const char *json, std::size_t jsonSize)
|
||||||
{
|
{
|
||||||
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
|
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
|
||||||
document.Parse(json, jsonSize);
|
if (!doc.IsObject()) {
|
||||||
|
return Type();
|
||||||
|
}
|
||||||
|
|
||||||
Type res;
|
Type res;
|
||||||
pull<Type>(res, document.GetObject());
|
pull<Type>(res, doc.GetObject());
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>...>
|
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>...>
|
||||||
Type fromJson(const char *json, std::size_t jsonSize)
|
Type fromJson(const char *json, std::size_t jsonSize)
|
||||||
{
|
{
|
||||||
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
|
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
|
||||||
document.Parse(json, jsonSize);
|
if (!doc.Is<Type>()) {
|
||||||
return document.Get<Type>();
|
return Type();
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc.Get<Type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIfAny<std::is_same<Type, std::string>>...> Type fromJson(const char *json, std::size_t jsonSize)
|
template <typename Type, Traits::EnableIfAny<std::is_same<Type, std::string>>...> Type fromJson(const char *json, std::size_t jsonSize)
|
||||||
{
|
{
|
||||||
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
|
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
|
||||||
document.Parse(json, jsonSize);
|
if (!doc.IsString()) {
|
||||||
return document.GetString();
|
return Type();
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type> Type fromJson(const std::string &json)
|
template <typename Type> Type fromJson(const std::string &json)
|
||||||
|
|
|
@ -112,6 +112,8 @@ class JSONReflectorTests : public TestFixture {
|
||||||
CPPUNIT_TEST(testDeserializePrimitives);
|
CPPUNIT_TEST(testDeserializePrimitives);
|
||||||
CPPUNIT_TEST(testDeserializeSimpleObjects);
|
CPPUNIT_TEST(testDeserializeSimpleObjects);
|
||||||
CPPUNIT_TEST(testDeserializeNestedObjects);
|
CPPUNIT_TEST(testDeserializeNestedObjects);
|
||||||
|
CPPUNIT_TEST(testHandlingParseError);
|
||||||
|
CPPUNIT_TEST(testHandlingTypeMismatch);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -125,6 +127,8 @@ public:
|
||||||
void testDeserializePrimitives();
|
void testDeserializePrimitives();
|
||||||
void testDeserializeSimpleObjects();
|
void testDeserializeSimpleObjects();
|
||||||
void testDeserializeNestedObjects();
|
void testDeserializeNestedObjects();
|
||||||
|
void testHandlingParseError();
|
||||||
|
void testHandlingTypeMismatch();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
@ -315,3 +319,26 @@ void JSONReflectorTests::testDeserializeNestedObjects()
|
||||||
CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
|
CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JSONReflectorTests::testHandlingParseError()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
NestingObject::fromJson("{\"name\":nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
|
||||||
|
"\"test\",\"boolean\":false}}");
|
||||||
|
CPPUNIT_FAIL("expected ParseResult thrown");
|
||||||
|
} catch (const RAPIDJSON_NAMESPACE::ParseResult &res) {
|
||||||
|
CPPUNIT_ASSERT_EQUAL(RAPIDJSON_NAMESPACE::kParseErrorValueInvalid, res.Code());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(9_st, res.Offset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSONReflectorTests::testHandlingTypeMismatch()
|
||||||
|
{
|
||||||
|
NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":\"42\",\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
|
||||||
|
"\"test\",\"boolean\":false}}");
|
||||||
|
NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":1,\"text\":"
|
||||||
|
"\"test\",\"boolean\":false}}");
|
||||||
|
NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":\"this is not an object\"}");
|
||||||
|
NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":\"42\",\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
|
||||||
|
"\"test\",\"boolean\":\"false\"}}");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue