Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Resolved How do i use the deserialized JSON data and what is the better option to deserialize it?

Discussion in 'Scripting' started by gjaccieczo, Jun 30, 2021.

  1. gjaccieczo

    gjaccieczo

    Joined:
    Jun 30, 2021
    Posts:
    306
    Hello everyone,

    I'm a both Unity and C# newbie, so excuse me if my question is dumb.

    I have a small project that i'm working on, that i picked up to learn both of the aformentioned technologies. A part of this project is retrieving all the constant values from my JSON file and using them in my game. My JSON file is fairly simple, having a following structure:

    Code (CSharp):
    1. {
    2.     "heroes" : [
    3.         {
    4.             "heroNumber": 1,
    5.             "heroName": "Alex",
    6.         },
    7.         {
    8.             "heroNumber": 2,
    9.             "heroName": "Bob",
    10.         },
    11.         {
    12.             "heroNumber": 3,
    13.             "heroName": "Chris",
    14.         },
    15.     ]
    16. }
    I do not intend to make the JSON file any more complex, other than, maybe, adding some more entries.

    Now the code that reads the JSON file. I have two solutions for that, one being a more "complex" one and a "simpler" one.

    I found the more complex one on stackexchange and it seems to work. However, i had to use a Json.NET for Unity package from jilleJr to make it work properly:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using UnityEngine;
    5. using Newtonsoft.Json;
    6.  
    7. [System.Serializable]
    8. public class HeroList : MonoBehaviour
    9. {
    10.     void Start()
    11.     {
    12.         Deserializer.DeserializingRootItem();
    13.     }
    14.  
    15. [System.Serializable]
    16.  
    17. public partial class Deserializer
    18. {
    19.     public static void DeserializingRootItem()
    20.     {
    21.         string jsonPath;
    22.         jsonPath = File.ReadAllText(Application.dataPath + "/list_of_heroes.json");
    23.         RootItem deserializedHero = JsonConvert.DeserializeObject<RootItem>(jsonPath);
    24.  
    25.     }
    26.  
    27. }
    28.  
    29. [System.Serializable]
    30. public class DeserializedHeroList
    31. {
    32.     public List<RootItem> deserializedHeroList = new List<RootItem>();
    33.  
    34. }
    35.  
    36. [System.Serializable]
    37. public partial class RootItem
    38. {
    39.     [JsonProperty("heroes")]
    40.     public List<Hero> heroes { get; set; }
    41. }
    42.  
    43. [System.Serializable]
    44.     public partial class Hero
    45.     {
    46.         [JsonProperty("heroNumber")]
    47.         public int heroNumber { get; set; }
    48.         [JsonProperty("heroName")]
    49.         public string heroName { get; set; }
    50.  
    51.     }
    52. }
    For example: using the solution above, i'm able to deserialize the JSON and Debug.Log a value of my choosing (in this case of the second entry) by putting Debug.Log(deserializedHero.heroes[1].heroName) into the DeserializingRootItem(). However, i cannot understand how to use the deserialized data outside of that method.

    I found another solution on Youtube
    . I've tried it out as well

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class JSONdeserializer : MonoBehaviour
    6. {
    7.     public TextAsset textJSON;
    8.  
    9.     [System.Serializable]
    10.  
    11.     public class Hero
    12.     {
    13.         public int heroNumber;
    14.         public string heroName;
    15.     }
    16.  
    17.     [System.Serializable]
    18.     public class HeroList
    19.     {
    20.            public Hero[] heroes;
    21.     }
    22.  
    23.     public HeroList myHeroList = new HeroList();
    24.  
    25.     // Start is called before the first frame update
    26.     void Start()
    27.     {
    28.         myHeroList = JsonUtility.FromJson<HeroList>(textJSON.text);
    29.     }
    30.  
    31.     // Update is called once per frame
    32.     void Update()
    33.     {
    34.      
    35.     }
    36. }
    37.  
    Now, the solution above lists the heroes in the inspector windows on project's launch. However, i cannot understand how i use the data listed.

    So eventually, i have several questions:
    1. Which one of the two solutions would fit my simple JSON file deserialization needs better?
    2. In the case of the first solution, how do i use the deserialized data outside of the DeserializingRootItem()?
    3. In the case of the second solution, how do i use the deserialized data at all?
    Thank you in advance for your answers.
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,932
    In your final code sample, it seems like you have everything in place for loading your hero list into a field in your script. What part are you struggling with after that? Your
    myHeroList
    field has all your data, do with it what you want.
     
    gjaccieczo and Bunny83 like this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,020
    I realize you may have hand-monkey edited the JSON when posting it here, but beware the JSON you quoted at the top of your post is NOT VALID. It has at least four (4) illegal commas where none are permitted.

    You can validate JSON at jsonlint.com.

    Some JSON readers will happily guzzle down invalid JSON.

    Some JSON readers will complain bitterly and loudly.

    Some JSON readers will silently fail to hydrate all or part(s) of your invalid object, with no indication why.

    Always lint your data, especially if you hand-edit it.
     
    Last edited: Jul 1, 2021
  4. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,109
    Yes, based on the pure JSON specification it's not valid since JSON is just a subset of javascript. In pure js you are allowed to have trailing commas in objects or arrays. Though pure JSON does not allow such commas. The syntax of JSON can be best learned at json.org. A json file / fragment consists of a single "value". So just follow the lines until you reach the end. As you can see, following a comma either inside an object or inside an array there has to be a next value

    Now, assuming the json itself is fixed, back to topic. JSON is just an object notation format. So it describes objects in a string / text format. So after loading / parsing a json file you have the described objects as actual C# object in memory. So you can simply access any data you want from those objects like any other C# object. As @PraetorBlue said it's up to you what you want to do with that data.

    Just some quick notes on your code. In your first example, why do you have some of the classes be declared as partial classes? You should be careful with partial classes. They can easily lead to bad design choices and makes the code harder to read. You also seem to stick the Serializable attribute to literally every class, even those which are not serialized or do not contain any data that could be serialized (like the Deserializer class which is an empty class).

    Your "DeserializedHeroList" class is not used at all so it's just noise in your example which just blows up the code for no reason. We could say the same about the Deserializer class. If you strip them out the first solution is almost identical to the second, just using the Json.Net library instead. In your second example you create a new HeroList instance in this line:

    Code (CSharp):
    1. public HeroList myHeroList = new HeroList();
    However the deserializer does already create an HeroList instance based on the json and you actually replace it in this line

    Code (CSharp):
    1. myHeroList = JsonUtility.FromJson<HeroList>(textJSON.text);
    In both cases you will have that "heroes" list which you can read as usual. For example iterate through all elements of the array. In the first case you can do

    Code (CSharp):
    1. foreach(Hero hero in deserializedHero.heroes)
    2. {
    3.     Debug.Log("Hero name: " + hero.heroName + " with number: " + hero.heroNumber);
    4. }
    This code would belong to line 24 after you deserialized your "deserializedHero" object.

    In the second case it's essentially the same but you would use "myHeroList" instead of "deserializedHero" since you named it that way.
     
    gjaccieczo likes this.
  5. gjaccieczo

    gjaccieczo

    Joined:
    Jun 30, 2021
    Posts:
    306
    Wow! First of all, thank you all again for your replies, i didn't expect them to come up so quickly.


    Thank you for your answer PraetorBlue. The part i had trouble with is understanding exactly how to interact with that code. For whatever reason, after i tried the "simpler" solution and saw it pop up in the Inspector, i treated it as something that you cannot interact with in the same way i tried to interact with the "complex" one.


    Thank you for your answer Kurt. Yes indeed, i edited the list to make it smaller because having 20 entries for no reason would be silly.
    Thank you very much for the provided link and info about those picky JSON readers :) I've checked the JSON that i've posted and it's indeed bad. I checked the big one with the validator and it's fine. I'll be sure to use that resource in the future and hope to make a habit of linting the data.


    Thank you for your answer Bunny83. I found this snippet as a part of a tutorial somewhere and i wouldn't be able to answer you why exactly it's there. However i've tried it and it seems to work just fine.
    Could you provide some more explanation on why partial classes may lead to bad design choices? I'm new to it all and would be glad to get some extra info on good and bad practices.

    Now the Serializable attribute was sticked because for whatever reason it wouldn't work without it at the time. I removed the ones i've put before the HeroList class and Deserializer and it works just fine. Maybe i was trying another solution i've found somewhere and forgot to remove it.

    So those two lines are unnecessary, right?


    Thank you very much for your response. Funnily enough, i've found the answer to my second question almost right after i've made this post (how do i use the data outside of that specific method) which was to simply pass a reference type by reference. Basically i should've read the Microsoft C# guides a bit more careful instead of jumping up to making a post.
     
    Kurt-Dekker likes this.