// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "WebAPIEditorLog.h" #include "Templates/IsUEnumClass.h" #include "UObject/Class.h" #include "UObject/ReflectedTypeAccessors.h" namespace UE::Json { // Numeric template constexpr typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { return InJsonValue->TryGetNumber(OutValue); } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { return InJsonObject->TryGetNumberField(InFieldName, OutValue); } // Enum template typename TEnableIf::Value, bool>::Type TryGet( const TSharedPtr& InJsonValue, EnumType& OutValue, const TMap& InNameToValue) { bool bResult = false; // Try bool first - TryGetNumber converts "false" to 0, etc. which is undesired for an enum if(InJsonValue->Type != EJson::Boolean) { // Try int only if bool conversion failed uint8 IntValue; bResult = InJsonValue->TryGetNumber(IntValue); if(bResult) { OutValue = StaticCast(IntValue); } else { static const UEnum* TypeEnum = nullptr; if constexpr (TIsUEnumClass::Value) { TypeEnum = StaticEnum(); } if(!TypeEnum && InNameToValue.IsEmpty()) { // UE_LOG(LogWebAPIEditor, Error, TEXT("Tried to convert enum from string, but no lookup was provided.")); return bResult; } FString StrValue; bResult = InJsonValue->TryGetString(StrValue); if(bResult) { if(TypeEnum) { if(int64 EnumValue = TypeEnum->GetValueByNameString(StrValue); EnumValue != INDEX_NONE) { OutValue = StaticCast(EnumValue); } } else if(const EnumType* NameToValue = InNameToValue.Find(StrValue)) { OutValue = *NameToValue; } else { // Got a valid string, but it wasn't in the NameToValue map bResult = false; } } } } return bResult; } template constexpr typename TEnableIf::Value, bool>::Type TryGetField( const TSharedPtr& InJsonObject, const FString& InFieldName, EnumType& OutValue, const TMap& InNameToValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue, InNameToValue); } return false; } // String template <> inline bool TryGet(const TSharedPtr& InJsonValue, FString& OutValue) { return InJsonValue->TryGetString(OutValue); } template <> inline bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, FString& OutValue) { return InJsonObject->TryGetStringField(InFieldName, OutValue); } // Text template <> inline bool TryGet(const TSharedPtr& InJsonValue, FText& OutValue) { FString StrValue; if(InJsonValue->TryGetString(StrValue)) { OutValue = FText::FromString(StrValue); return true; } return false; } template <> inline bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, FText& OutValue) { FString StrValue; if(InJsonObject->TryGetStringField(InFieldName, StrValue)) { OutValue = FText::FromString(StrValue); return true; } return false; } // Bool template constexpr typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { return InJsonValue->TryGetBool(OutValue); } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { return InJsonObject->TryGetBoolField(InFieldName, OutValue); } // Array template typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ContainerType& OutValues) { using ValueType = typename ContainerType::ElementType; const TArray>* Values = nullptr; if(InJsonValue->TryGetArray(Values)) { bool bSuccess = true; if(Values->Num() > 0) { OutValues.Reserve(Values->Num()); for(const TSharedPtr& JsonValue : *Values) { ValueType& Value = OutValues.Emplace_GetRef(); bSuccess &= TryGet(JsonValue, Value); } } return bSuccess; } return false; } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ContainerType& OutValues) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { using ValueType = typename ContainerType::ElementType; return TryGet(JsonField, OutValues); } return false; } // Map template typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, TMap& OutValues) { const TSharedPtr* JsonObject = nullptr; if(InJsonValue->TryGetObject(JsonObject)) { OutValues.Reserve(JsonObject->Get()->Values.Num()); for(TPair>& FieldValuePair : JsonObject->Get()->Values) { ValueType& ItemValue = OutValues.Emplace(MoveTemp(FieldValuePair.Key)); TryGet(FieldValuePair.Value, ItemValue); } return true; } return false; } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TMap& OutValues) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValues); } return false; } template typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, MapType& OutValues) { using KeyType = typename MapType::KeyType; using ValueType = typename MapType::ValueType; return TryGet(InJsonValue, OutValues); } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, MapType& OutValues) { using KeyType = typename MapType::KeyType; using ValueType = typename MapType::ValueType; return TryGetField(InJsonObject, InFieldName, OutValues); } // Optional template constexpr typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, TOptional& OutValue) { ValueType Value; if(TryGet(InJsonValue, Value)) { OutValue = Value; return true; } return true; } template typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TOptional& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { // Field found, so initialize TOptional if(!OutValue.IsSet()) { OutValue = ValueType{}; } return TryGet(JsonField, OutValue); } return true; } // Optional Enum template constexpr typename TEnableIf::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, TOptional& OutValue, const TMap& InNameToValue) { EnumType Value; if(TryGet>(InJsonValue, Value, InNameToValue)) { OutValue = Value; return true; } return true; } template constexpr typename TEnableIf::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TOptional& OutValue, const TMap& InNameToValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { if(!OutValue.IsSet()) { OutValue = EnumType{}; } return TryGet(JsonField, OutValue.GetValue(), InNameToValue); } return true; } // Object (with FromJson) template typename TEnableIf< TAnd< TNot>, TypeTraits::THasFromJson>::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { const TSharedPtr* Value; if(InJsonValue->TryGetObject(Value)) { return OutValue.FromJson(Value->ToSharedRef()); } return false; } template typename TEnableIf< TAnd< TNot>, TypeTraits::THasFromJson>::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return false; } // Object (without FromJson) template typename TEnableIf< TAnd< TNot>>, TNot>>, TNot>, TNot>, TNot>, TNot>, TNot>>::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { static_assert(TypeTraits::THasFromJson::Value, "ValueType must implement FromJson"); return false; } template typename TEnableIf< TAnd< TNot>>, TNot>>, TNot>, TNot>, TNot>, TNot>, TNot>>::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { static_assert(TypeTraits::THasFromJson::Value, "ValueType must implement FromJson"); return false; } // UniqueObj template bool TryGet(const TSharedPtr& InJsonValue, TUniqueObj& OutValue) { return Json::TryGet(InJsonValue, OutValue.Get()); } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TUniqueObj& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue.Get()); } return false; } // TJsonReference template bool TryGet(const TSharedPtr& InJsonValue, TJsonReference& OutValue) { const TSharedPtr* JsonObject = nullptr; if(InJsonValue->TryGetObject(JsonObject)) { FString ReferencePath; if(JsonObject->Get()->TryGetStringField(TEXT("$ref"), ReferencePath)) { OutValue.ResolveDeferred(ReferencePath); return true; } } return Json::TryGet(InJsonValue, *OutValue.Get()); } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TJsonReference& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return false; } template typename TEnableIf>::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { return TryGet(InJsonValue, OutValue); } template typename TEnableIf>::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { return TryGet(InJsonObject, InFieldName, OutValue); } // SharedPtr template bool TryGet(const TSharedPtr& InJsonValue, TSharedPtr& OutValue) { if(InJsonValue->IsNull()) { return true; } // Initialize if invalid if(!OutValue.IsValid()) { OutValue = MakeShared(); } return Json::TryGet(InJsonValue, *OutValue.Get()); } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TSharedPtr& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return false; } template typename TEnableIf>::Value, bool>::Type TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { return TryGet(InJsonValue, OutValue); } template typename TEnableIf>::Value, bool>::Type TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, ValueType& OutValue) { return TryGet(InJsonObject, InFieldName, OutValue); } // SharedRef template bool TryGet(const TSharedPtr& InJsonValue, TSharedRef& OutValue) { return Json::TryGet(InJsonValue, OutValue.Get()); } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TSharedRef& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return false; } // Optional UniqueObj template bool TryGet(const TSharedPtr& InJsonValue, TOptional>& OutValue) { if(OutValue.IsSet()) { TUniqueObj& Value = OutValue.GetValue(); if(TryGet(InJsonValue, OutValue.GetValue())) { OutValue = Value; return true; } } else { TUniqueObj Value; if(TryGet(InJsonValue, Value)) { OutValue = Value; return true; } } return true; } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TOptional>& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return true; } // Optional SharedRef template bool TryGet(const TSharedPtr& InJsonValue, TOptional>& OutValue) { TSharedRef Value = MakeShared(); if(TryGet(InJsonValue, Value)) { OutValue = Value; return true; } return true; } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TOptional>& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return true; } // JsonObject template bool TryGet(const TSharedPtr& InJsonValue, ValueType& OutValue) { const TSharedPtr* Value = nullptr; if(InJsonValue->TryGetObject(Value)) { OutValue = *Value; return true; } return false; } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TSharedPtr& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet<>(JsonField, OutValue); } return false; } template bool TryParse(const TSharedPtr& InJsonValue, TVariant& OutValue) { using VariantType = TVariant; if constexpr (TypeIndex < TVariantSize::Value) { using ValueType = typename TNthTypeFromParameterPack::Type; ValueType Value; if (UE::Json::TryGet(InJsonValue, Value)) { OutValue.template Set(MoveTemp(Value)); return true; } return TryParse(InJsonValue, OutValue); } return false; } // Variant template bool TryGet(const TSharedPtr& InJsonValue, TVariant& OutValue) { if(TryParse<0, ValueTypes...>(InJsonValue, OutValue)) { return true; } return false; } template bool TryGetField(const TSharedPtr& InJsonObject, const FString& InFieldName, TVariant& OutValue) { if(const TSharedPtr JsonField = InJsonObject->TryGetField(InFieldName)) { return TryGet(JsonField, OutValue); } return false; } }