From a98355e000095542aec130f7c8c6b2f5bbb5e1cc Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Fri, 11 Jun 2021 13:41:54 -0700 Subject: [PATCH] Fix PODs not initializing in Json Serialization When pointers are used new instances are created for pod types, which will have random values at that point. The Json Serialization did not set a value for these if they were explicitly set to defaults. This change adds initialization for explicit defaults in the bool, integer and double serializer plus unit tests to verify. --- .../Serialization/Json/BoolSerializer.cpp | 21 +++++-- .../Serialization/Json/BoolSerializer.h | 1 + .../Serialization/Json/DoubleSerializer.cpp | 31 ++++++++-- .../Serialization/Json/DoubleSerializer.h | 2 + .../Serialization/Json/IntSerializer.cpp | 46 ++++++++++----- .../AzCore/Serialization/Json/IntSerializer.h | 58 +++++++++---------- .../Json/BoolSerializerTests.cpp | 38 ++++++++++++ .../Json/DoubleSerializerTests.cpp | 49 ++++++++++++++++ .../Serialization/Json/IntSerializerTests.cpp | 38 ++++++++++++ 9 files changed, 229 insertions(+), 55 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.cpp index d37e512ac2..7ac16b214d 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.cpp @@ -30,8 +30,8 @@ namespace AZ if (text && textLength > 0) { - static constexpr const char trueString[] = "true"; - static constexpr const char falseString[] = "false"; + static constexpr const char* trueString = "true"; + static constexpr const char* falseString = "false"; // remove null terminator for string length counts // rapidjson stringlength doesn't include it in length calculations, but sizeof() will static constexpr size_t trueStringLength = sizeof(trueString) - 1; @@ -82,12 +82,18 @@ namespace AZ bool* valAsBool = reinterpret_cast(outputValue); + if (IsExplicitDefault(inputValue)) + { + *valAsBool = false; + return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Boolean value set to default of 'false'."); + } + switch (inputValue.GetType()) { case rapidjson::kArrayType: - // fallthrough + [[fallthrough]]; case rapidjson::kObjectType: - // fallthrough + [[fallthrough]]; case rapidjson::kNullType: return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Unsupported type. Booleans can't be read from arrays, objects or null."); @@ -96,7 +102,7 @@ namespace AZ return SerializerInternal::TextToValue(valAsBool, inputValue.GetString(), inputValue.GetStringLength(), context); case rapidjson::kFalseType: - // fallthrough + [[fallthrough]]; case rapidjson::kTrueType: *valAsBool = inputValue.GetBool(); return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Successfully read boolean."); @@ -145,4 +151,9 @@ namespace AZ return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "Default boolean used."); } + + auto JsonBoolSerializer::GetOperationsFlags() const -> OperationFlags + { + return OperationFlags::ManualDefault; + } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.h index ac288c73ed..f000a03317 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.h @@ -27,5 +27,6 @@ namespace AZ JsonDeserializerContext& context) override; JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) override; + OperationFlags GetOperationsFlags() const override; }; } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.cpp index 9140be7fcd..647ff67eb6 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.cpp @@ -62,19 +62,26 @@ namespace AZ } template - static JsonSerializationResult::Result Load(T* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context) + static JsonSerializationResult::Result Load( + T* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context, bool isExplicitDefault) { namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds. static_assert(AZStd::is_floating_point::value, "Expected T to be a floating point type"); AZ_Assert(outputValue, "Expected a valid pointer to load from json value."); + if (isExplicitDefault) + { + *outputValue = 0.0f; + return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Double value set to default of 0.0."); + } + switch (inputValue.GetType()) { case rapidjson::kArrayType: - // fallthrough + [[fallthrough]]; case rapidjson::kObjectType: - // fallthrough + [[fallthrough]]; case rapidjson::kNullType: return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Unsupported type. Floating point values can't be read from arrays, objects or null."); @@ -83,7 +90,7 @@ namespace AZ return TextToValue(outputValue, inputValue.GetString(), context); case rapidjson::kFalseType: - // fallthrough + [[fallthrough]]; case rapidjson::kTrueType: *outputValue = inputValue.GetBool() ? 1.0f : 0.0f; return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, @@ -144,7 +151,8 @@ namespace AZ "Unable to deserialize double to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerFloatingPointInternal::Load(reinterpret_cast(outputValue), inputValue, context); + return SerializerFloatingPointInternal::Load( + reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonDoubleSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, @@ -156,6 +164,11 @@ namespace AZ return SerializerFloatingPointInternal::Store(outputValue, inputValue, defaultValue, context); } + auto JsonDoubleSerializer::GetOperationsFlags() const -> OperationFlags + { + return OperationFlags::ManualDefault; + } + JsonSerializationResult::Result JsonFloatSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) { @@ -163,7 +176,8 @@ namespace AZ "Unable to deserialize float to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerFloatingPointInternal::Load(reinterpret_cast(outputValue), inputValue, context); + return SerializerFloatingPointInternal::Load( + reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonFloatSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, @@ -174,4 +188,9 @@ namespace AZ AZ_UNUSED(valueTypeId); return SerializerFloatingPointInternal::Store(outputValue, inputValue, defaultValue, context); } + + auto JsonFloatSerializer::GetOperationsFlags() const -> OperationFlags + { + return OperationFlags::ManualDefault; + } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.h index 81e631d9ab..a8c37316f0 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.h @@ -28,6 +28,7 @@ namespace AZ JsonDeserializerContext& context) override; JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) override; + OperationFlags GetOperationsFlags() const override; }; class JsonFloatSerializer @@ -40,5 +41,6 @@ namespace AZ JsonDeserializerContext& context) override; JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) override; + OperationFlags GetOperationsFlags() const override; }; } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.cpp index cc365da4f7..28da852da3 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.cpp @@ -25,6 +25,8 @@ namespace AZ { + AZ_CLASS_ALLOCATOR_IMPL(BaseJsonIntegerSerializer, SystemAllocator, 0); + AZ_CLASS_ALLOCATOR_IMPL(JsonCharSerializer, SystemAllocator, 0); AZ_CLASS_ALLOCATOR_IMPL(JsonShortSerializer, SystemAllocator, 0); AZ_CLASS_ALLOCATOR_IMPL(JsonIntSerializer, SystemAllocator, 0); @@ -56,19 +58,25 @@ namespace AZ template static JsonSerializationResult::Result LoadInt(T* outputValue, const rapidjson::Value& inputValue, - JsonDeserializerContext& context) + JsonDeserializerContext& context, bool isDefaultValue) { namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds. static_assert(AZStd::is_integral(), "Expected T to be a signed or unsigned type"); AZ_Assert(outputValue, "Expected a valid pointer to load from json value."); + if (isDefaultValue) + { + *outputValue = 0; + return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Integer value set to default of zero."); + } + switch (inputValue.GetType()) { case rapidjson::kArrayType: - // fallthrough + [[fallthrough]]; case rapidjson::kObjectType: - // fallthrough + [[fallthrough]]; case rapidjson::kNullType: return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Unsupported type. Integers can't be read from arrays, objects or null."); @@ -77,7 +85,7 @@ namespace AZ return TextToValue(outputValue, inputValue.GetString(), context); case rapidjson::kFalseType: - // fallthrough + [[fallthrough]]; case rapidjson::kTrueType: *outputValue = inputValue.GetBool() ? 1 : 0; return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, @@ -125,6 +133,11 @@ namespace AZ } } // namespace SerializerInternal + auto BaseJsonIntegerSerializer::GetOperationsFlags() const -> OperationFlags + { + return OperationFlags::ManualDefault; + } + JsonSerializationResult::Result JsonCharSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) { @@ -132,7 +145,7 @@ namespace AZ "Unable to deserialize char to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context); + return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonCharSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, @@ -151,7 +164,7 @@ namespace AZ "Unable to deserialize short to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context); + return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonShortSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, @@ -170,7 +183,7 @@ namespace AZ "Unable to deserialize int to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context); + return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonIntSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, @@ -189,7 +202,7 @@ namespace AZ "Unable to deserialize long to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context); + return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonLongSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, @@ -208,7 +221,7 @@ namespace AZ "Unable to deserialize long long to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context); + return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonLongLongSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, @@ -227,7 +240,8 @@ namespace AZ "Unable to deserialize unsigned char to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context); + return SerializerInternal::LoadInt( + reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonUnsignedCharSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, @@ -246,7 +260,8 @@ namespace AZ "Unable to deserialize unsigned short to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context); + return SerializerInternal::LoadInt( + reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonUnsignedShortSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, @@ -265,7 +280,8 @@ namespace AZ "Unable to deserialize unsigned int to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context); + return SerializerInternal::LoadInt( + reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonUnsignedIntSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, @@ -284,7 +300,8 @@ namespace AZ "Unable to deserialize unsigned long to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context); + return SerializerInternal::LoadInt( + reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonUnsignedLongSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, @@ -303,7 +320,8 @@ namespace AZ "Unable to deserialize unsigned long long to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); - return SerializerInternal::LoadInt(reinterpret_cast(outputValue), inputValue, context); + return SerializerInternal::LoadInt( + reinterpret_cast(outputValue), inputValue, context, IsExplicitDefault(inputValue)); } JsonSerializationResult::Result JsonUnsignedLongLongSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.h index 9f522619ae..31d5a4164a 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.h @@ -18,11 +18,18 @@ namespace AZ { - class JsonCharSerializer - : public BaseJsonSerializer + class BaseJsonIntegerSerializer : public BaseJsonSerializer { public: - AZ_RTTI(JsonCharSerializer, "{CA2A4AAC-3068-40B2-94F8-A537FBA8236E}", BaseJsonSerializer); + AZ_RTTI(BaseJsonIntegerSerializer, "{FD060F54-D3B5-4D5B-B64A-AFE371CD6F20}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + OperationFlags GetOperationsFlags() const override; + }; + + class JsonCharSerializer : public BaseJsonIntegerSerializer + { + public: + AZ_RTTI(JsonCharSerializer, "{CA2A4AAC-3068-40B2-94F8-A537FBA8236E}", BaseJsonIntegerSerializer); AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; @@ -30,11 +37,10 @@ namespace AZ const Uuid& valueTypeId, JsonSerializerContext& context) override; }; - class JsonShortSerializer - : public BaseJsonSerializer + class JsonShortSerializer : public BaseJsonIntegerSerializer { public: - AZ_RTTI(JsonShortSerializer, "{3D6789BD-231B-4E5D-B81D-609E71A2BCB5}", BaseJsonSerializer); + AZ_RTTI(JsonShortSerializer, "{3D6789BD-231B-4E5D-B81D-609E71A2BCB5}", BaseJsonIntegerSerializer); AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; @@ -42,11 +48,10 @@ namespace AZ const Uuid& valueTypeId, JsonSerializerContext& context) override; }; - class JsonIntSerializer - : public BaseJsonSerializer + class JsonIntSerializer : public BaseJsonIntegerSerializer { public: - AZ_RTTI(JsonIntSerializer, "{29E26946-0F1F-44B0-A098-1171B7B0C8FA}", BaseJsonSerializer); + AZ_RTTI(JsonIntSerializer, "{29E26946-0F1F-44B0-A098-1171B7B0C8FA}", BaseJsonIntegerSerializer); AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; @@ -54,11 +59,10 @@ namespace AZ const Uuid& valueTypeId, JsonSerializerContext& context) override; }; - class JsonLongSerializer - : public BaseJsonSerializer + class JsonLongSerializer : public BaseJsonIntegerSerializer { public: - AZ_RTTI(JsonLongSerializer, "{0EB432D0-A0C8-43B2-9D65-A73A4D6DFE3E}", BaseJsonSerializer); + AZ_RTTI(JsonLongSerializer, "{0EB432D0-A0C8-43B2-9D65-A73A4D6DFE3E}", BaseJsonIntegerSerializer); AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; @@ -66,11 +70,10 @@ namespace AZ const Uuid& valueTypeId, JsonSerializerContext& context) override; }; - class JsonLongLongSerializer - : public BaseJsonSerializer + class JsonLongLongSerializer : public BaseJsonIntegerSerializer { public: - AZ_RTTI(JsonLongLongSerializer, "{5E7967DE-A4DC-40E1-81A1-2896A054BB8A}", BaseJsonSerializer); + AZ_RTTI(JsonLongLongSerializer, "{5E7967DE-A4DC-40E1-81A1-2896A054BB8A}", BaseJsonIntegerSerializer); AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; @@ -78,11 +81,10 @@ namespace AZ const Uuid& valueTypeId, JsonSerializerContext& context) override; }; - class JsonUnsignedCharSerializer - : public BaseJsonSerializer + class JsonUnsignedCharSerializer : public BaseJsonIntegerSerializer { public: - AZ_RTTI(JsonUnsignedCharSerializer, "{1E6D606F-8490-4736-AAFF-91046FDEA2BB}", BaseJsonSerializer); + AZ_RTTI(JsonUnsignedCharSerializer, "{1E6D606F-8490-4736-AAFF-91046FDEA2BB}", BaseJsonIntegerSerializer); AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; @@ -90,11 +92,10 @@ namespace AZ const Uuid& valueTypeId, JsonSerializerContext& context) override; }; - class JsonUnsignedShortSerializer - : public BaseJsonSerializer + class JsonUnsignedShortSerializer : public BaseJsonIntegerSerializer { public: - AZ_RTTI(JsonUnsignedShortSerializer, "{3C92D2CC-CB13-4A40-B779-47562EE36451}", BaseJsonSerializer); + AZ_RTTI(JsonUnsignedShortSerializer, "{3C92D2CC-CB13-4A40-B779-47562EE36451}", BaseJsonIntegerSerializer); AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; @@ -102,11 +103,10 @@ namespace AZ const Uuid& valueTypeId, JsonSerializerContext& context) override; }; - class JsonUnsignedIntSerializer - : public BaseJsonSerializer + class JsonUnsignedIntSerializer : public BaseJsonIntegerSerializer { public: - AZ_RTTI(JsonUnsignedIntSerializer, "{70C0714A-690D-4F30-8986-ABC9DEFE9D62}", BaseJsonSerializer); + AZ_RTTI(JsonUnsignedIntSerializer, "{70C0714A-690D-4F30-8986-ABC9DEFE9D62}", BaseJsonIntegerSerializer); AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; @@ -114,11 +114,10 @@ namespace AZ const Uuid& valueTypeId, JsonSerializerContext& context) override; }; - class JsonUnsignedLongSerializer - : public BaseJsonSerializer + class JsonUnsignedLongSerializer : public BaseJsonIntegerSerializer { public: - AZ_RTTI(JsonUnsignedLongSerializer, "{28E5499F-6AF4-4778-AE14-66BA40B56247}", BaseJsonSerializer); + AZ_RTTI(JsonUnsignedLongSerializer, "{28E5499F-6AF4-4778-AE14-66BA40B56247}", BaseJsonIntegerSerializer); AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; @@ -126,11 +125,10 @@ namespace AZ const Uuid& valueTypeId, JsonSerializerContext& context) override; }; - class JsonUnsignedLongLongSerializer - : public BaseJsonSerializer + class JsonUnsignedLongLongSerializer : public BaseJsonIntegerSerializer { public: - AZ_RTTI(JsonUnsignedLongLongSerializer, "{AB048BB3-C280-4166-9E2E-54CE2C3413CA}", BaseJsonSerializer); + AZ_RTTI(JsonUnsignedLongLongSerializer, "{AB048BB3-C280-4166-9E2E-54CE2C3413CA}", BaseJsonIntegerSerializer); AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/BoolSerializerTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/BoolSerializerTests.cpp index cf9d76e79d..6396e4ccdf 100644 --- a/Code/Framework/AzCore/Tests/Serialization/Json/BoolSerializerTests.cpp +++ b/Code/Framework/AzCore/Tests/Serialization/Json/BoolSerializerTests.cpp @@ -63,6 +63,18 @@ namespace JsonSerializationTests : public BaseJsonSerializerFixture { public: + struct BoolPointerWrapper + { + AZ_TYPE_INFO(BoolPointerWrapper, "{2E67C069-BB0F-4F00-A704-E964F5FE5ED2}"); + + bool* m_value{ nullptr }; + + ~BoolPointerWrapper() + { + azfree(m_value); + } + }; + void SetUp() override { BaseJsonSerializerFixture::SetUp(); @@ -75,6 +87,12 @@ namespace JsonSerializationTests BaseJsonSerializerFixture::TearDown(); } + void RegisterAdditional(AZStd::unique_ptr& serializeContext) override + { + serializeContext->Class() + ->Field("Value", &BoolPointerWrapper::m_value); + } + void Load(rapidjson::Value& testVal, bool expectedBool, AZ::JsonSerializationResult::Outcomes expectedOutcome) { using namespace AZ::JsonSerializationResult; @@ -242,4 +260,24 @@ namespace JsonSerializationTests Load(m_jsonValue.SetDouble(-1.0f), true, AZ::JsonSerializationResult::Outcomes::Success); Load(m_jsonValue.SetDouble(2.0), true, AZ::JsonSerializationResult::Outcomes::Success); } + + TEST_F(JsonBoolSerializerTests, Load_LoadDefaultToPointer_ValueIsIsInitialized) + { + using namespace AZ::JsonSerializationResult; + + BoolPointerWrapper instance; + + this->m_jsonDocument->Parse(R"({ "Value": {}})"); + ASSERT_FALSE(this->m_jsonDocument->HasParseError()); + + AZ::JsonDeserializerSettings settings; + settings.m_serializeContext = this->m_jsonDeserializationContext->GetSerializeContext(); + settings.m_registrationContext = this->m_jsonDeserializationContext->GetRegistrationContext(); + ResultCode result = AZ::JsonSerialization::Load(instance, *this->m_jsonDocument, settings); + + EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome()); + EXPECT_EQ(Processing::Completed, result.GetProcessing()); + ASSERT_NE(nullptr, instance.m_value); + EXPECT_FALSE(*instance.m_value); + } } // namespace JsonSerializationTests diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/DoubleSerializerTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/DoubleSerializerTests.cpp index d19c38fcdc..4279017276 100644 --- a/Code/Framework/AzCore/Tests/Serialization/Json/DoubleSerializerTests.cpp +++ b/Code/Framework/AzCore/Tests/Serialization/Json/DoubleSerializerTests.cpp @@ -71,6 +71,20 @@ namespace JsonSerializationTests : public BaseJsonSerializerFixture { public: + struct DoublePointerWrapper + { + AZ_TYPE_INFO(DoublePointerWrapper, "{C2FD9E0B-2641-4D24-A3D9-A29FD1A21A81}"); + + double* m_double{ nullptr }; + float* m_float{ nullptr }; + + ~DoublePointerWrapper() + { + azfree(m_float); + azfree(m_double); + } + }; + void SetUp() override { BaseJsonSerializerFixture::SetUp(); @@ -85,6 +99,13 @@ namespace JsonSerializationTests BaseJsonSerializerFixture::TearDown(); } + void RegisterAdditional(AZStd::unique_ptr& serializeContext) override + { + serializeContext->Class() + ->Field("Double", &DoublePointerWrapper::m_double) + ->Field("Float", &DoublePointerWrapper::m_float); + } + void TestSerializers(rapidjson::Value& testVal, double expectedValue, AZ::JsonSerializationResult::Outcomes expectedOutcome) { using namespace AZ::JsonSerializationResult; @@ -275,4 +296,32 @@ namespace JsonSerializationTests EXPECT_EQ(Outcomes::Unsupported, result.GetOutcome()); EXPECT_EQ(42.0f, value); } + + // Pointers + + TEST_F(JsonDoubleSerializerTests, Load_LoadDefaultToPointer_ValuesArIsInitialized) + { + using namespace AZ::JsonSerializationResult; + + DoublePointerWrapper instance; + + this->m_jsonDocument->Parse(R"( + { + "Double": {}, + "Float": {} + })"); + ASSERT_FALSE(this->m_jsonDocument->HasParseError()); + + AZ::JsonDeserializerSettings settings; + settings.m_serializeContext = this->m_jsonDeserializationContext->GetSerializeContext(); + settings.m_registrationContext = this->m_jsonDeserializationContext->GetRegistrationContext(); + ResultCode result = AZ::JsonSerialization::Load(instance, *this->m_jsonDocument, settings); + + EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome()); + EXPECT_EQ(Processing::Completed, result.GetProcessing()); + ASSERT_NE(nullptr, instance.m_double); + ASSERT_NE(nullptr, instance.m_float); + EXPECT_DOUBLE_EQ(0.0, *instance.m_double); + EXPECT_FLOAT_EQ(0.0f, *instance.m_float); + } } // namespace JsonSerializationTests diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/IntSerializerTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/IntSerializerTests.cpp index db764badcb..c4132e983c 100644 --- a/Code/Framework/AzCore/Tests/Serialization/Json/IntSerializerTests.cpp +++ b/Code/Framework/AzCore/Tests/Serialization/Json/IntSerializerTests.cpp @@ -147,6 +147,18 @@ namespace JsonSerializationTests : public BaseJsonSerializerFixture { public: + struct IntegerPointerWrapper + { + AZ_TYPE_INFO(IntegerPointerWrapper, "{F6B3BEF1-59A4-4E45-BF02-DDA868C38A28}"); + + typename SerializerInfo::DataType* m_value{ nullptr }; + + ~IntegerPointerWrapper() + { + azfree(m_value); + } + }; + AZStd::unique_ptr m_serializer; void SetUp() override @@ -161,6 +173,12 @@ namespace JsonSerializationTests BaseJsonSerializerFixture::TearDown(); } + void RegisterAdditional(AZStd::unique_ptr& serializeContext) override + { + serializeContext->Class() + ->Field("Value", &IntegerPointerWrapper::m_value); + } + template::value, int> = 0> void SetValue(rapidjson::Value& out, T in) { @@ -487,6 +505,26 @@ namespace JsonSerializationTests EXPECT_EQ(typename SerializerInfo::DataType(), convertedValue); } + TYPED_TEST(TypedJsonIntSerializerTests, Load_LoadDefaultToPointer_ValueIsIsInitialized) + { + using namespace AZ::JsonSerializationResult; + + IntegerPointerWrapper instance; + + this->m_jsonDocument->Parse(R"({ "Value": {}})"); + ASSERT_FALSE(this->m_jsonDocument->HasParseError()); + + AZ::JsonDeserializerSettings settings; + settings.m_serializeContext = this->m_jsonDeserializationContext->GetSerializeContext(); + settings.m_registrationContext = this->m_jsonDeserializationContext->GetRegistrationContext(); + ResultCode result = AZ::JsonSerialization::Load(instance, *this->m_jsonDocument, settings); + + EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome()); + EXPECT_EQ(Processing::Completed, result.GetProcessing()); + ASSERT_NE(nullptr, instance.m_value); + EXPECT_EQ(0, *instance.m_value); + } + TYPED_TEST(TypedJsonIntSerializerTests, Load_MaxInt8Value_ConvertIfFitsOrUnsupported) { this->template TestMaxValue(); } TYPED_TEST(TypedJsonIntSerializerTests, Load_MaxShortValue_ConvertIfFitsOrUnsupported) { this->template TestMaxValue(); } TYPED_TEST(TypedJsonIntSerializerTests, Load_MaxIntValue_ConvertIfFitsOrUnsupported) { this->template TestMaxValue(); }