Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

JsonUtility nullable fields

Discussion in 'Scripting' started by or113, Feb 23, 2017.

  1. or113

    or113

    Joined:
    Nov 5, 2016
    Posts:
    41
    Hey,
    I'm trying to parse json into class with nullable fields.
    My class looks like this:

    Code (CSharp):
    1. [Serializable]
    2. public class QuestObjective
    3. {
    4.     public int? levelId;
    5.     public bool? isWinner;
    6.     public int? stars;
    7.     public int? coins;
    8.  
    9.     public string text;
    10.     public bool achieved;
    11. }
    And my test code is this:
    Code (CSharp):
    1.         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!
     
    Last edited: Feb 23, 2017
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    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.
     
  3. or113

    or113

    Joined:
    Nov 5, 2016
    Posts:
    41
    Thanks for your response. I'll try to explain more.

    I have this object in my json string:
    Code (CSharp):
    1. {"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.
     
  4. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    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?
     
  5. or113

    or113

    Joined:
    Nov 5, 2016
    Posts:
    41
    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 :)
     
  6. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    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).
     
  7. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Enums?
     
  8. or113

    or113

    Joined:
    Nov 5, 2016
    Posts:
    41
    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:
    https://github.com/SaladLab/Json.Net.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)
     
    georgi_petrovitch likes this.
  9. Gizmoi

    Gizmoi

    Joined:
    Jan 9, 2013
    Posts:
    327
    Enums would be the best way.
    In JSON you can serialize Enums from ints or strings.
    So your enum could be

    Code (CSharp):
    1. enum WinState
    2. {
    3.     Agnostic,
    4.     MustWin,
    5.     MustLose,
    6. }
    And your JSON could be
    Code (CSharp):
    1. {"text": "some text", "winState": 1}
    or
    Code (CSharp):
    1. {"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).
     
    Kiwasi likes this.
  10. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    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.
     
  11. or113

    or113

    Joined:
    Nov 5, 2016
    Posts:
    41
    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.
     
  12. Gizmoi

    Gizmoi

    Joined:
    Jan 9, 2013
    Posts:
    327
    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.
     
  13. or113

    or113

    Joined:
    Nov 5, 2016
    Posts:
    41
    Got it! Good idea. Taking back what I said about enum :)
     
    Gizmoi likes this.
  14. Elringus

    Elringus

    Joined:
    Oct 3, 2012
    Posts:
    483
    Novack and hippogames like this.
  15. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    Still no nullable types in unity json :(
     
  16. Elringus

    Elringus

    Joined:
    Oct 3, 2012
    Posts:
    483
    Doesn't [SerializeReference] added in 2019.3 work with nullables?
     
    Antony-Blackett likes this.
  17. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    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.
     
    Last edited: Jan 3, 2020
  18. Elringus

    Elringus

    Joined:
    Oct 3, 2012
    Posts:
    483
    Ah, then I guess custom serializable wrappers is still the only way to achieve this: https://github.com/Elringus/UnityCo...s/UnityCommon/Runtime/Collections/Nullable.cs
     
    Novack and Antony-Blackett like this.
  19. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    Thanks for sharing. I’ll try it out.
     
  20. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    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
     
    Last edited: Jan 14, 2020
    SimonDarksideJ and Novack like this.
  21. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,688
    Any further updates, other than a quick regex on the output json, any way to ignore serialising null fields, in the same way newtonsoft does with their "NullValueHandling = NullValueHandling.Ignore"?