keywords: UE4, Json, C++, Convert json to ustruct, Convert struct to json

Build.cs

using UnrealBuildTool;

public class TestPrj : ModuleRules
{
	public TestPrj(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Json", "JsonUtilities" });

        if (Target.bBuildEditor)
        {
            PrivateDependencyModuleNames.AddRange(new string[] { "UnrealEd" });
        }
    }
}

JsonTestActor.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "JsonTestActor.generated.h"

USTRUCT()
struct FJsonActorInfo
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY()
        FTransform Transform;

    UPROPERTY()
        TArray<UStaticMesh*> MeshList;
};

USTRUCT()
struct FJsonActorList
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY()
        TArray<FJsonActorInfo> Actors;
};

UCLASS()
class TESTPRJ_API AJsonTestActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AJsonTestActor();

    UFUNCTION(Blueprintcallable)
    void WriteJson();

    UFUNCTION(Blueprintcallable)
    void ReadJson();
};

JsonTestActor.cpp

#include "JsonTestActor.h"

#include "Editor/EditorEngine.h"
#include "LevelEditorViewport.h"
#include "EngineUtils.h"
#include "Components/InstancedStaticMeshComponent.h"
#include "JsonObjectConverter.h"
#include "Misc/FileHelper.h"

// Sets default values
AJsonTestActor::AJsonTestActor()
{
}

void AJsonTestActor::WriteJson()
{
#if WITH_EDITOR
    FJsonActorList ActorList;
    ActorList.Actors.Empty();
    if (UWorld* World = GEditor->GetLevelViewportClients()[0]->GetWorld())
    {
        for (TActorIterator<AActor> Itr(World); Itr; ++Itr)
        {
            bool Appended = false;
            AActor* Actor = (*Itr);
            const TSet<UActorComponent*>& Components = Actor->GetComponents();
            for (UActorComponent* Component : Components)
            {
                if (UStaticMeshComponent* InstancedStaticMeshComponent = Cast<UStaticMeshComponent>(Component))
                {
                    if (!Appended)
                    {
                        Appended = true;
                        ActorList.Actors.Add(FJsonActorInfo());

                        ActorList.Actors.Last().Transform = Actor->GetTransform();
                        ActorList.Actors.Last().MeshList.Add(InstancedStaticMeshComponent->GetStaticMesh());
                    }
                    else
                    {
                        ActorList.Actors.Last().MeshList.Add(InstancedStaticMeshComponent->GetStaticMesh());
                    }
                }
            }
        }

        TSharedPtr<FJsonObject> JsonObject = FJsonObjectConverter::UStructToJsonObject<FJsonActorList>(ActorList);
        FString JsonStr = TEXT("");
        TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&JsonStr);
        if (FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer) && JsonObject.IsValid())
        {
            IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
            FString SavePath = FPaths::ProjectSavedDir() + TEXT("/JsonTest/");
            if (!PlatformFile.DirectoryExists(*SavePath))
            {
                PlatformFile.CreateDirectory(*SavePath);
            }

            static const FString JsonFileName(TEXT("mesh_actors.json"));
            FString JsonFullPath = SavePath + JsonFileName;

            FFileHelper::SaveStringToFile(JsonStr, *JsonFullPath);
        }
    }
#endif
}

void AJsonTestActor::ReadJson()
{
#if WITH_EDITOR
    static const FString JsonFileName(TEXT("mesh_actors.json"));
    FString SavePath = FPaths::ProjectSavedDir() + TEXT("/JsonTest/");
    FString JsonFullPath = SavePath + JsonFileName;
    IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
    if (!PlatformFile.FileExists(*JsonFullPath))
    {
        UE_LOG(LogTemp, Error, TEXT("File [%s] doesn't exist"), *JsonFullPath);
        return;
    }

    FString JsonStr;
    FFileHelper::LoadFileToString(JsonStr, *JsonFullPath);

    TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(JsonStr);
    TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
    if (FJsonSerializer::Deserialize(JsonReader, JsonObject) && JsonObject.IsValid())
    {
        FJsonActorList ActorList;
        if (FJsonObjectConverter::JsonObjectToUStruct<FJsonActorList>(JsonObject.ToSharedRef(), &ActorList))
        {
            for (const FJsonActorInfo& ActorInfo : ActorList.Actors)
            {
                for (const UStaticMesh* Mesh : ActorInfo.MeshList)
                {
                    UE_LOG(LogTemp, Display, TEXT("mesh path: %s"), *Mesh->GetPathName());
                }
            }
        }
    }
#endif
}

The uproperty of UStaticMesh pointer can’t be initialized if the static mesh asset missed in game.

Json output:

{
	"actors": [
		{
			"transform":
			{
				"rotation":
				{
					"x": 0,
					"y": 0,
					"z": 0,
					"w": 1
				},
				"translation":
				{
					"x": 0,
					"y": 0,
					"z": 0
				},
				"scale3D":
				{
					"x": 1,
					"y": 1,
					"z": 1
				}
			},
			"meshList": [
				"StaticMesh'/Engine/EngineSky/SM_SkySphere.SM_SkySphere'"
			]
		},
		{
			"transform":
			{
				"rotation":
				{
					"x": 0,
					"y": -1.3470648809743579e-05,
					"z": 0,
					"w": 1
				},
				"translation":
				{
					"x": -399.75146484375,
					"y": 0,
					"z": 130.27708435058594
				},
				"scale3D":
				{
					"x": 0.75,
					"y": 0.75,
					"z": 1
				}
			},
			"meshList": [
				"StaticMesh'/Game/Geometry/Meshes/TemplateFloor.TemplateFloor'"
			]
		}
	]
}

Enjoy yourself. It’s later than you think. -Chinese Proverbs