Json returns null

I got this code from github:

using System;
using UnityEngine;

public static class JsonHelper
{
    public static T[] FromJson<T>(string json)
    {
        Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(json);
        return wrapper.Items;
    }

    public static string ToJson<T>(T[] array)
    {
        Wrapper<T> wrapper = new Wrapper<T>();
        wrapper.Items = array;
        return JsonUtility.ToJson(wrapper);
    }

    public static string ToJson<T>(T[] array, bool prettyPrint)
    {
        Wrapper<T> wrapper = new Wrapper<T>();
        wrapper.Items = array;
        return JsonUtility.ToJson(wrapper, prettyPrint);
    }

    [Serializable]
    private class Wrapper<T>
    {
        public T[] Items;
    }
}

Which looks ok to me, I didn’t find any errors or anything, but when I load a Json file and try to get an array, it doesn’t show an error until I try to acces the array, so in this example the error will be caused:

        //a custom class I made
        scenario[] scenarios;
        //uses the JsonHelper to get the scenarios array
        scenarios = JsonHelper.FromJson<scenario>(scenariosJson.text);
        //this line causes an error
        string text = scenarios[0];

the json file:

{
    "scenarios":[
    {"id":"0",
    "text": "I am {character.age}, {(characetr.age < 50 ? \"I still got some time\" : \"Guess I am getting olf\" )}",
    "popupText": "You are {(characetr.age < 50 ? \"Young\" : \"Old\" )}",
    "conditions": ""},
    {"id":"1",
    "text": "I am {character.firstName} {character.lastName}",
    "popupText": "You are {character.firstName} {character.lastName}",
    "conditions": ""}
]
}

the error message:

NullReferenceException: Object reference not set to an instance of an object
GameManager.addDay () (at Assets/scripts/GameManager.cs:27)
UnityEngine.Events.InvokableCall.Invoke () (at <4a31731933e0419ca5a995305014ad37>:0)
UnityEngine.Events.UnityEvent.Invoke () (at <4a31731933e0419ca5a995305014ad37>:0)
UnityEngine.UI.Button.Press () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:70)
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:114)
UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:57)
UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:272)
UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:501)

I’m fairly certain Unity’s bare bones JsonUtility will fail to properly serialise/deserialise generics. You will need to use a more robust serialiser.

1 Like

fix:
changed the json to:

{
    "Items":[
    {"id":"0",
    "text": "I am {character.age}, {(characetr.age < 50 ? \"I still got some time\" : \"Guess I am getting olf\" )}",
    "popupText": "You are {(characetr.age < 50 ? \"Young\" : \"Old\" )}",
    "conditions": ""},
    {"id":"1",
    "text": "I am {character.firstName} {character.lastName}",
    "popupText": "You are {character.firstName} {character.lastName}",
    "conditions": ""}
]
}
2 Likes

Yes, that’s what I would have suggested. While the idea of the wrapper was meant as a workaround to serialize an array and to deserialize that array again, since your original json did actually had a different key name, you could have simply created the proper class that matches your json.
Specifically

[System.Serializable]
public class ScenarioRoot
{
    public scenario[] scenarios;
}

So instead of loading / saving your scenarios array with the “JsonHelper”, you could simply use Unity’s JsonUtility on the ScenarioRoot object.

ps: class / type names should always start with an upper case letter. Calling your class “scenario” is really strange and can easily lead to confusion down the line.

1 Like

The problem with creaing a class to represent the json is I will use alot of json files, as the game is text based and I need to store all the text data in files, and most of the data will be arrays, so it means I have to make 2 classes(item and root) which means I will end up with many classes, which I don’t want, and this is where Generics come into place(Reducing the classes by half).

And thanks for noting I should start my classes names with upper case letters, I will keep it in mind.

If you don’t want to create classes to represent the Json, you should look at Newtonsoft Json instead.
The dictionary-access you can use through that will make it a lot easier.
https://www.newtonsoft.com/json

1 Like

