3

I've been building an English language game using the unity engine. I am struggling to get C# to parse JSON.

I've been trying to get JSON to parse for the last few days, unsuccessfully. I've validated the JSON, can debug the jsonString to the console but as soon as jsonUtility gets its hand on the json then I end up with a load of NULL data.

Here is my json:

 {"question": {"questionType": "0", "categoryID": "0", "bonusBool": "FALSE", "answerText": "cake", "questionText": "If something is really easy to do, it\u2019s a piece of \u2026\u2026\u2026 \\n a. pie \\n b. tart \\n c. cake", "ID": "0"}}

Here is my C#:

 [System.Serializable]
 public class QuestionDataAsString
 {

     public string questionText;
     public string answerText;
     public string categoryID;
     public string ID;
     public string questionType;
     public string bonusBool;

 }

 [System.Serializable]
 public class Question{

     public string questionText;
     public string answerText;
     public int categoryID;
     public int ID;
     public int questionType;
     public bool bonusBool;

 }

 public static void LoadQuestion()
     {
         string filePath = Path.Combine(Application.streamingAssetsPath, "questionData.json");
         string dataAsJSON = File.ReadAllText(filePath);
         Debug.Log(dataAsJSON);
         QuestionDataAsString question = JsonUtility.FromJson<QuestionDataAsString>(dataAsJSON);
         Debug.Log(question.questionText);
     }

 public static Question ConvertQuestionDataFromString(QuestionDataAsString stringData)
     {
         Question question = new Question();
         question.questionText = stringData.questionText;
         question.answerText = stringData.answerText;
         question.categoryID = int.Parse(stringData.categoryID);
         question.ID = int.Parse(stringData.ID);
         question.questionType = int.Parse(stringData.questionType);
         question.bonusBool = Boolean.Parse(stringData.bonusBool);
         return question;
     }

When I run LoadQuestion through a splashscreen controller, I can log the json to console as a string. But I get Null objects once I use jsonUtility.

This is the console output:

 {"question": {"questionType": "0", "categoryID": "0", "bonusBool": "FALSE", "answerText": "cake", "questionText": "If something is really easy to do, it\u2019s a piece of \u2026\u2026\u2026 \\n a. pie \\n b. tart \\n c. cake", "ID": "0"}}
 UnityEngine.Debug:Log(Object)
 SaveLoadManager:LoadQuestion() (at Assets/Scripts/SaveLoadManager.cs:91)
 <Start>c__Iterator0:MoveNext() (at Assets/Scripts/SplashController.cs:18)
 UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

 Null
 UnityEngine.Debug:Log(Object)
 SaveLoadManager:LoadQuestion() (at Assets/Scripts/SaveLoadManager.cs:93)
 <Start>c__Iterator0:MoveNext() (at Assets/Scripts/SplashController.cs:18)
 UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

I've searched through the answers here and on unity answers, but have not found any relevant solutions.

Any ideas why fromJson is returning Null for everything?

Era
  • 141
  • 1
  • 4
  • 13
  • 1
    Your JSON doesn't match your C# class structure. – DavidG Sep 25 '17 at 15:10
  • Good luck using that JSON Class, being that unity does not Deseralize JSON Below 7 Nested Levels – johnny 5 Sep 25 '17 at 15:24
  • 1
    @johnny5 What's the problem? This is only 2 levels. – DavidG Sep 25 '17 at 15:25
  • @DavidG nothing wrong with the current problem, I just mean Good luck using the JSON Deserializer Class because it doesn't serialize beyond 7 levels. Nobody told me this until I already wrote a project dependent on it, afterwards I had to support it, I think Newtsoft JSON, has a portable version which works with unity – johnny 5 Sep 25 '17 at 15:31
  • @DavidG You are right and your solution works great – Era Sep 26 '17 at 15:32
  • You should check this link, it will generate a c# class for you. http://json2csharp.com/ – ZackOfAllTrades Dec 06 '17 at 18:10

1 Answers1

6

Your JSON doesn't match your C# class structure. You need a root level object to hold the question details. Also, you should use properties, not fields. For example:

public class QuestionRoot
{
    public Question Question { get; set; }
}

public class Question
{
    public string questionType { get; set; }
    public string categoryID { get; set; }
    public string bonusBool { get; set; }
    public string answerText { get; set; }
    public string questionText { get; set; }
    public string ID { get; set; }
}

Now you can do this:

var questionRoot = JsonUtility.FromJson<QuestionRoot>(dataAsJSON);
var questionText = questionRoot.question.questionText;

Side note: You should consider following C# common practice for your naming. Properties almost always start with a capital letter:

public string QuestionText { get; set; }
DavidG
  • 95,392
  • 10
  • 185
  • 181
  • 4
    This might not work in Unity since the engine does not handle properties as well as it should. But the part about the root object is valid. – Viktor Seifert Sep 25 '17 at 15:25
  • @ViktorSeifert Hm that's an interesting point (I'm not a Unity user!) – DavidG Sep 25 '17 at 15:26
  • Thank you, I'll try this solution tomorrow! I'm coming from python, this is my first C# project so I don't know all the conventions yet. As Viktor mentioned, I have read many issues with Unity and properties. If you have a spare minute, unity specific issues aside, could you explain the advantage of using properties over fields? – Era Sep 25 '17 at 21:59
  • 4
    a note on unity - I had a problem which led me here, reverting all my properties to just fields caused the object to load correctly. – Rawrgramming Feb 19 '19 at 15:21
  • Can confirm, changing it back to fields in Unity fixed it for me, and the 'Serializable' attribute Unity recommends is not needed. – Greg Quinn Apr 18 '21 at 22:44