JsonUtility nullable fields

Hey,
I’m trying to parse json into class with nullable fields.
My class looks like this:

[Serializable]
public class QuestObjective
{
    public int? levelId;
    public bool? isWinner;
    public int? stars;
    public int? coins;

    public string text;
    public bool achieved;
}

And my test code is this:

        var testJson = JsonUtility.FromJson<QuestObjective>("{\"isWinner\": true, \"text\":\"this is working\"}");

The testJson variable has the text field as the json, but the isWinner is null.

How do I work with nullable fields? I know the inspector is not support them, and I JsonUtility share the same code base, but my question is - how do I make it serialize the values into my object?

Thanks!

I’ve not used nullable values with my json yet. And I don’t currently use unity’s json (I’m using json.net).

I also am not sure I understand what your issue is. Can you explain what you are trying to do exactly?

I know with json.net that I’m using, if I pass in a json file that is missing some data (like if I don’t have a middle name for example, despite having the property for it) it handles it just fine. I think strings are just empty and other values are null depending on what they are.

Thanks for your response. I’ll try to explain more.

I have this object in my json string:

{"text": "some text", "isWinner": true}

And I’m trying to parse it into the class I posted(QuestObjective), but when I inspect the object I get, the value of isWinner is null(should be true), but the value of the text field is(as expected) “some text”.

I figured this happens because the isWinner is a nullable boolean field, and in my other tests when parsing json strings into nullable fields it is always null value, no matter what is the value in the original json.

Ah, ic. So, would it be better to just not make the bool nullable?
I can’t say how unity is handling it or if this is even a normal response from other json deserializers without testing to see if json.net does the same.

I know json.net uses properties though, and unity’s json uses fields, so there may be some differences there.

Is there a special reason you need these fields to be nullable?

Well, the point of this class is to represent a quest objective, each field is a task the user has to do. For instance, if isWinner is true - the user has to be the winner, if false - it has to lose, and if null it does not matter (mean I won’t even check if he won or not, and the other conditions will be applied, like coins count etc).

If someone has better approach to that I’m opening to hear :slight_smile:

Ah, got it. Well, I do understand that. I would say if nullable bool is creating an issue, could you just make it a string or an int (maybe 0,1,2 to represent the three conditions).

Enums?

Guys thanks for trying to help!
I don’t want use strings because then I have to cast manually each field, this will be pain in the future where many more fields will be add.

Same thing with Enums. It’s work great for my bool example, but will start to be messy with int and strings(yeah I know -1 and empty string, but still have to manually check for each type)

*Both method will make my json much bigger because I have to specify all the fields.

Solution
As much as I didn’t want to use other things other than Unity’s built-ins, I tried json.net with this library:
GitHub - SaladLab/Json.Net.Unity3D: Forked Newtonsoft.Json to support Unity3D

So much more features and works great with my code. I would not recommend using Unity JsonUtility unless you have thousands of json and performance is important(if you’re dealing with the web this is likely not the case)

1 Like

Enums would be the best way.
In JSON you can serialize Enums from ints or strings.
So your enum could be

enum WinState
{
    Agnostic,
    MustWin,
    MustLose,
}

And your JSON could be

{"text": "some text", "winState": 1}

or

{"text": "some text", "winState": "MustWin"}

If you do not specify “winState” in your JSON (assuming your JSON parser handles missing data) it will default to 0 (Agnostic).

1 Like

Yep, I use json.net, which is what we used at work before Unity put in their own json. Granted, ours came from the asset store, but I have always found it to work really well and have great support.

Yes, this will work, but then you will have to explicitly write "winState": 1 in all your json objects(and also for all the other fields!) this adds another layer of maintenance, with json.net I just omit them from the json.

As I stated in the last section of my post: if omitted, “winState” will default to 0. Whatever value of the enum is set to 0 - in this case Agnostic - will be the default value. This is exactly the same as your using null as Agnostic, except the code will be more readable and easily extensible. Added bonus of the JSON being more readable if you use strings, or more “secure” (unreadable) if you use ints.

Got it! Good idea. Taking back what I said about enum :slight_smile:

1 Like

I’ve created a feedback request to add support for nullable types to JsonUtility: https://feedback.unity3d.com/suggestions/add-support-for-nullable-types-to-jsonutility

Will really appreciate any votes you can spend on this idea :slight_smile:

2 Likes

Still no nullable types in unity json :frowning:

Doesn’t [SerializeReference] added in 2019.3 work with nullables?

1 Like

Omg. Must try

----- Edit ----

I gave it a go. It works for classes but not for reference struct types e.g. (int?) It also creates some extremely verbose json which is what I was trying to avoid.

I wanted behaviour something like this:

int? field;

if field has a value
then Serialise field;

That way only if there is a value will it be serialised at all, keeping my game->web json small, otherwise it’s assumed to be null and I can then substitute some default value in a getter function.

Ah, then I guess custom serializable wrappers is still the only way to achieve this: https://github.com/Elringus/UnityCommon/blob/master/Assets/UnityCommon/Runtime/Collections/Nullable.cs

2 Likes

Thanks for sharing. I’ll try it out.

I just tried out your code. It’s nice but still produces more verbose json than I would like…

a null float = {“floatName”:{“value”:0.0,“hasValue”:false} }

Where as I’d rather it just be = {}

My solution is to have a list of vector3’s and floats and make the list empty when i want them null. it’s gross but it does make smaller json.

e.g.
{ “listFloats” : [ ] }
{ “listVector3s” : [ ] }

The downside here is I rely on keeping my variable ordering consistent across versions or have some nice versioning system. Unless i have a list per value, which is also gross… maybe I’ll just write a new json util

2 Likes