Files
UnrealEngine/Engine/Source/Runtime/Json/Public/Serialization/JsonSerializable.h
2025-05-18 13:04:45 +08:00

273 lines
8.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Dom/JsonObject.h"
#include "Policies/CondensedJsonPrintPolicy.h"
#include "Serialization/JsonWriter.h"
#include "Serialization/JsonSerializer.h"
#include "Serialization/JsonSerializerReader.h"
#include "JsonSerializerWriter.h"
#include "Misc/TVariant.h"
/**
* Base class for a JSON serializable object
*/
struct FJsonSerializable
{
/**
* Virtualize destructor as we provide overridable functions
*/
JSON_API virtual ~FJsonSerializable();
/**
* Used to allow serialization of a const ref
*
* @return the corresponding json string
*/
JSON_API const FString ToJson(bool bPrettyPrint = true) const;
JSON_API const FUtf8String ToJsonUtf8(bool bPrettyPrint = true) const;
/**
* Serializes this object to its JSON string form
*
* @param bPrettyPrint - If true, will use the pretty json formatter
* @return the corresponding json string
*/
JSON_API virtual const FString ToJson(bool bPrettyPrint=true);
JSON_API virtual const FUtf8String ToJsonUtf8(bool bPrettyPrint = true);
/**
* Serializes this object with a Json Writer
*
* @param JsonWriter - The writer to use
* @param bFlatObject if true then no object wrapper is used
*/
template<class CharType, class PrintPolicy, ESPMode SPMode>
void ToJson(TSharedRef<TJsonWriter<CharType, PrintPolicy>, SPMode> JsonWriter, bool bFlatObject = false) const;
/**
* Serializes the contents of a JSON string into this object
*
* @param Json the JSON data to serialize from
*/
JSON_API virtual bool FromJson(const TCHAR* Json);
JSON_API virtual bool FromJson(const UTF8CHAR* Json);
JSON_API virtual bool FromJson(const FString& Json);
JSON_API virtual bool FromJson(const FUtf8String& Json);
/**
* Serializes the contents of a JSON string into this object
*
* @param Json the JSON data to serialize from
*/
JSON_API virtual bool FromJson(FString&& Json);
JSON_API virtual bool FromJson(FUtf8String&& Json);
/**
* Serializes the contents of a JSON string into this object using FUtf8StringView
*
* @param JsonStringView the JSON data to serialize from
*/
JSON_API bool FromJsonStringView(FUtf8StringView JsonStringView);
/**
* Serializes the contents of a JSON string into this object using FWideStringView
*
* @param JsonStringView the JSON data to serialize from
*/
JSON_API bool FromJsonStringView(FWideStringView JsonStringView);
JSON_API virtual bool FromJson(TSharedPtr<FJsonObject> JsonObject);
/**
* Abstract method that needs to be supplied using the macros
*
* @param Serializer the object that will perform serialization in/out of JSON
* @param bFlatObject if true then no object wrapper is used
*/
virtual void Serialize(FJsonSerializerBase& Serializer, bool bFlatObject) = 0;
};
template<class CharType, class PrintPolicy, ESPMode SPMode>
inline void FJsonSerializable::ToJson(TSharedRef<TJsonWriter<CharType, PrintPolicy>, SPMode> JsonWriter, bool bFlatObject) const
{
FJsonSerializerWriter<CharType, PrintPolicy> Serializer(MoveTemp(JsonWriter));
const_cast<FJsonSerializable*>(this)->Serialize(Serializer, bFlatObject);
}
namespace UE::JsonArray
{
namespace Private
{
template<typename T, typename CharType>
inline bool FromJson(TArray<T>& OutArray, TStringView<CharType> JsonString)
{
OutArray.Reset();
TArray<TSharedPtr<FJsonValue>> ArrayValues;
TSharedRef<TJsonReader<CharType>> JsonReader = TJsonReaderFactory<CharType>::CreateFromView(JsonString);
if (FJsonSerializer::Deserialize(JsonReader, ArrayValues))
{
for (const TSharedPtr<FJsonValue>& Value : ArrayValues)
{
TSharedPtr<FJsonObject>* ArrayEntry;
if (Value.IsValid() && Value->TryGetObject(ArrayEntry))
{
if (ArrayEntry && ArrayEntry->IsValid())
{
FJsonSerializerReader Serializer(*ArrayEntry);
OutArray.Add_GetRef(T()).Serialize(Serializer, false);
}
else
{
UE_LOG(LogJson, Error, TEXT("Failed to parse Json from array"));
return false;
}
}
}
return true;
}
return false;
}
using ReturnStringArgs = TTuple<FString* /*OutValue*/, bool /*bPrettyPrint*/>;
using PrettyWriter = TSharedRef<TJsonWriter<>>;
using CondensedWriter = TSharedRef<TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>>;
using WriterVariants = TVariant<PrettyWriter, CondensedWriter>;
using ToJsonVariantArgs = TVariant<ReturnStringArgs, WriterVariants>;
using PrettySerializer = FJsonSerializerWriter<>;
using CondensedSerializer = FJsonSerializerWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>;
template<typename T, typename...SerializerArgsT>
inline void ToJson_SerializeArrayElements(TArray<T>& InArray, SerializerArgsT...Args)
{
for (T& ArrayEntry : InArray)
{
ArrayEntry.Serialize(Args...);
}
}
template<typename T, typename...SerializerArgsT>
inline void ToJson_SerializeArrayElements(TArray<T*>& InArray, SerializerArgsT...Args)
{
for (T* ArrayEntry : InArray)
{
ArrayEntry->Serialize(Args...);
}
}
template<typename T>
inline void ToJson(TArray<T>& InArray, const ToJsonVariantArgs& InArgs)
{
using PrettySerializerAndWriter = TTuple<PrettySerializer, PrettyWriter>;
using CondensedSerializerAndWriter = TTuple<CondensedSerializer, CondensedWriter>;
using SerializerVariant = TVariant<PrettySerializerAndWriter, CondensedSerializerAndWriter>;
SerializerVariant SerializerToUse = ::Visit([](auto& StoredValue)
{
using StoredValueType = std::decay_t<decltype(StoredValue)>;
if constexpr (std::is_same_v<StoredValueType, ReturnStringArgs>)
{
if (StoredValue.template Get<1>())
{
PrettyWriter NewWriter = TJsonWriterFactory<>::Create(StoredValue.template Get<0>());
return SerializerVariant(TInPlaceType<PrettySerializerAndWriter>(), PrettySerializer(NewWriter), NewWriter);
}
else
{
CondensedWriter NewWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>::Create(StoredValue.template Get<0>());
return SerializerVariant(TInPlaceType<CondensedSerializerAndWriter>(), CondensedSerializer(NewWriter), NewWriter);
}
}
else
{
return ::Visit([](auto& StoredWriter)
{
using StoredWriterType = std::decay_t<decltype(StoredWriter)>;
if constexpr (std::is_same_v<StoredWriterType, PrettyWriter>)
{
return SerializerVariant(TInPlaceType<PrettySerializerAndWriter>(), PrettySerializer(StoredWriter), StoredWriter);
}
else if constexpr (std::is_same_v<StoredWriterType, CondensedWriter>)
{
return SerializerVariant(TInPlaceType<CondensedSerializerAndWriter>(), CondensedSerializer(StoredWriter), StoredWriter);
}
}, StoredValue);
}
}, InArgs);
const bool bCloseWriter = InArgs.IsType<ReturnStringArgs>();
::Visit([bCloseWriter, &InArray](auto& StoredSerializer)
{
StoredSerializer.template Get<0>().StartArray();
ToJson_SerializeArrayElements(InArray, StoredSerializer.template Get<0>(), false);
StoredSerializer.template Get<0>().EndArray();
if (bCloseWriter)
{
StoredSerializer.template Get<1>()->Close();
}
}, SerializerToUse);
}
} // namespace Private
template<typename T>
static bool FromJson(TArray<T>& OutArray, const FString& JsonString)
{
return Private::FromJson(OutArray, FStringView(JsonString));
}
template<typename T>
static bool FromJson(TArray<T>& OutArray, FString&& JsonString)
{
return Private::FromJson(OutArray, FStringView(MoveTemp(JsonString)));
}
template<typename T>
static bool FromJson(TArray<T>& OutArray, FUtf8StringView JsonStringView)
{
return Private::FromJson(OutArray, JsonStringView);
}
template<typename T>
static bool FromJson(TArray<T>& OutArray, FWideStringView JsonStringView)
{
return Private::FromJson(OutArray, JsonStringView);
}
/* non-const due to T::Serialize being a non-const function */
template<typename T>
static const FString ToJson(TArray<T>& InArray, const bool bPrettyPrint = true)
{
FString JsonStr;
Private::ToJson(InArray, Private::ToJsonVariantArgs(TInPlaceType<Private::ReturnStringArgs>(), &JsonStr, bPrettyPrint));
return JsonStr;
}
template<typename T>
static void ToJson(TArray<T>& InArray, Private::PrettyWriter& JsonWriter)
{
Private::ToJson(InArray, Private::ToJsonVariantArgs(TInPlaceType<Private::WriterVariants>(), Private::WriterVariants(TInPlaceType<Private::PrettyWriter>(), JsonWriter)));
}
template<typename T>
static void ToJson(TArray<T>& InArray, Private::CondensedWriter& JsonWriter)
{
Private::ToJson(InArray, Private::ToJsonVariantArgs(TInPlaceType<Private::WriterVariants>(), Private::WriterVariants(TInPlaceType<Private::CondensedWriter>(), JsonWriter)));
}
} // namespace UE::JsonArray