diff --git a/CHANGELOG.md b/CHANGELOG.md index 54c53d79..25063c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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# ### diff --git a/cpp/inc/bond/core/detail/string_stream.h b/cpp/inc/bond/core/detail/string_stream.h index ddadaaf6..59103222 100644 --- a/cpp/inc/bond/core/detail/string_stream.h +++ b/cpp/inc/bond/core/detail/string_stream.h @@ -41,7 +41,8 @@ public: return *this; } - basic_string_stream& operator<<(const std::string& str) + template + basic_string_stream& operator<<(const std::basic_string& str) { write(str.begin(), str.end()); return *this; diff --git a/cpp/inc/bond/core/exception.h b/cpp/inc/bond/core/exception.h index 700f59b1..d32de91a 100644 --- a/cpp/inc/bond/core/exception.h +++ b/cpp/inc/bond/core/exception.h @@ -5,6 +5,8 @@ #include "detail/string_stream.h" #include +#include +#include #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 + BOND_NORETURN inline void ElementNotFoundExceptionHelper( + const Key& key, + typename boost::enable_if>::type* = nullptr) + { + try + { + BOND_THROW(CoreException, + "Map element not found: key: " << + boost::locale::conv::utf_to_utf( + 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: "); + } + } + + template + BOND_NORETURN inline void ElementNotFoundExceptionHelper( + const Key& key, + typename boost::disable_if>::type* = nullptr) + { + BOND_THROW(CoreException, + "Map element not found: key: " << key); + } +} + + template 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); } diff --git a/cpp/inc/bond/protocol/simple_json_reader_impl.h b/cpp/inc/bond/protocol/simple_json_reader_impl.h index 34596e02..a42afc5e 100644 --- a/cpp/inc/bond/protocol/simple_json_reader_impl.h +++ b/cpp/inc/bond/protocol/simple_json_reader_impl.h @@ -150,8 +150,19 @@ DeserializeMap(X& var, BondDataType keyType, const T& element, SimpleJsonReader< { detail::Read(*it, key); } + else + { + bond::InvalidKeyTypeException(); + } - SimpleJsonReader input(reader, *++it); + ++it; + + if (it == end) + { + bond::ElementNotFoundException(key); + } + + SimpleJsonReader input(reader, *it); if (value_type.ComplexTypeMatch(*it)) detail::MakeValue(input, element).template Deserialize(mapped_at(var, key));