// 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 void ToJson(TSharedRef, 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 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 inline void FJsonSerializable::ToJson(TSharedRef, SPMode> JsonWriter, bool bFlatObject) const { FJsonSerializerWriter Serializer(MoveTemp(JsonWriter)); const_cast(this)->Serialize(Serializer, bFlatObject); } namespace UE::JsonArray { namespace Private { template inline bool FromJson(TArray& OutArray, TStringView JsonString) { OutArray.Reset(); TArray> ArrayValues; TSharedRef> JsonReader = TJsonReaderFactory::CreateFromView(JsonString); if (FJsonSerializer::Deserialize(JsonReader, ArrayValues)) { for (const TSharedPtr& Value : ArrayValues) { TSharedPtr* 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; using PrettyWriter = TSharedRef>; using CondensedWriter = TSharedRef>>; using WriterVariants = TVariant; using ToJsonVariantArgs = TVariant; using PrettySerializer = FJsonSerializerWriter<>; using CondensedSerializer = FJsonSerializerWriter>; template inline void ToJson_SerializeArrayElements(TArray& InArray, SerializerArgsT...Args) { for (T& ArrayEntry : InArray) { ArrayEntry.Serialize(Args...); } } template inline void ToJson_SerializeArrayElements(TArray& InArray, SerializerArgsT...Args) { for (T* ArrayEntry : InArray) { ArrayEntry->Serialize(Args...); } } template inline void ToJson(TArray& InArray, const ToJsonVariantArgs& InArgs) { using PrettySerializerAndWriter = TTuple; using CondensedSerializerAndWriter = TTuple; using SerializerVariant = TVariant; SerializerVariant SerializerToUse = ::Visit([](auto& StoredValue) { using StoredValueType = std::decay_t; if constexpr (std::is_same_v) { if (StoredValue.template Get<1>()) { PrettyWriter NewWriter = TJsonWriterFactory<>::Create(StoredValue.template Get<0>()); return SerializerVariant(TInPlaceType(), PrettySerializer(NewWriter), NewWriter); } else { CondensedWriter NewWriter = TJsonWriterFactory>::Create(StoredValue.template Get<0>()); return SerializerVariant(TInPlaceType(), CondensedSerializer(NewWriter), NewWriter); } } else { return ::Visit([](auto& StoredWriter) { using StoredWriterType = std::decay_t; if constexpr (std::is_same_v) { return SerializerVariant(TInPlaceType(), PrettySerializer(StoredWriter), StoredWriter); } else if constexpr (std::is_same_v) { return SerializerVariant(TInPlaceType(), CondensedSerializer(StoredWriter), StoredWriter); } }, StoredValue); } }, InArgs); const bool bCloseWriter = InArgs.IsType(); ::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 static bool FromJson(TArray& OutArray, const FString& JsonString) { return Private::FromJson(OutArray, FStringView(JsonString)); } template static bool FromJson(TArray& OutArray, FString&& JsonString) { return Private::FromJson(OutArray, FStringView(MoveTemp(JsonString))); } template static bool FromJson(TArray& OutArray, FUtf8StringView JsonStringView) { return Private::FromJson(OutArray, JsonStringView); } template static bool FromJson(TArray& OutArray, FWideStringView JsonStringView) { return Private::FromJson(OutArray, JsonStringView); } /* non-const due to T::Serialize being a non-const function */ template static const FString ToJson(TArray& InArray, const bool bPrettyPrint = true) { FString JsonStr; Private::ToJson(InArray, Private::ToJsonVariantArgs(TInPlaceType(), &JsonStr, bPrettyPrint)); return JsonStr; } template static void ToJson(TArray& InArray, Private::PrettyWriter& JsonWriter) { Private::ToJson(InArray, Private::ToJsonVariantArgs(TInPlaceType(), Private::WriterVariants(TInPlaceType(), JsonWriter))); } template static void ToJson(TArray& InArray, Private::CondensedWriter& JsonWriter) { Private::ToJson(InArray, Private::ToJsonVariantArgs(TInPlaceType(), Private::WriterVariants(TInPlaceType(), JsonWriter))); } } // namespace UE::JsonArray