[c++] Fix SimpleJSON map deserializtion
Correctly handle issues when deserializing invalid map data in SimpleJSON protocol, specifically: * When keys aren't of primitive type * When there isn't a matching value for evey key Also: * Change bond::basic_string_stream operator << to support various forms of std::basic_string<char> * Fix ElementNotFoundException to work with wstrings
This commit is contained in:
Родитель
3d67501110
Коммит
d80983ac3f
|
@ -23,6 +23,10 @@ different versioning scheme, following the Haskell community's
|
|||
|
||||
* When Unicode conversion fails during JSON deserialization to wstring, a
|
||||
bond::CoreException is now thrown instead of a Boost exception.
|
||||
* When SimpleJSON deserializes a map key with no matching value, a
|
||||
bond::CoreException is now thrown.
|
||||
* When SimpleJSON deserializes a map key of non-primitive type, a
|
||||
bond::CoreException is now thrown.
|
||||
|
||||
### C# ###
|
||||
|
||||
|
|
|
@ -41,7 +41,8 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
basic_string_stream& operator<<(const std::string& str)
|
||||
template<typename T, typename A>
|
||||
basic_string_stream& operator<<(const std::basic_string<char, T, A>& str)
|
||||
{
|
||||
write(str.begin(), str.end());
|
||||
return *this;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "detail/string_stream.h"
|
||||
#include <bond/core/bond_types.h>
|
||||
#include <boost/locale/encoding_utf.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
#define BOND_THROW(x, y) throw x((::bond::detail::basic_string_stream<1024>() << y).content());
|
||||
|
||||
|
@ -55,26 +57,65 @@ BOND_NORETURN inline void MergerContainerException(uint32_t payload, uint32_t ob
|
|||
}
|
||||
|
||||
|
||||
BOND_NORETURN inline void InvalidKeyTypeException()
|
||||
{
|
||||
BOND_THROW(CoreException,
|
||||
"Map key type not valid");
|
||||
}
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Key>
|
||||
BOND_NORETURN inline void ElementNotFoundExceptionHelper(
|
||||
const Key& key,
|
||||
typename boost::enable_if<is_wstring<Key>>::type* = nullptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
BOND_THROW(CoreException,
|
||||
"Map element not found: key: " <<
|
||||
boost::locale::conv::utf_to_utf<char>(
|
||||
string_data(key),
|
||||
string_data(key) + string_length(key),
|
||||
boost::locale::conv::stop));
|
||||
}
|
||||
catch (boost::locale::conv::conversion_error &)
|
||||
{
|
||||
BOND_THROW(CoreException, "Map element not found: key: <bad wstring>");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
BOND_NORETURN inline void ElementNotFoundExceptionHelper(
|
||||
const Key& key,
|
||||
typename boost::disable_if<is_wstring<Key>>::type* = nullptr)
|
||||
{
|
||||
BOND_THROW(CoreException,
|
||||
"Map element not found: key: " << key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Key>
|
||||
BOND_NORETURN inline void ElementNotFoundException(const Key& key)
|
||||
{
|
||||
BOND_THROW(CoreException,
|
||||
"Map element not found: key: " << key);
|
||||
detail::ElementNotFoundExceptionHelper(key);
|
||||
}
|
||||
|
||||
|
||||
BOND_NORETURN inline void UnknownProtocolException()
|
||||
{
|
||||
BOND_THROW(CoreException,
|
||||
"Unmarshaling failed: unsupported protocol");
|
||||
"Unmarshaling failed: unsupported protocol");
|
||||
}
|
||||
|
||||
|
||||
BOND_NORETURN inline void UnknownProtocolException(uint16_t magic)
|
||||
{
|
||||
BOND_THROW(CoreException,
|
||||
"Unsupported protocol: "
|
||||
<< (char)(magic & 0xFF) << (char)(magic >> 8));
|
||||
"Unsupported protocol: "
|
||||
<< (char)(magic & 0xFF) << (char)(magic >> 8));
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,14 +128,14 @@ BOND_NORETURN inline void NothingException()
|
|||
|
||||
BOND_NORETURN inline void InvalidEnumValueException(const char* value, const char* enum_)
|
||||
{
|
||||
BOND_THROW(bond::CoreException,
|
||||
BOND_THROW(bond::CoreException,
|
||||
"Unexpected value " << value << " for enum " << enum_);
|
||||
}
|
||||
|
||||
|
||||
BOND_NORETURN inline void InvalidEnumValueException(int32_t value, const char* enum_)
|
||||
{
|
||||
BOND_THROW(bond::CoreException,
|
||||
BOND_THROW(bond::CoreException,
|
||||
"Unexpected value " << value << " for enum " << enum_);
|
||||
}
|
||||
|
||||
|
@ -106,7 +147,7 @@ BOND_NORETURN inline void RapidJsonException(const char* error, size_t offset)
|
|||
}
|
||||
|
||||
|
||||
BOND_NORETURN inline void UnicodeConversionException(void)
|
||||
BOND_NORETURN inline void UnicodeConversionException()
|
||||
{
|
||||
BOND_THROW(CoreException,
|
||||
"Unicode conversion exception");
|
||||
|
@ -135,8 +176,8 @@ BOND_NORETURN
|
|||
inline void StructBaseDifferentException(const StructDef& src,
|
||||
const StructDef& dst)
|
||||
{
|
||||
BOND_THROW(SchemaValidateException,
|
||||
"Schemas are incompatible; struct base different: "
|
||||
BOND_THROW(SchemaValidateException,
|
||||
"Schemas are incompatible; struct base different: "
|
||||
<< src.metadata.name << ", " << dst.metadata.name);
|
||||
}
|
||||
|
||||
|
@ -145,8 +186,8 @@ BOND_NORETURN
|
|||
inline void RequiredFieldMissingException(const StructDef& s_dst,
|
||||
const FieldDef& f_dst)
|
||||
{
|
||||
BOND_THROW(SchemaValidateException,
|
||||
"Schemas are incompatible; required field missing: "
|
||||
BOND_THROW(SchemaValidateException,
|
||||
"Schemas are incompatible; required field missing: "
|
||||
<< s_dst.metadata.name << "::" << f_dst.metadata.name);
|
||||
}
|
||||
|
||||
|
@ -157,9 +198,9 @@ inline void OptionalToRequiredException(const StructDef& s_src,
|
|||
const FieldDef& f_src,
|
||||
const FieldDef& f_dst)
|
||||
{
|
||||
BOND_THROW(SchemaValidateException,
|
||||
"Schemas are incompatible; required modifier removed: "
|
||||
<< s_src.metadata.name << "::" << f_src.metadata.name << ", "
|
||||
BOND_THROW(SchemaValidateException,
|
||||
"Schemas are incompatible; required modifier removed: "
|
||||
<< s_src.metadata.name << "::" << f_src.metadata.name << ", "
|
||||
<< s_dst.metadata.name << "::" << f_dst.metadata.name);
|
||||
}
|
||||
|
||||
|
@ -170,16 +211,16 @@ inline void FieldTypeIncompatibleException(const StructDef& s_src,
|
|||
const FieldDef& f_src,
|
||||
const FieldDef& f_dst)
|
||||
{
|
||||
BOND_THROW(SchemaValidateException,
|
||||
"Schemas are incompatible; field types incompatible: "
|
||||
<< s_src.metadata.name << "::" << f_src.metadata.name << ", "
|
||||
BOND_THROW(SchemaValidateException,
|
||||
"Schemas are incompatible; field types incompatible: "
|
||||
<< s_src.metadata.name << "::" << f_src.metadata.name << ", "
|
||||
<< s_dst.metadata.name << "::" << f_dst.metadata.name);
|
||||
}
|
||||
|
||||
|
||||
BOND_NORETURN inline void UnknownSchemaDefException(uint16_t id)
|
||||
{
|
||||
BOND_THROW(SchemaValidateException,
|
||||
BOND_THROW(SchemaValidateException,
|
||||
"Failed to validate schema compatibility; "
|
||||
"SchemaDef contains unknown field: " << id);
|
||||
}
|
||||
|
|
|
@ -150,8 +150,19 @@ DeserializeMap(X& var, BondDataType keyType, const T& element, SimpleJsonReader<
|
|||
{
|
||||
detail::Read(*it, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
bond::InvalidKeyTypeException();
|
||||
}
|
||||
|
||||
SimpleJsonReader<Buffer> input(reader, *++it);
|
||||
++it;
|
||||
|
||||
if (it == end)
|
||||
{
|
||||
bond::ElementNotFoundException(key);
|
||||
}
|
||||
|
||||
SimpleJsonReader<Buffer> input(reader, *it);
|
||||
|
||||
if (value_type.ComplexTypeMatch(*it))
|
||||
detail::MakeValue(input, element).template Deserialize<Protocols>(mapped_at(var, key));
|
||||
|
|
Загрузка…
Ссылка в новой задаче