// Copyright 2014-2019 Vladimir Alyamkin. All Rights Reserved. #pragma once #include "VaRestDefines.h" #include "Dom/JsonObject.h" #include "Templates/UnrealTypeTraits.h" #include "VaRestJsonObject.generated.h" class UVaRestJsonValue; /** * Blueprintable FJsonObject wrapper */ UCLASS(BlueprintType, Blueprintable) class VAREST_API UVaRestJsonObject : public UObject { GENERATED_UCLASS_BODY() public: /** Reset all internal data */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void Reset(); /** Get the root Json object */ TSharedRef& GetRootObject(); /** Set the root Json object */ void SetRootObject(const TSharedPtr& JsonObject); ////////////////////////////////////////////////////////////////////////// // Serialization /** Serialize Json to string (formatted with line breaks) */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") FString EncodeJson() const; /** Serialize Json to string (single string without line breaks) */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") FString EncodeJsonToSingleString() const; /** Construct Json object from string */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") bool DecodeJson(const FString& JsonString, bool bUseIncrementalParser = true); ////////////////////////////////////////////////////////////////////////// // FJsonObject API /** Gets the type of value as string for a given field */ UFUNCTION(BlueprintPure, Category = "VaRest|Json") FString GetFieldTypeString(const FString& FieldName) const; /** Returns a list of field names that exist in the object */ UFUNCTION(BlueprintPure, Category = "VaRest|Json") TArray GetFieldNames() const; /** Checks to see if the FieldName exists in the object */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") bool HasField(const FString& FieldName) const; /** Remove field named FieldName */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void RemoveField(const FString& FieldName); /** Get the field named FieldName as a JsonValue */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") UVaRestJsonValue* GetField(const FString& FieldName) const; /** Add a field named FieldName with a Value */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetField(const FString& FieldName, UVaRestJsonValue* JsonValue); /** Get the field named FieldName as a Json Array */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") TArray GetArrayField(const FString& FieldName) const; /** Set an ObjectField named FieldName and value of Json Array */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetArrayField(const FString& FieldName, const TArray& InArray); /** Adds all of the fields from one json object to this one */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void MergeJsonObject(UVaRestJsonObject* InJsonObject, bool Overwrite); ////////////////////////////////////////////////////////////////////////// // FJsonObject API Helpers (easy to use with simple Json objects) /** Get the field named FieldName as a number. Ensures that the field is present and is of type Json number. * Attn.!! float used instead of double to make the function blueprintable! */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") float GetNumberField(const FString& FieldName) const; /** DEPRECATED Attn.!! float used instead of double to make the function blueprintable! */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetNumberField(const FString& FieldName, float Number); /** Add a field named FieldName with Number as value */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetNumberFieldDouble(const FString& FieldName, double Number); /** Get the field named FieldName as an Integer. Ensures that the field is present and is of type Json number. */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") int32 GetIntegerField(const FString& FieldName) const; /** Add a field named FieldName with Integer as value. */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetIntegerField(const FString& FieldName, int32 Number); /** Get the field named FieldName as an Int64. Ensures that the field is present and is of type Json number. */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") int64 GetInt64Field(const FString& FieldName) const; /** Add a field named FieldName with Int64 as value. */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetInt64Field(const FString& FieldName, int64 Number); /** Get the field named FieldName as a string. */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") FString GetStringField(const FString& FieldName) const; /** Add a field named FieldName with value of StringValue */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetStringField(const FString& FieldName, const FString& StringValue); /** Get the field named FieldName as a boolean. */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") bool GetBoolField(const FString& FieldName) const; /** Set a boolean field named FieldName and value of InValue */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetBoolField(const FString& FieldName, bool InValue); /** Get the field named FieldName as a Json object. */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") UVaRestJsonObject* GetObjectField(const FString& FieldName) const; /** Set an ObjectField named FieldName and value of JsonObject */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetObjectField(const FString& FieldName, UVaRestJsonObject* JsonObject); /** Set a map of fields with String values */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetMapFields_string(const TMap& Fields); /** Set a map of fields with uint8 values */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetMapFields_uint8(const TMap& Fields); /** Set a map of fields with int32 values */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetMapFields_int32(const TMap& Fields); /** Set a map of fields with int64 values */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetMapFields_int64(const TMap& Fields); /** Set a map of fields with bool values */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetMapFields_bool(const TMap& Fields); private: /** Internal implementation for setting map fields. */ template void SetMapFields_Impl(const TMap& Fields) { for (auto& field : Fields) { // No need to support all int types as they're not supported by BP if (std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) { SetNumberField(field.Key, field.Value); } else if (std::is_same_v) { SetBoolField(field.Key, (bool)field.Value); } } } /** Internal implementation to get number arrays of different types */ template TArray GetTypeArrayField(const FString& FieldName) const { TArray NumberArray; if (!JsonObj->HasTypedField(FieldName) || FieldName.IsEmpty()) { UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Array"), *VA_FUNC_LINE, *FieldName); return NumberArray; } const TArray> JsonArrayValues = JsonObj->GetArrayField(FieldName); for (TArray>::TConstIterator It(JsonArrayValues); It; ++It) { const auto Value = (*It).Get(); if (Value->Type != EJson::Number) { UE_LOG(LogVaRest, Error, TEXT("Not Number element in array with field name %s"), *FieldName); } NumberArray.Add((*It)->AsNumber()); } return NumberArray; } ////////////////////////////////////////////////////////////////////////// // Array fields helpers (uniform arrays) public: /** Get the field named FieldName as a Number Array. Use it only if you're sure that array is uniform! * Attn.!! float used instead of double to make the function blueprintable! */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") TArray GetNumberArrayField(const FString& FieldName) const; /** Get the field named FieldName as a Number Array. Use it only if you're sure that array is uniform! */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") TArray GetIntegerArrayField(const FString& FieldName) const; /** DEPRECATED Attn.!! float used instead of double to make the function blueprintable! */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetNumberArrayField(const FString& FieldName, const TArray& NumberArray); /** Set an ObjectField named FieldName and value of Number Array */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetNumberArrayFieldDouble(const FString& FieldName, const TArray& NumberArray); /** Get the field named FieldName as a String Array. Use it only if you're sure that array is uniform! */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") TArray GetStringArrayField(const FString& FieldName) const; /** Set an ObjectField named FieldName and value of String Array */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetStringArrayField(const FString& FieldName, const TArray& StringArray); /** Get the field named FieldName as a Bool Array. Use it only if you're sure that array is uniform! */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") TArray GetBoolArrayField(const FString& FieldName) const; /** Set an ObjectField named FieldName and value of Bool Array */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetBoolArrayField(const FString& FieldName, const TArray& BoolArray); /** Get the field named FieldName as an Object Array. Use it only if you're sure that array is uniform! */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") TArray GetObjectArrayField(const FString& FieldName) const; /** Set an ObjectField named FieldName and value of Ob Array */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetObjectArrayField(const FString& FieldName, const TArray& ObjectArray); ////////////////////////////////////////////////////////////////////////// // Deserialize public: /** Deserialize byte content to json */ int32 DeserializeFromUTF8Bytes(const ANSICHAR* Bytes, int32 Size); /** Deserialize byte content to json */ int32 DeserializeFromTCHARBytes(const TCHAR* Bytes, int32 Size); /** Deserialize byte stream from reader */ void DecodeFromArchive(TUniquePtr& Reader); ////////////////////////////////////////////////////////////////////////// // Serialize public: /** Save json to file */ bool WriteToFile(const FString& Path) const; /** * Blueprint Save json to filepath * * @param bIsRelativeToProjectDir If set to 'false' path is treated as absolute */ UFUNCTION(BlueprintCallable, Category = "VaRest|Json") bool WriteToFilePath(const FString& Path, const bool bIsRelativeToProjectDir = true); static bool WriteStringToArchive(FArchive& Ar, const TCHAR* StrPtr, int64 Len); ////////////////////////////////////////////////////////////////////////// // Data private: /** Internal JSON data */ TSharedRef JsonObj; };