Don’t complicate your life and just use JsonUtility. It has its limitations that you have to adjust to (change what it don’t or can’t use properly, change Array to List). Everything is described in detail below. Three methods to remember, why wrap it in some wrapper classes like this Helper?

The only rule to remember:
Only plain classes and structures are supported; classes derived from UnityEngine.Object (such as MonoBehaviour or ScriptableObject) are not.

In short, game objects are supposed to wrap data from JSON, not the other way around.

JsonUtility has been getting hate from everyone for years for a reason.
Hell, even Unity’s own developers use Newtonsoft instead (which is why it’s a dependency in among others: Version Control, Unity Collections, ECS, etc.)

1 Like

JsonUtility is often the best Json serializer to use in Unity. It’s built-in, fast and simple to use when you’re already familiar with Unity’s serialization rules. Though it’s definitely not for every use case, especially when you need to read or write Json that’s used outside of Unity, you need the flexibility of a full Json library.

2 Likes

Well, those “reasons” are most of the time hyped way too much. The JsonUtility is just a text / json based extension of Unity’s own serialization system and therefore has the same limitations. In comparison to almost all other json solutions, Unity’s JsonUtility is one of the fastest, probably because of its limitations.

Depending on the usecase there are many different solutions available and JsonUtility, as long as you can live with / work around its limitations, is just one of them.

Well, it’s not clear how your project actually scales and what kind of information you may store in the json. However you usually would have all necessary data in a single json structure. Using generics does not reduce the number of classes at all, it just hides the generation of those from you. The actual generic class is JIT compiled at runtime when a type is bound to a generic type parameter. So when you use for example the generic List class with string, int, Vector3 and GameObject, you will actually have 4 distinct classes that the JIT compiler (or AoT compiler for IL2CPP) would generate.

If you just want to load json without dealing with object mapping at all, you can use my SimpleJSON parser. It’s a single cs file and allows parsing and generating json data and also provides easy access to it. Internally it just parses the data into JSONObjects (internally a Dictionary), JSONArrays (internally a List), JSONStrings, JSONNumber (just a double value) and JSONBool. It’s very extensible to customize or extend the built-in functionality. I’ve also made a Unity specific extension file that just needs to sit next to the main file. It gives implicit conversion support for some Unity types like Vector2/3/4, Color, Quaternion and some other types. Though as I said, you could add your own additions to convert to / from your own types.

ps: I’m wondering: You’re using what looks like string interpolation in the texts you store in your json file. However you can’t really interpret those when the string is loaded dynamically at runtime. Do you have your own string interpolator that works at runtime?

Yes. You need to ‘live with’ or ‘work around’ its limitations.
I was responding to:

Working around limitations IS complicating your life. Which is why everyone switches to another library as soon as they need to do more than very basic serialization/deserialization.

Maybe I’m not very picky because of years spent on really badly written libraries for JSON in C and C++.

The very idea that in C# I can easily serialize/deserialize something and have it already in struct is like a huge kick forward with work.

1 Like

No, that’s only the case when you actually need a workaround :slight_smile: Especially when there are already solutions for certain cases. In most cases it’s quite trivial to adapt to the slight change necessary to make it work natively with JsonUtility. You know, for a small Unity project, all your compiled game code is probably 10% of the size of the Newtonsoft parser :slight_smile: Don’t get me wrong, the Json.NET library is really a great library, but even there you bump into limitations that require workarounds. Vector3 or other Unity types. You may need some converters or object generators that you can register to Json.NET and it handles everything for you. But you still have to do those things because even with Json.NET there are cases that need workarounds or adjustments. Maybe just another attribute, maybe some sort of ContractResolver / JsonConverter magic. I just react a bit allergic against those who praise one solution and condemn another “just because”.

As with any piece of software or library, you have to know its limitations and decide what fits your usecase and what amount of adjustments you can and want to tolerate.

ps: Here’s a benchmark between JsonUtilty, LitJson and Json.NET.

1 Like