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

[SOLVED]Baffled by JSON deserialized List<T>

Discussion in 'Scripting' started by Flynn_Prime, Sep 2, 2018.

  1. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    387
    This one is really frustrating me. I thought my data serialization system was functional, but now I just noticed that it is deserializing incorrectly. Specifically, there are lists within the Expertise variables in the first script below which are the parts not deserializing correctly.

    I have also included a snippet of the json file that is currently saved. However, on debugging, after deserializing AccountData, the elements of the Lists mentioned above have duplicated... I'm not even sure how this is possible when the json file is there in black and white, with only 1 item in said list, but on deserialization another element has magically appeared?

    Code (CSharp):
    1. using System;
    2.  
    3. [Serializable]
    4. public class CharacterData
    5. {
    6.     public string playerName;
    7.     public int currentLevel;
    8.     public int inventorySize;
    9.     //public int currentHighestMap;
    10.     public Inventory inventory = new Inventory();
    11.     public Expertise primaryExpertise;
    12.     public Expertise secondaryExpertise;
    13. }

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [Serializable]
    6. public class AccountData
    7. {
    8.     public int gold;
    9.     public int gems;
    10.     public int characterSlots;
    11.     //public Achievements achievements;
    12.     public List<CharacterData> saves;
    13. }

    Code (CSharp):
    1. {
    2.   "gold": 0,
    3.   "gems": 0,
    4.   "characterSlots": 3,
    5.   "saves": [
    6.     {
    7.       "playerName": "TestName",
    8.       "currentLevel": 1,
    9.       "inventorySize": 30,
    10.       "inventory": {
    11.         "items": null
    12.       },
    13.       "primaryExpertise": {
    14.         "$type": "BlackMage, Assembly-CSharp",
    15.         "expertiseName": "Black Mage",
    16.         "abilities": [
    17.           {
    18.             "expertise": 0,
    19.             "abilityName": "Fireball",
    20.             "currentLevel": 0
    21.           }
    22.         ]
    23.       },
    24.       "secondaryExpertise": {
    25.         "$type": "WhiteMage, Assembly-CSharp",
    26.         "expertiseName": "White Mage",
    27.         "abilities": [
    28.           {
    29.             "expertise": 1,
    30.             "abilityName": "Regen",
    31.             "currentLevel": 0
    32.           }
    33.         ]
    34.       }
    35.     }
    36.   ]
    37. }

    Code (CSharp):
    1.  public static AccountData LoadAccountData(string path)
    2.     {
    3.         string jsonString = File.ReadAllText(path);
    4.  
    5.         var format = new JsonSerializerSettings()
    6.         {
    7.             TypeNameHandling = TypeNameHandling.Auto
    8.         };
    9.  
    10.         //This data variable shows a list that has duplicated its values, even though the json...
    11.         //file only shows one item in the list
    12.         AccountData data = JsonConvert.DeserializeObject<AccountData>(jsonString, format);
    13.         return data;
    14.     }
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,533
    Are you sure the duplication happens internally in the json deserialization? Perhaps you are adding the same item twice, maybe before and after deserializing.

    DeserializeObject is going to create a new instance. If that is not what you want Json.Net has another way of deserializing fields into an existing instance, I just can‘t remember what it is called right now.
     
  3. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    387
    I have spent 2 evenings trying to debug this to no avail.

    I am pretty sure that it's the Json causing the issue, although not 100%. I have debugged every other script that affects the class in question. If you look at the 2 last code snippets above, surely that proves something extra is going on in deserialization? With debugger attached, Account Data data should deserialize like the Json file. But when it deserializes, there will be 2 fireballs or Regen abilities in the lists instead of one
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,754
    Try using JsonUtility instead JsonConvert.DeserializeObject.
    Also, I would check, if you don't have duplicate script running somewhere.
    Put Debug.Log just after
    AccountData data = JsonConvert.DeserializeObject<AccountData>(jsonString, format);
    to show what is in data. Or you can add breakpoints and expand over data content.
     
  5. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    387
    Json Utility won't serialize my data (polymorphism).

    I already did add a break point at the line you suggested, and the duplicated ability is shown there too. If I then save AccountData to file again, the Json also has a duplicate of every ability. Duplicate may be the wrong word actually. Say my list just contains a single fireball element, when I LoadAccountData there will be 2. Then when I SaveAccountData to json there will also be 2. Then when I load again, there would be 3 fireball elements. I hope that makes sense.

    I can send a link to the bit bucket repo if you would like?
     
  6. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Don't know if this helps, but I just tried your json data with this code and it seemed to work ok (I had to comment out the line
    public Inventory inventory = new Inventory();
    in CharacterData) :-
    Code (CSharp):
    1.     public AccountData LoadAccountData()
    2.     {
    3.         string jsonString = File.ReadAllText(@"D:\Temp\Test.json");
    4.         AccountData data = JsonUtility.FromJson<AccountData>(jsonString);
    5.         return data;
    6.     }
     
  7. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    387
    The issue is definitely linked to this method. I enter debugger mode and attach to unity, and at the breakpoint noted below I inspect the jsonString using JSON viewer. This displays the correct string and data to be deserialized.

    HOWEVER, at breakpoint 2, if I hover over "data" I can see that the list already has a duplicated element! I have no idea what on earth is causing this!

    Code (CSharp):
    1.     public static accountdata loadaccountdata(string path)
    2.     {
    3.         string jsonstring = file.readalltext(path);
    4.  
    5.         var format = new jsonserializersettings()
    6.         {
    7.             typenamehandling = typenamehandling.auto
    8.         };
    9.  
    10.         accountdata data = jsonconvert.deserializeobject<accountdata>(jsonstring, format); //BREAKPOINT 1
    11.         return data; //BREAKPOINT 2
    12.     }
     
  8. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    387
    Solved this issue guys. It was a constructor and reflection issue (using a temporary List, returned from a static method was causing the drama I believe).

    If anyone ever has similar issues, drop me a message and I'll try to be more specific with how I fixed it.
     
    a12012 likes this.
  9. dhy948

    dhy948

    Joined:
    Sep 20, 2018
    Posts:
    1

    -------------------------------------------------------
    I'm experiencing the same problem.
    Can I ask you a question?