LoginSignup
2
1

More than 3 years have passed since last update.

UnityEngine.JsonUtilityを使ってJSON配列をオブジェクトリストに変換する

Posted at

概要

UnityにはJsonUtilityというJSON <-> Object に変換できるクラスが存在していますが、残念ながらルートがリストのJsonには対応していません。

var jsonArray = "[{...}, {...}]";
var res = JsonUtility.FromJson<List<MyClass>>(jsonArray); // System.ArgumentException : JSON must represent an object type.

悲しいね。

ただ、サーバー通信することを考えると、普通にJSON配列を返して配列をデシリアライズしたいものです。
(JSONオブジェクトを返して内部にリストを持たせたら解決はするけど、なんか「できない」っていうの嫌なの)

かといって、ひとつひとつEntityにデシリアライズの実装を書くのも面倒…ということで、Json配列をList型にできるWrapperクラスを作成しました。
あとついでにNullチェックなどもするようにしました。

UnityJsonDeserializer.cs
https://gist.github.com/brbranch/f95da90291419f19f0e41fccc6adc4ea

使い方

とりあえずJSON -> Objectだけです。
テストでも張り付けておきますね。

public class JsonDeserializerTest {
    [Serializable]
    protected class MyClass {
        [SerializeField] private int test1;
        [NotNull][SerializeField] private string test2;
        [SerializeField] private InnerClass1 test3;
        [SerializeField] private List<int> test4;

        public override string ToString() {
            return $"test1:{test1},test2:{test2},test3:{test3},test4:[{string.Join(",", test4)}]";
        }
    }

    [Serializable]
    protected class InnerClass1 {
        [SerializeField] private int a;
        [SerializeField] private InnerClass2 b;

        public override string ToString() {
            return $"{{a:{a},b:{b}}}";
        }
    }

    [Serializable]
    protected class InnerClass2 {
        [SerializeField] private int c;

        public override string ToString() {
            return c.ToString();
        }
    }

    [Test]
    public void JsonDeserializerTestSuccess() {
        var se = JsonDeserializer.FromJsonArray<MyClass>(jsonAry);
        var res = string.Join(",", se.Select(s => s.ToString()));
        Assert.AreEqual(res, "test1:1,test2:abc,test3:{a:1,b:3},test4:[3,4,5],test1:2,test2:bcd,test3:{a:2,b:3},test4:[]");
    }

    [Test]
    public void JsonDeserializerTestShouldError() {
        try {
            var se = JsonDeserializer.FromJsonArray<MyClass>(jsonAry2);
            var res = string.Join(",", se.Select(s => s.ToString()));
            Assert.Fail($"expect JsonDecodeException but actual not occurred: {res}");
        }
        catch (JsonDecodeException e) {
            Assert.AreEqual(e.Message, "failed to parse json.");
        }
    }

    [Test]
    public void JsonDeserializerTestShouldError2() {
        try {
            var se = JsonDeserializer.FromJsonArray<MyClass>(jsonAry3);
            var res = string.Join(",", se.Select(s => s.ToString()));
            Assert.Fail($"expect JsonDecodeException but actual not occurred: {res}");
        }
        catch (JsonDecodeException e) {
            Assert.AreEqual(e.Message, "test2 is null.");
        }
    }

    private static readonly string jsonAry = @"[
{""test1"": 1,""test2"":""abc"", ""test3"": {""a"": 1, ""b"": {""c"": 3}}, ""test4"": [3,4,5]},
{""test1"": 2,""test2"":""bcd"", ""test3"": {""a"": 2, ""b"": {""c"": 3}}, ""test4"": []}
]";
    private static readonly string jsonAry2 = @"[
{""test1"": 1,""test2"":b, ""test3"": {""a"": 1, ""b"": {""c"": 3}}, ""test4"": [3,4,5]},
{""test1"": 2,""test2"":""bcd"", ""test3"": {""a"": 2, ""b"": {""c"": 3}}, ""test4"": []}
]";

    private static readonly string jsonAry3 = @"[
{""test1"": 1,""test3"":2, ""test3"": {""a"": 1, ""b"": {""c"": 3}}, ""test4"": [3,4,5]},
{""test1"": 2,""test2"":""bcd"", ""test3"": {""a"": 2, ""b"": {""c"": 3}}, ""test4"": []}
]";
}

あんまりちゃんとチェックはしてくれない子なので使い勝手はよくないです。

ちなみに

List -> JSON への変更は、JsonUtilityを使っても簡単にできます。

var json = $"[{string.Join(",", objectList.Select(JsonUtility.ToJson))}]";
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1