クラスター開発者ブログ

LitJSONからUnityのJsonUtilityに移行したときに気になったこと

こんにちは。じょんそん(@johnson65t)です。

Unity 5.3のアップデートでJsonUtilityが追加され、Unity標準の機能でJSONを扱うことができるようになりました。

それまで弊社ではJSONを扱うのにLitJSONを使っていましたが、パフォーマンスに優れたAPIが標準に追加されたことから、こちらを使うようになりました。

移行時に気になった両者の違いと、一部LitJSONでできていたことができなくなって対応が必要だったところを紹介します。

使い方

JsonUtilityの基本的な使い方などは以下の記事などによくまとまっています。

LitJsonとの違い

移行の際に感じたJsonUtilityの良いところと悪いところを挙げていきます。

良いところ

シリアライズ対象を柔軟に決められる

[SerializeField][NonSerialize]でシリアライズ対象となるフィールドを指定できます。

privateだけどシリアライズしたいフィールドがある場合、LitJSONを使っていた時はpublicフィールドに[Obsolete]をつけたりしていたので、それと比べるとかなり扱いやすいと感じています。

LitJSONを使う場合
1
2
3
4
public class User
{
    [Obsolete] public string name;
}
JsonUtilityを使う場合
1
2
3
4
5
[Serializable]
public class User
{
    [SerializeField] string name;
}

プロパティをシリアライズしない

LitJSONがpublicプロパティをシリアライズするのは正直煩わしいと感じていたので、ここも良いところです。

publicなCountプロパティを実装しているファーストクラスコレクションをJSONに変換すると、Countまでシリアライズされるというようなことがなくなりました。

悪いところ

ルートがArrayのJSONをパースできない

これはJsonUtilityの大きな欠点だと思います。

ルートがArrayのJSONをパースする場合、LitJSON.JsonMapper.ToObject<T>なら型パラメーターにListやArrayを指定すればいい感じにパースしてくれるのですが、JsonUtility.FromJson<T>の場合パースされるJSONのルートはObjectである必要があり、ルートがArrayのJSONをパースしようとすると例外になります。

不便なのでアップデートで対応して欲しいところですが、とりあえずワークアラウンドで解決したのでサンプルコードを交えて紹介します。

前提

このようなUserクラスがあって、

1
2
3
4
5
[Serializable]
public class User
{
    public string name;
}

以下のJSONをパースしてList<User>を得たいとします。

1
2
3
4
5
6
7
8
[
    {
        "name": "johnson65t"
    },
    {
        "name": "mizoguche"
    }
]

LitJSONを使う場合

JsonMapper.ToObject<T>の型パラメーターにList<User>を指定すればOKです。

1
2
var json = "[{\"name\": \"johnson65t\"},{\"name\": \"mizoguche\"}]";
List<User> users = JsonMapper.ToObject<List<User>>(json); // OK

JsonUtilityを使う場合

JSONのルートがArrayなので、例外が発生してパースに失敗します。

1
2
3
var json = "[{\"name\": \"johnson65t\"},{\"name\": \"mizoguche\"}]";
List<User> users = JsonUtility.FromJson<List<User>>(json); // NG
// => ArgumentException: JSON must represent an object type.

対象のJSONを{"list": + }で囲んでパースしてから、Listだけ返すヘルパーを実装します。

UnityForumに投稿されていたワークアラウンドを参考にしました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class JsonHelper
{
    public static List<T> ListFromJson<T>(string json)
    {
        var newJson = "{ \"list\": " + json + "}";
        Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(newJson);
        return wrapper.list;
    }

    [Serializable]
    class Wrapper<T>
    {
        public List<T> list;
    }
}

使うときはこうなります。型パラメーターがList<User>ではなくUserなのに注意してください。

1
2
var json = "[{\"name\": \"johnson65t\"},{\"name\": \"mizoguche\"}]";
List<User> users = JsonHelper.ListFromJson<User>(json); // OK

まとめ

まだ一部使いにくいところがありますが、標準のAPIで高速にJSONが扱えるのはいいですね。

このエントリーをはてなブックマークに追加