diff --git a/lib/json/reflector.h b/lib/json/reflector.h index f82dc13..09d33e4 100644 --- a/lib/json/reflector.h +++ b/lib/json/reflector.h @@ -590,9 +590,10 @@ void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue>...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable) +template , IsMapOrHash>...> +RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable) { RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); RAPIDJSON_NAMESPACE::Document::Object object(document.GetObject()); @@ -614,7 +615,7 @@ RAPIDJSON_NAMESPACE::StringBuffer toJson(Type reflectable) /*! * \brief Serializes the specified \a reflectable which is an std::string. */ -template >...> +template >...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const std::string &reflectable) { RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType); @@ -625,19 +626,29 @@ RAPIDJSON_NAMESPACE::StringBuffer toJson(const std::string &reflectable) /*! * \brief Serializes the specified \a reflectable which is a C-string. */ -template >...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const char *reflectable) +template >...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const char *reflectable) { RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType); document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), document.GetAllocator()); return serializeJsonDocToString(document); } +/*! + * \brief Serializes the specified \a reflectable which can be mapped to an array. + */ +template >...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable) +{ + RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kArrayType); + push(reflectable, document, document.GetAllocator()); + return serializeJsonDocToString(document); +} + // define functions providing high-level JSON deserialization /*! - * \brief Deserializes the specified JSON to \tparam Type which is a custom type. + * \brief Deserializes the specified JSON to \tparam Type which is a custom type or can be mapped to an object. */ -template >...> +template , IsMapOrHash>...> Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr) { RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize)); @@ -657,7 +668,7 @@ Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors * \brief Deserializes the specified JSON to \tparam Type which is an integer, float or boolean. */ template , std::is_floating_point>...> -Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors) +Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr) { RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize)); if (!doc.Is()) { @@ -673,8 +684,8 @@ Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors /*! * \brief Deserializes the specified JSON to \tparam Type which is a std::string. */ -template >...> -Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors) +template >...> +Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr) { RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize)); if (!doc.IsString()) { @@ -687,10 +698,37 @@ Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors return doc.GetString(); } +/*! + * \brief Deserializes the specified JSON to \tparam Type which can be mapped to an array. + */ +template >...> +Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr) +{ + RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize)); + if (!doc.IsArray()) { + if (errors) { + errors->reportTypeMismatch(doc.GetType()); + } + return Type(); + } + + Type res; + pull(res, doc.GetArray(), errors); + return res; +} + +/*! + * \brief Deserializes the specified JSON from an null-terminated C-string to \tparam Type. + */ +template Type fromJson(const char *json, JsonDeserializationErrors *errors = nullptr) +{ + return fromJson(json, std::strlen(json), errors); +} + /*! * \brief Deserializes the specified JSON from an std::string to \tparam Type. */ -template Type fromJson(const std::string &json, JsonDeserializationErrors *errors) +template Type fromJson(const std::string &json, JsonDeserializationErrors *errors = nullptr) { return fromJson(json.data(), json.size(), errors); } diff --git a/lib/tests/jsonreflector.cpp b/lib/tests/jsonreflector.cpp index f994878..a6b0943 100644 --- a/lib/tests/jsonreflector.cpp +++ b/lib/tests/jsonreflector.cpp @@ -279,6 +279,7 @@ void JsonReflectorTests::testSerializeNestedObjects() CPPUNIT_ASSERT_EQUAL( "{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{}}}"s, string(nestingObj.toJson().GetString())); + NestingArray nestingArray; nestingArray.name = "nesting2"; nestingArray.testObjects.emplace_back(testObj); @@ -287,6 +288,12 @@ void JsonReflectorTests::testSerializeNestedObjects() CPPUNIT_ASSERT_EQUAL( "{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{}},{\"number\":43,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{}}]}"s, string(nestingArray.toJson().GetString())); + + vector nestedInVector; + nestedInVector.emplace_back(testObj); + CPPUNIT_ASSERT_EQUAL( + "[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{}}]"s, + string(JsonReflector::toJson(nestedInVector).GetString())); } void JsonReflectorTests::testSerializeUniquePtr() @@ -419,9 +426,12 @@ void JsonReflectorTests::testDeserializeSimpleObjects() */ void JsonReflectorTests::testDeserializeNestedObjects() { + JsonDeserializationErrors errors; const NestingObject nestingObj(NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793," - "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}")); + "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}", + &errors)); const TestObject &testObj = nestingObj.testObj; + CPPUNIT_ASSERT_EQUAL(0_st, errors.size()); CPPUNIT_ASSERT_EQUAL("nesting"s, nestingObj.name); CPPUNIT_ASSERT_EQUAL(42, testObj.number); CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2); @@ -431,8 +441,10 @@ void JsonReflectorTests::testDeserializeNestedObjects() const NestingArray nestingArray(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}]}")); + "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}", + &errors)); const vector &testObjects = nestingArray.testObjects; + CPPUNIT_ASSERT_EQUAL(0_st, errors.size()); CPPUNIT_ASSERT_EQUAL("nesting2"s, nestingArray.name); CPPUNIT_ASSERT_EQUAL(2_st, testObjects.size()); CPPUNIT_ASSERT_EQUAL(42, testObjects[0].number); @@ -443,6 +455,15 @@ void JsonReflectorTests::testDeserializeNestedObjects() CPPUNIT_ASSERT_EQUAL("test"s, testObj.text); CPPUNIT_ASSERT_EQUAL(false, testObj.boolean); } + + const auto nestedInVector(JsonReflector::fromJson>( + "[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{}}]", + &errors)); + CPPUNIT_ASSERT_EQUAL(0_st, errors.size()); + CPPUNIT_ASSERT_EQUAL(1_st, nestedInVector.size()); + CPPUNIT_ASSERT_EQUAL(42, nestedInVector[0].number); + CPPUNIT_ASSERT_EQUAL(4_st, nestedInVector[0].numbers.size()); + CPPUNIT_ASSERT_EQUAL("test"s, nestedInVector[0].text); } void JsonReflectorTests::testDeserializeUniquePtr()