0

I'm new to using Json and I cant figure out why data isn't deserializing. I tried many things and I don't know what the problem is. First I need to get data from this link https://jsonplaceholder.typicode.com/users and then i need to deserialize it. (Need to use REST request)

Whenever I wanna use any property it tells me its NULL "NullReferenceException: Object reference not set to an instance of an object"

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Net;
using System.IO;

public class Houses : MonoBehaviour
{
    public GameObject Prefab;

    void Update()
    {
        if (Input.GetKey(KeyCode.T))
        { 
            onClick();
        }
    }


    public void onClick()
    {

        UnityWebRequest request = UnityWebRequest.Get("https://jsonplaceholder.typicode.com/users");

        RootObject[] rootObjects = JsonUtility.FromJson<RootObject[]>(request.downloadHandler.text);




        //Debug.Log(request.downloadHandler.text);
        //foreach (var item in rootObjects)
        //{
        //    Debug.Log(item.id);
        //}



        //----------------------------------------------------------------------------------------
        //Latitude is the Y axis, longitude is the X axis

        //for (int i = 0; i < rootObjects.Length; i++)
        //{
        //    float x = float.Parse(rootObjects[i].address.geo.lng);
        //    float y = float.Parse(rootObjects[i].address.geo.lat);

        //    Instantiate(Prefab, new Vector3(x, y, 0f), Quaternion.identity);
        //}








    }



}

//public class ListItems
//{
//    //public RootObject[] rootObjects;

    //public List<RootObject> rootObjects;
//}
[System.Serializable]
public class Geo
{
    public string lat { get; set; }
    public string lng { get; set; }
}

[System.Serializable]
public class Address
{
    public string street { get; set; }
    public string suite { get; set; }
    public string city { get; set; }
    public string zipcode { get; set; }
    public Geo geo { get; set; }
}

[System.Serializable]
public class Company
{
    public string name { get; set; }
    public string catchPhrase { get; set; }
    public string bs { get; set; }
}

[System.Serializable]
public class RootObject
{
    public int id; //{ get; set; }
    public string name { get; set; }
    public string username { get; set; }
    public string email { get; set; }
    public Address address { get; set; }
    public string phone { get; set; }
    public string website { get; set; }
    public Company company { get; set; }
}

I would be really grateful if someone could help me out.

EDIT: So i made some changes. Turns out thanks to you guys i didnt give the UnityWebRequest time to get the data. Now im getting a different error "ArgumentException: JSON must represent an object type."

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Net;
using System.IO;

public class Houses : MonoBehaviour
{
    public GameObject Prefab;
    public string jsonURL;

    void Update()
    {
        if (Input.GetKeyUp(KeyCode.T))
        { 
            onClick();
        }
    }

    public void processJsonData(string _url)
    {
        RootObject[] rootObjects = JsonUtility.FromJson<RootObject[]>(_url);
        Debug.Log(rootObjects[0].id);
    }


    IEnumerator getData()
    {
        Debug.Log("Procesing data, please wait.");


        //WWW _www = new WWW(jsonURL);

        UnityWebRequest request = UnityWebRequest.Get("https://jsonplaceholder.typicode.com/users");

        yield return request.SendWebRequest();
        if (request.error == null)
        {
            processJsonData(request.downloadHandler.text);
        }
        else
        {
            Debug.Log("Oops something went wrong.");
        }
    }


    public void onClick()
    {



        //----------------------------------------------------------------------------------------
        //Latitude is the Y axis, longitude is the X axis

        //for (int i = 0; i < rootObjects.Length; i++)
        //{
        //    float x = float.Parse(rootObjects[i].address.geo.lng);
        //    float y = float.Parse(rootObjects[i].address.geo.lat);

        //    Instantiate(Prefab, new Vector3(x, y, 0f), Quaternion.identity);
        //}


        StartCoroutine(getData());
    }



}

//public class ListItems
//{
//    //public RootObject[] rootObjects;

    //public List<RootObject> rootObjects;
