Unity Json

Unity JsonUtility: Serialization and Deserialization

JsonUtility is a class that comes with Unity, facilitating the serialization and deserialization of content based on the JSON format.

Table of contents

Introduction to JSON

JSON, or JavaScript Object Notation, is a standard text-based format for representing structured data based on JavaScript object syntax. In Unity, it allows transforming text into an instance of a C# class.

JSON Example:

{"id":1,"username":"VectorFocus"}

This is equivalent to the following instance of this C# class:


public class User
{
    public int id;
    public string username;
}

var user = new User()
{
    id = 1,
    username = "VectorFocus"
};
        

Serialization with JsonUtility.ToJson

To serialize an object into a JSON string, you can use the JsonUtility.ToJson method.

public class User
{
    public int id;
    public string username;
}

var user = new User()
{
    id = 1,
    username = "VectorFocus"
};

// {"id":1,"username":"VectorFocus"}
string json = JsonUtility.ToJson(user);
        

Deserialization with JsonUtility.FromJson

To deserialize a JSON-formatted string into an object, you can use JsonUtility.FromJson.

string json = "{\"id\":1,\"username\":\"VectorFocus\"}";
User user = JsonUtility.FromJson<User>(json);
        

Deserialization to Monobehaviour and ScriptableObject with JsonUtility.FromJsonOverwrite

JsonUtility.FromJsonOverwrite allows deserialization of JSON into classes inheriting from UnityEngine.Object (Monobehaviour and ScriptableObject). It can also be used for simpler classes by passing an object as the second parameter to update, instead of creating a new object.

using UnityEngine;

public class JsonMonobehaviour : MonoBehaviour
{
    public int number;
    public string informations;

    private void Start()
    {
        string json = "{\"number\":6,\"informations\":\"my data\"}";
        JsonUtility.FromJsonOverwrite(json, this);
    }
}
        

Hiding Fields with JsonUtility

Fields can be hidden from serialization using the [NonSerialized] attribute. Private fields and getters/setters are also ignored.


using UnityEngine;
using System;

public class JsonMonobehaviour : MonoBehaviour
{
    public int number;
    public string informations;

    // hide from JsonUtility
    [NonSerialized]
    public int field;

    // hide from JsonUtility
    private int _field2;

    // hide from JsonUtility
    public int Field3 { get; set; }
}
        

Using Getters/Setters with JsonUtility

Getters and setters can be directly serialized using the [field: SerializeField] attribute. However, the field will be assigned a non-human-friendly key (e.g., k__BackingField).


[field: SerializeField]
public int Field3 { get; set; }
        

Using Arrays with JsonUtility

Arrays or lists can be directly defined in the structure for simple types (int, string, etc.).


public class User
{
    public int id;
    public string username;
    public List<int> points = new List<int>();
    public int[] pointsArray;
}
        

Using Custom Types with JsonUtility

Custom types can be used in your structure; just assign the [System.Serializable] attribute to your Custom class or struct.


    public class User
    {
        public int id;
        public string username;

        // only one group
        public Group group;

        // work with list and array too
        public List<Group> groups = new List<Group>();
    }

    [System.Serializable]
    public class Group
    {
        public string name;
    }

Background Thread with JsonUtility

If your JSON data becomes enormous and JsonUtility becomes slow:

Unity JsonUtility Main Thread

It may be a good idea to run the serialization in another thread to prevent the main thread from being blocked and the game from freezing. Since Unity 2019.1.6, we can use JsonUtility in background thread.
You should not alter any object that is being used in the function while it is running


using System.Collections;
using System.Threading;
using UnityEngine;
using UnityEngine.Events;

public class JsonBackground : MonoBehaviour
{
    public class User
    {
        public int id;
        public string username;
    }

    private void Start()
    {
        string json = "{\"id\":1,\"username\":\"VectorFocus\"}";

        FromJsonBackground<User>(json, (user) =>
        {
            // actions with user
        });
    }

    public void FromJsonBackground<T>(string data, UnityAction<T> unityAction)
    {
        StartCoroutine(FromJsonBackgroundCoroutine<T>(data, unityAction));
    }

    private IEnumerator FromJsonBackgroundCoroutine<T>(string data, UnityAction<T> unityAction)
    {
        T convertData = default(T);

        var thread = new Thread(() =>
        {
            convertData = JsonUtility.FromJson<T>(data);
        });

        thread.Start();

        while (thread.IsAlive)
        {
            yield return null;
        }

        unityAction.Invoke(convertData);
    }
}

I’m not a big fan of this code, I’m not happy about mixing thread and coroutine.
Another problem is added: if the coroutine is stopped, the thread will continue to run. I haven’t yet found a solution to this problem, as Thread.Abort is obsolete and  CancellationToken doesn’t seem to meet this need.

Background Thread with Task and Async

You can use C#’s Task and async/await features in Unity to perform these operations in the background. Remember to call Unity-related operations on the main thread when necessary.

using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;

public class JsonBackgroundTask : MonoBehaviour
{
    public class User
    {
        public int id;
        public string username;
    }

    private void Start()
    {
        string json = "{\"id\":1,\"username\":\"VectorFocus\"}";
        FromJsonTask<User>(json, (user) =>
        {
            // actions with user
        });

        AwaitSyntax();
    }

    public async void AwaitSyntax()
    {
        // if you prefer without callback with await
        string json = "{\"id\":1,\"username\":\"VectorFocus\"}";
        var user = await FromJsonGetTask<User>(json);
    }

    public async void FromJsonTask<T>(string json, UnityAction unityAction)
    {
        var data = await Task.Run(() => JsonUtility.FromJson<T>(json));
        unityAction?.Invoke(data);
    }

    public Task FromJsonGetTask<T>(string json)
    {
        return Task.Run(() => JsonUtility.FromJson<T>(json));
    }
}

I have the same problem here as with the code using the thread, the task will continue even if the object is destroyed.
You can modify the code to add a CancellationToken, but it doesn’t seem possible to stop JsonUtility execution once it’s started.

EditorJsonUtility in Editor Context

EditorJsonUtility is a similar utility to JsonUtility but is specifically designed for the Unity Editor. It provides more control over serialization and deserialization in editor scripts.


using UnityEditor;
using UnityEngine;

public class EditorJsonExample
{
    [MenuItem("Tools/Deserialize JSON")]
    private static void DeserializeJson()
    {
        User user = new User() { id = 1 };
        string json = EditorJsonUtility.ToJson(user);
    }
}
        

Original illustration by J S of Pixabay

Leave a Reply

Your email address will not be published. Required fields are marked *