Improve error handling

* Throw ParseResult when parsing error occurs
* Silence type mismatch or missing members for now
This commit is contained in:
Martchus 2017-10-27 20:20:22 +02:00
parent 97f1dc57cf
commit 1b1d07ef8c
2 changed files with 86 additions and 9 deletions

View File

@ -43,6 +43,16 @@ inline RAPIDJSON_NAMESPACE::StringBuffer documentToString(RAPIDJSON_NAMESPACE::D
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 {
// 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>>>>...>
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());
}
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)
{
if (!value->Is<Type>()) {
return; // TODO: handle type mismatch
}
reflectable = value->Get<Type>();
++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>>...>
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>();
}
template <>
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();
++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();
}
@ -228,6 +253,9 @@ template <typename Type,
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value)
{
if (!value->IsArray()) {
return; // TODO: handle type mismatch
}
pull(reflectable, value->GetArray());
++value;
}
@ -236,6 +264,9 @@ 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)
{
if (!value->IsArray()) {
return; // TODO: handle type mismatch
}
auto array = value->GetArray();
reflectable.reserve(array.Size());
pull(reflectable, array);
@ -247,6 +278,9 @@ template <typename Type,
Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>>...>
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value)
{
if (!value.IsArray()) {
return; // TODO: handle type mismatch
}
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>>>...>
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value)
{
if (!value.IsArray()) {
return; // TODO: handle type mismatch
}
auto array = value.GetArray();
reflectable.reserve(array.Size());
pull(reflectable, array);
@ -274,6 +311,10 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
template <typename Type>
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);
}
@ -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)
{
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
document.Parse(json, jsonSize);
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
if (!doc.IsObject()) {
return Type();
}
Type res;
pull<Type>(res, document.GetObject());
pull<Type>(res, doc.GetObject());
return res;
}
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>...>
Type fromJson(const char *json, std::size_t jsonSize)
{
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
document.Parse(json, jsonSize);
return document.Get<Type>();
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
if (!doc.Is<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)
{
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
document.Parse(json, jsonSize);
return document.GetString();
RAPIDJSON_NAMESPACE::Document doc(parseDocumentFromString(json, jsonSize));
if (!doc.IsString()) {
return Type();
}
return doc.GetString();
}
template <typename Type> Type fromJson(const std::string &json)

View File

@ -112,6 +112,8 @@ class JSONReflectorTests : public TestFixture {
CPPUNIT_TEST(testDeserializePrimitives);
CPPUNIT_TEST(testDeserializeSimpleObjects);
CPPUNIT_TEST(testDeserializeNestedObjects);
CPPUNIT_TEST(testHandlingParseError);
CPPUNIT_TEST(testHandlingTypeMismatch);
CPPUNIT_TEST_SUITE_END();
public:
@ -125,6 +127,8 @@ public:
void testDeserializePrimitives();
void testDeserializeSimpleObjects();
void testDeserializeNestedObjects();
void testHandlingParseError();
void testHandlingTypeMismatch();
private:
};
@ -315,3 +319,26 @@ void JSONReflectorTests::testDeserializeNestedObjects()
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\"}}");
}