//}

[System.Serializable]
public class Geo
{
    public string lat;
    public string lng;
}

[System.Serializable]
public class Address
{
    public string street;
    public string suite;
    public string city;
    public string zipcode;
    public Geo geo;
}

[System.Serializable]
public class Company
{
    public string name;
    public string catchPhrase;
    public string bs;
}

[System.Serializable]
public class RootObject
{
    public int id;
    public string name;
    public string username;
    public string email;
    public Address address;
    public string phone;
    public string website;
    public Company company;
}```
Klemen
  • 11
  • 5
  • Can you try `JsonConvert.DeserializeObject(request.downloadHandler.text)` And while you debugging, what value u seeing in `request.downloadHandler.text`? – sri harsha Dec 30 '19 at 10:52
  • where did you send request? – Selvin Dec 30 '19 at 10:59
  • Sorry I didn't mention this, I need to use JsonUtility (Its an Assignment I need to do). But still Its not letting me use JsonConvert. – Klemen Dec 30 '19 at 10:59
  • I need to send a request to this link https://jsonplaceholder.typicode.com/users and get the info from it to use it. I don't even know if I used the UnityWebRequest correctly because I'm fairly new to this. – Klemen Dec 30 '19 at 11:04
  • @Selvin it will be assigned automatically when using [`UnityWebRequest.Get`](https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest.Get.html) it creates a new `UnityWebRequest` with all required components for a standard get request for downloading text. – derHugo Dec 30 '19 at 13:18
  • seems like you have right https://github.com/Unity-Technologies/UnityCsReference/blob/master/Modules/UnityWebRequest/Public/WebRequestExtensions.cs#L19 – Selvin Dec 30 '19 at 13:23
  • Could you add the output text you receive from the request? Probably it is malformed - at least for JsonUtility. Please checkout [Serialize and Deserialize Json and Json Array in Unity](https://stackoverflow.com/questions/36239705/serialize-and-deserialize-json-and-json-array-in-unity) – derHugo Dec 30 '19 at 13:35
  • @derHugo you mean what i get from `request.downloadHandler.text` i tried using `Debug.Log(request.downloadHandler.text);` this is what i get in the console "ArgumentException: JSON must represent an object type." – Klemen Dec 30 '19 at 13:37
  • @Klemen try to make the log before trying to parse it – derHugo Dec 30 '19 at 13:39
  • @derHugo What do you mean before I parse it – Klemen Dec 30 '19 at 13:49
  • @Klemen well the `ArgumentException` about a JSON is probably thrown in `JsonUtility.FromJson` .. so make sure the log is executed before this line – derHugo Dec 30 '19 at 14:28
  • @derHugo The `ArgumentException` happanes because I use the log to show me at least one ID from the `RootObject` – Klemen Dec 30 '19 at 14:39
  • Yes .. and what I meant is show us a log of the raw text you receive **before** parsing it from json to the `rootObject` ;) – derHugo Dec 30 '19 at 15:03
  • @derHugo well, now Im using the WWW insted of `UnityWebRequest` and I actually have gotten the full string from the link. Now the only problem is deserializing data with JsonUtility which is the main problem I needed help from the start – Klemen Dec 30 '19 at 17:15
  • @derHugo If I use `Debug.Log(_www.text);`, I get the whole string from this site https://jsonplaceholder.typicode.com/users. I cant post it in the comments since its a big string – Klemen Dec 30 '19 at 17:18
  • @derHugo You can see the the raw data I get on the link, if you click on "Raw Data" in the left upper corner – Klemen Dec 30 '19 at 17:24
  • @Klemen I checked out the link: What you get there is not a JSON object but an array of objects. (You see that since it starts with `[ ... ]`) Please follow the link I added as duplicate about deserializing arrays in Unity. There are multiple ways described of how to tackle this exact issue :) – derHugo Dec 30 '19 at 19:12
  • Yoi should anyway accept the answer below since it actually solved your first issue which originally was even receiving the json string at all. – derHugo Dec 30 '19 at 19:14

2 Answers2

3

Untiy's JsonUtility is a relatively performant but also extremely limited serializer. It only supports serializing fields, while the objects you are trying to deserialize are entirely made up of properties, which it does not support.

(By the way, that Unity's default serializer doesn't support properties, is also why they don't show up in the editor while fields do.)

Since it doesn't know how to set the property, it doesn't, and the property remains with its default valuel. In the case of refrence types (string, Address, etc.) the default value is NULL, which makes trying to access them throw an exception.

All you have to do to fix this in your case is change the classes you want to deserialize so that this:

    public class Geo
    {
        public string lat { get; set; }
        public string lng { get; set; }
    }

Becomes this:

    public class Geo
    {
        public string lat;
        public string lng;
    }

Do that for all your classes, and you should be golden.

EDIT: As Philip B. Mentioned in his answer, you are also not using UnityWebRequest.Get correctly.

UnityWebRequest doesnt resolve immediatly, and you must either yield return... to it from inside a Unity Coroutine, or wait for it to resolve with a blocking loop like so:

UnityWebRequest request = UnityWebRequest.Get("https://jsonplaceholder.typicode.com/users");

request.SendWebRequest();

while (!request.isDone) {}

Of course this is considered very bad form, as it freezes the game untill the data is downloaded. However, under the hood Unity handles the downloads on background threads, so you won't be blocking the download itself while you wait.

You should also query the request to see if any errors came up so you can handle them if you want to, as you might also be having issues with the download itself.

if (request.isHttpError || request.isNetworkError)
{
    //... handle errors here
}
else
{
    RootObject[] rootObjects = JsonUtility.FromJson<RootObject[]>(request.downloadHandler.text);
}

However, I'd really recommend you use coroutines here as described in Unity's UnityWebRequest.Get documentation. If you're new to Unity Coroutines please read up, it's a valuable tool for Unity development.

EDIT 2: Per this answer JsonUtility doesn't support serializing an array as a top level object, so you'll have to wrap your array in an object first, and deserialize that. You'll also have to make the top level object in the json file an object that holds that array.

[Serializable]
public class Routes
{
    public RootObject[] roots;
}

If you don't control the contents of the file, (and again this idea is coming from that excelent answer I linked to) you can do so with some string magic.

string jsonString = $@"{{""roots"":{request.downloadHandler.text}}}";
TJ Michael
  • 155
  • 9
  • 1
    So you are saying that I need to get rid of all the { get; set; }? I tried but i still get the same error. – Klemen Dec 30 '19 at 11:12
  • See my edit, Phillip B. is right about not using web request correctly. – TJ Michael Dec 30 '19 at 11:57
  • Thanks :). I edited my post, am getting a different error now – Klemen Dec 30 '19 at 12:49
  • 1
    @Klemen that is actually a new question since now it seems the text you now successfully downloaded is formatted in a form that Unity JsonUtility doesn't understand. Please checkout [Serialize and Deserialize Json and Json Array in Unity](https://stackoverflow.com/questions/36239705/serialize-and-deserialize-json-and-json-array-in-unity) – derHugo Dec 30 '19 at 13:32
  • Added another edit there, best of luck. – TJ Michael Dec 30 '19 at 13:56
0

You are trying to access request.downloader.text which is NULL (hence the "NullReferenceException: Object reference not set to an instance of an object") since you didn't send your GET request.

If you follow this link on how to use UnityWebRequest.Get you will see that you need more than just UnityWebRequest.Get("Your_Url"); to get your JSON string from the URL.

Try the following :

public void onClick() 
{ 
    using (UnityWebRequest request = UnityWebRequest.Get("https://jsonplaceholder.typicode.com/users"))
    {
        request.SendWebRequest();

        RootObject[] rootObjects = JsonUtility.FromJson<RootObject[]>(request.downloadHandler.text); 
    }
}

Hope this will help you.

Philippe B.
  • 485
  • 4
  • 18