JsonUtility workaround for dictionaries when trying to desrialize on a collection?

I am trying to set dynamic json collection data using JsonUtilit,and not having a lot of luck, at first I tried getting the raw string (but why would that ever work) so I could iterate over it then cast them to their types, once I had the string types.

This is an example of hacking it to make it work but since I have a nested collection the solution wouldn’t work here: JsonUtility.FromJson to a dynamic object? - Unity Forum

  [Serializable]
    public class JsonHeader
    {
        public string title;
        public string description;
        public string id;
        public JsonData[] data;
    }

    [Serializable]
    public class JsonData
    {
        //Use this type to use as a switch to deseralize to the correct object? 
        public string type;
        public Dictionary<string, object> data;
        //I just need a way to get the data in some form in json utility so I can desacralize it properly. 
    }

    [Serializable]
    public class SingleData...

    [Serializable]
    public class DateData... 

    public void Start()
    {
        string jsonString = @"
        {
            ""title"": ""Tester"",
            ""description"": ""foobar"",
            ""id"": ""1"",
            ""data"": [
                {
                    ""type"": ""single"",
                    ""data"": {
                        ""title"": ""Multiple choice"",
                        ""description"": """",
                        ""id"": ""2"",
                        ""options"": [
                            ""test1"",
                            ""test2""
                        ],
                        ""default"": 0,
                        ""required"": false
                    }
                },
                {     
                    ""type"": ""date"",
                    ""data"": {
                        ""title"": ""Date picker"",
                        ""description"": """",
                        ""id"": ""3"",
                        ""default"": ""2011/11/11"",
                        ""required"": false
                    }
                }
            ]
        }";

        //Not setting the data
        var data = JsonUtility.FromJson<JsonHeader>(jsonString);
        //Setting the data
        var data2 = JsonConvert.DeserializeObject<JsonHeader>(jsonString);

Anyone see a way to do this using JsonUtlity, even if it’s a hack?

You can copy the dictionary data to parallel arrays instead, it’ll serialize those.

Better yet, use Newtonsoft Json.Net instead of JsonUtility and be done with it. As soon as you start needing to “hack” JsonUtility, it’s easier to just use the better JSON package to start with.

2 Likes

Because of iOS I can’t use Newtonsoft.

I’m not able to deseralize to any array, unless I’m missing something.

There has to be a serialisation library you can use on IOS. JsonUtility is pretty damn useless. It can’t serialise anything that Unity can’t draw in the inspector, which is a lot of things honestly.

“There has to be a serialisation library you can use on IOS.”

Yes, JsonUtility. :smile:

One that isn’t completely limited to the point of being useless.

I don’t know what to tell you mate, Unity is pretty bad at making their own libs.

This is why I’m looking for a way to get this to work.

Hence why when someone says “I’m using JsonUtility”, everyone else says, “Use an actual proper serialisation lib”. There has to be others. Have you looked at the Odin serialiser?

unity game engine - Json.NET under Unity3d for iOS - Stack Overflow

Downloading the package for newtonsoft fixes the AOT issues, this is working on iOS.

3 Likes

It’s more complex in the case of JsonUtility as it’s kept around largely for backwards compatibility reasons. Around five years ago (Unity 2019.1) Unity released the following package with a more competent JSON implementation that isn’t dependent on third party libraries like Newtonsoft (though I’d likely still use that over an official one).

https://docs.unity3d.com/Packages/com.unity.serialization@3.1/manual/index.html

2 Likes

The issue with newtonsofts is the build size is increased iirc ~20mb for a mobile build.

Will post my build output later.

Note that Unity’s JsonUtility is actually one of the fastest json parsers in most comparisons because it’s actually written o the C++ side with tons of optimisations as it ties into the internal serialization system. That’s why it has the same limitations. Those strict limitations actually made it that fast.

Apart from that, what’s your actual goal? If you just want to handle arbireary json data, you could use my SimpleJSON library. It’s just a single source file (well there are extension files, one for Unity) and it doesn’t actually map the data to your own classes but simply provides access to the json data in an easy to use manner.

Whatever object mapper you would use, your approach by using a Dictionary<string,object> would require tons of type checking and casting in order to use the data. I’ve originally written the parser outside of Unity specifically to handle webservice requests and answers.

The usage is as simple as

JSONNode n = JSON.Parse(jsonString);
string opt = n["data"][0]["data"]["options"][1];
Debug.Log(opt); // prints test2

The library will rarely cause any error as missing keys just means it will dynamically create a “LazyCreator” which will retroactively create the structure once you assign a value to a nested but missing object. Though be warned that you can not lazily create an array entry with a specific index. When you provide an invalid index, it will simply add an element at the end. So this

JSONNode n = new JSONObject();
n["test"][0]["foobar"] = 5;
n["test"][-42]["foobar"] = 42;
Debug.Log(n.ToString(4))

will create this json

{
    "test":[
        {
            "foobar": 5
        },
        {
            "foobar": 42
        }
    ]
}

The library is simple but has a lot of flexibility. All classes are declared as partial so you can augment whatever data or methods you want into the concept. Have a look at the Unity extension file which adds conversion methods / properties and conversion operators to the JSONNode class so you can transparently read Vector3 or Color values. Adding custom conversion operators is quite easy for other custom classes if that’s necessary. Each JSONNode also has casting properties so you can easily attempt to convert say a string to a float or int.

1 Like

“what’s your actual goal?”

Do you lads not read, it’s the literal title of the question. :smile:

I needed to handle dictionaries in iOS. Almost every suggestion on this forum has been something that wasn’t needed / wrong.

Newtonsoft removed their reflection implementations so it doesn’t use the AOT so it can be used in iOS.

As for the “ton” of type casting, no you don’t you just grab the string type and pass it back through a switch that dwswralizes into its object.