Improved reporting on unsupported types by the Json Serialization
The Json Serialization currently doesn't support AZStd::any, AZStd::variant and AZStd::optional due to various JSON formatting concerns. This wasn't properly reported resulting in confusion about whether the missing functionality is intentional or a bug. This change makes this explicit with an error message. As this solution uses a custom json serializer to report the issue, an option was added so it's possible to overwrite a serializer for a specific type. This doesn't mean that the three listed types will never be supported. If/when a suitable format is found an implementation will be added.
This commit is contained in:
@@ -24,7 +24,12 @@
|
||||
#include <AzCore/Serialization/Json/StringSerializer.h>
|
||||
#include <AzCore/Serialization/Json/TupleSerializer.h>
|
||||
#include <AzCore/Serialization/Json/UnorderedSetSerializer.h>
|
||||
#include <AzCore/Serialization/Json/UnsupportedTypesSerializer.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/any.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/tuple.h>
|
||||
#include <AzCore/std/utils.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
#include <AzCore/std/containers/forward_list.h>
|
||||
@@ -33,12 +38,11 @@
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/containers/variant.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/smart_ptr/intrusive_ptr.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/tuple.h>
|
||||
#include <AzCore/std/utils.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -98,6 +102,13 @@ namespace AZ
|
||||
jsonContext->Serializer<JsonArraySerializer>()
|
||||
->HandlesType<AZStd::array>();
|
||||
|
||||
jsonContext->Serializer<JsonAnySerializer>()
|
||||
->HandlesType<AZStd::any>();
|
||||
jsonContext->Serializer<JsonVariantSerializer>()
|
||||
->HandlesType<AZStd::variant>();
|
||||
jsonContext->Serializer<JsonOptionalSerializer>()
|
||||
->HandlesType<AZStd::optional>();
|
||||
|
||||
MathReflect(jsonContext);
|
||||
}
|
||||
else if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(reflectContext))
|
||||
|
||||
@@ -33,34 +33,38 @@ namespace AZ
|
||||
, m_serializerIter(serializerMapIter)
|
||||
{}
|
||||
|
||||
JsonRegistrationContext::SerializerBuilder* JsonRegistrationContext::SerializerBuilder::HandlesTypeId(const Uuid& uuid)
|
||||
JsonRegistrationContext::SerializerBuilder* JsonRegistrationContext::SerializerBuilder::HandlesTypeId(
|
||||
const Uuid& uuid, bool overwriteExisting)
|
||||
{
|
||||
if (!m_context->IsRemovingReflection())
|
||||
{
|
||||
auto serializer = m_serializerIter->second.get();
|
||||
if (uuid.IsNull())
|
||||
{
|
||||
AZ_Error("Serialization", false,
|
||||
"Could not register Json serializer %s. Its Uuid is null.",
|
||||
serializer->RTTI_GetTypeName()
|
||||
);
|
||||
AZ_Assert(false, "Could not register Json serializer %s. Its Uuid is null.", serializer->RTTI_GetTypeName());
|
||||
return this;
|
||||
}
|
||||
|
||||
auto serializerIter = m_context->m_handledTypesMap.find(uuid);
|
||||
|
||||
if (serializerIter == m_context->m_handledTypesMap.end())
|
||||
if (!overwriteExisting)
|
||||
{
|
||||
m_context->m_handledTypesMap.emplace(uuid, serializer);
|
||||
return this;
|
||||
auto serializerIter = m_context->m_handledTypesMap.find(uuid);
|
||||
if (serializerIter == m_context->m_handledTypesMap.end())
|
||||
{
|
||||
m_context->m_handledTypesMap.emplace(uuid, serializer);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(
|
||||
false,
|
||||
"Couldn't register Json serializer %s. Another serializer (%s) has already been registered for the same Uuid (%s).",
|
||||
serializer->RTTI_GetTypeName(), serializerIter->second->RTTI_GetTypeName(),
|
||||
serializerIter->first.ToString<OSString>().c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_context->m_handledTypesMap.insert_or_assign(uuid, serializer);
|
||||
}
|
||||
|
||||
AZ_Error("Serialization", false,
|
||||
"Couldn't register Json serializer %s. Another serializer (%s) has already been registered for the same Uuid (%s).",
|
||||
serializer->RTTI_GetTypeName(),
|
||||
serializerIter->second->RTTI_GetTypeName(),
|
||||
serializerIter->first.ToString<OSString>().c_str()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -63,52 +63,50 @@ namespace AZ
|
||||
SerializerBuilder* operator->();
|
||||
|
||||
template <typename T>
|
||||
SerializerBuilder* HandlesType()
|
||||
SerializerBuilder* HandlesType(bool overwriteExisting = false)
|
||||
{
|
||||
return HandlesTypeId(azrtti_typeid<T>());
|
||||
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
|
||||
}
|
||||
|
||||
template <template<typename...> class T>
|
||||
SerializerBuilder* HandlesType()
|
||||
SerializerBuilder* HandlesType(bool overwriteExisting = false)
|
||||
{
|
||||
return HandlesTypeId(azrtti_typeid<T>());
|
||||
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
|
||||
}
|
||||
|
||||
template<template<AZStd::size_t...> class T>
|
||||
SerializerBuilder* HandlesType()
|
||||
SerializerBuilder* HandlesType(bool overwriteExisting = false)
|
||||
{
|
||||
return HandlesTypeId(azrtti_typeid<T>());
|
||||
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
|
||||
}
|
||||
|
||||
template<template<typename, AZStd::size_t> class T>
|
||||
SerializerBuilder* HandlesType()
|
||||
SerializerBuilder* HandlesType(bool overwriteExisting = false)
|
||||
{
|
||||
return HandlesTypeId(azrtti_typeid<T>());
|
||||
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
|
||||
}
|
||||
|
||||
template<template<typename, typename, AZStd::size_t> class T>
|
||||
SerializerBuilder* HandlesType()
|
||||
SerializerBuilder* HandlesType(bool overwriteExisting = false)
|
||||
{
|
||||
return HandlesTypeId(azrtti_typeid<T>());
|
||||
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
|
||||
}
|
||||
|
||||
template<template<typename, typename, typename, AZStd::size_t> class T>
|
||||
SerializerBuilder* HandlesType()
|
||||
SerializerBuilder* HandlesType(bool overwriteExisting = false)
|
||||
{
|
||||
return HandlesTypeId(azrtti_typeid<T>());
|
||||
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
|
||||
}
|
||||
|
||||
template<template<typename, AZStd::size_t, typename> class T>
|
||||
SerializerBuilder* HandlesType()
|
||||
SerializerBuilder* HandlesType(bool overwriteExisting = false)
|
||||
{
|
||||
return HandlesTypeId(azrtti_typeid<T>());
|
||||
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
|
||||
}
|
||||
|
||||
protected:
|
||||
struct Placeholder { AZ_TYPE_INFO(PlaceHolder, "{4425191C-F497-411A-A7C3-52928E720B0A}"); };
|
||||
|
||||
SerializerBuilder(JsonRegistrationContext* context, SerializerMap::const_iterator serializerMapIter);
|
||||
SerializerBuilder* HandlesTypeId(const AZ::Uuid& uuid);
|
||||
SerializerBuilder* HandlesTypeId(const AZ::Uuid& uuid, bool overwriteExisting);
|
||||
|
||||
JsonRegistrationContext* m_context = nullptr;
|
||||
SerializerMap::const_iterator m_serializerIter;
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Serialization/Json/UnsupportedTypesSerializer.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonUnsupportedTypesSerializer, SystemAllocator, 0);
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonAnySerializer, SystemAllocator, 0);
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonVariantSerializer, SystemAllocator, 0);
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonOptionalSerializer, SystemAllocator, 0);
|
||||
|
||||
JsonSerializationResult::Result JsonUnsupportedTypesSerializer::Load(void*, const Uuid&, const rapidjson::Value&,
|
||||
JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult;
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Invalid, GetMessage());
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result JsonUnsupportedTypesSerializer::Store(rapidjson::Value&, const void*, const void*, const Uuid&,
|
||||
JsonSerializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult;
|
||||
return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::Invalid, GetMessage());
|
||||
}
|
||||
|
||||
AZStd::string_view JsonAnySerializer::GetMessage() const
|
||||
{
|
||||
return "The Json Serialization doesn't support AZStd::any by design. The Json Serialization attempts to minimize the use of $type, "
|
||||
"in particular the guid version, but no way has yet been found to use AZStd::any without explicitly and always requiring "
|
||||
"one.";
|
||||
}
|
||||
|
||||
AZStd::string_view JsonVariantSerializer::GetMessage() const
|
||||
{
|
||||
return "The Json Serialization doesn't support AZStd::variant by design. The Json Serialization attempts to minimize the use of "
|
||||
"$type, in particular the guid version. While combinations of AZStd::variant can be constructed that don't require a $type, "
|
||||
"this cannot be guaranteed in general.";
|
||||
}
|
||||
|
||||
AZStd::string_view JsonOptionalSerializer::GetMessage() const
|
||||
{
|
||||
return "The Json Serialization doesn't support AZStd::optional by design. No JSON format has yet been found that wasn't deemed too "
|
||||
"complex or overly verbose.";
|
||||
}
|
||||
} // namespace AZ
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class JsonUnsupportedTypesSerializer : public BaseJsonSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonUnsupportedTypesSerializer, "{AFCC76B9-1F28-429D-8B4E-020BFD95ADAC}", BaseJsonSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
|
||||
JsonSerializationResult::Result Load(
|
||||
void* outputValue,
|
||||
const Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context) override;
|
||||
JsonSerializationResult::Result Store(
|
||||
rapidjson::Value& outputValue,
|
||||
const void* inputValue,
|
||||
const void* defaultValue,
|
||||
const Uuid& valueTypeId,
|
||||
JsonSerializerContext& context) override;
|
||||
|
||||
protected:
|
||||
virtual AZStd::string_view GetMessage() const = 0;
|
||||
};
|
||||
|
||||
class JsonAnySerializer : public JsonUnsupportedTypesSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonAnySerializer, "{699A0864-C4E2-4266-8141-99793C76870F}", JsonUnsupportedTypesSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
|
||||
protected:
|
||||
AZStd::string_view GetMessage() const override;
|
||||
};
|
||||
|
||||
class JsonVariantSerializer : public JsonUnsupportedTypesSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonVariantSerializer, "{08F8E746-F8A4-4E83-8902-713E90F3F498}", JsonUnsupportedTypesSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
|
||||
protected:
|
||||
AZStd::string_view GetMessage() const override;
|
||||
};
|
||||
|
||||
class JsonOptionalSerializer : public JsonUnsupportedTypesSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonOptionalSerializer, "{F8AF1C95-BD1B-44D2-9B4A-F5726133A104}", JsonUnsupportedTypesSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
|
||||
protected:
|
||||
AZStd::string_view GetMessage() const override;
|
||||
};
|
||||
} // namespace AZ
|
||||
@@ -544,6 +544,8 @@ set(FILES
|
||||
Serialization/Json/TupleSerializer.cpp
|
||||
Serialization/Json/UnorderedSetSerializer.h
|
||||
Serialization/Json/UnorderedSetSerializer.cpp
|
||||
Serialization/Json/UnsupportedTypesSerializer.h
|
||||
Serialization/Json/UnsupportedTypesSerializer.cpp
|
||||
Serialization/std/VariantReflection.inl
|
||||
Settings/CommandLine.cpp
|
||||
Settings/CommandLine.h
|
||||
|
||||
Reference in New Issue
Block a user