Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialize Json an access the result

I have this Json:

{
   "UpdatePack":"updatePacks\/1585654836.pack",
   "Updates":[
      {
         "Name":"MsgBoxEx",
         "version":"1.5.14.88",
         "ChangeLog":"BugFix: Form didn't resize correct.",
         "Hash":"5FB23ED83693A6D3147A0485CD13288315F77D3D37AAC0697E70B8F8C9AA0BB8"

},
      {
         "Name":"Utilities",
         "version":"2.5.1.58",
         "ChangeLog":"StringManagement updated.",
         "Hash":"05E6B3F521225C604662916F50A701E9783E13776DE4FCA27BE4B69705491AC5"

}

]
}

I have created 2 classes to be used to Deserialize it.

class UpdatesList
{
    public string Name { get; set; }
    public string Version { get; set; }
    public string ChangeLog { get; set; }
    public string Hash { get; set; }
}
class JsonObjectHolder
{
    public string UpdatePack { get; set; }
    //public Dictionary<int, MyData> { get; set; }
    public Dictionary<int, UpdatesList> Updates { get; set; }
}

But when I try to access the dictionary, I keep getting Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at " Console.WriteLine(jsonTest.Dict.Count);"

Am I Deserializing it wrong, or do I need to do some thing else to access the result of the dictionary?

I'm new to both C# and Json.

I hope that some one could point me in the right direction on how to handle this.

I'm using Visual Studio 2019 latest update, and .net 4.8. Regards /LR

like image 743
LupusRex Avatar asked Mar 31 '20 09:03

LupusRex


People also ask

What does it mean to deserialize a JSON?

JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation (convert string -> object).

How does Newtonsoft JSON deserialize work?

Newtonsoft. Json uses reflection to get constructor parameters and then tries to find closest match by name of these constructor parameters to object's properties. It also checks type of property and parameters to match. If there is no match found, then default value will be passed to this parameterized constructor.

How do I deserialize JSON in Apex?

deserialize() , you must specify the type of value you expect the JSON to yield, and Apex will attempt to deserialize to that type. JSON. serialize() accepts both Apex collections and objects, in any combination that's convertible to legal JSON. String jsonString = JSON.


Video Answer


3 Answers

You code doesn't work because 0 and 1 tokens just a properties, not the array items (you don't have square brackets [] around them). You can parse these values to desired structure manually using JObject

var json = JObject.Parse(your_json_string);
var dict = new Dictionary<int, UpdatesList>();
foreach (var item in json.Properties())
{
    if (item.Value.Type == JTokenType.Object)
    {
        var index = int.Parse(item.Name);
        var updateList = item.Value.ToObject<UpdatesList>();
        dict.Add(index, updateList);
    }
}

var holder = new JsonObjectHolder
{
    UpdatePack = json["Updates"]?.Value<string>(),
    Dict = dict
};

Update: According to OP changes made to JSON it might be deserialized even more simply

var list = json["Updates"]?.ToObject<List<UpdatesList>>();

var holder = new JsonObjectHolder
{
    UpdatePack = json["UpdatePack"]?.Value<string>(),
    Dict = list.Select((updatesList, index) => new { updatesList, index })
                    .ToDictionary(x => x.index, x => x.updatesList)
};

The main point here is that Updates is an array of items, not the key-value collection. It can be transformed into Dictionary<int, UpdatesList> using ToDictionary method from System.Linq (or just use List<UpdatesList> as is)

like image 109
Pavel Anikhouski Avatar answered Sep 24 '22 14:09

Pavel Anikhouski


The exception you're getting essentially means the value is being accessed before the object is initialized.

A better, simpler and cleaner way to doing it is using NewtonSoft. (you can easily get it as a Nuget package)

example:

public class Account
{
    public string Email { get; set; }
    public bool Active { get; set; }
    public DateTime CreatedDate { get; set; }
    public IList<string> Roles { get; set; }
}

and then usage:

string json = @"{
  'Email': '[email protected]',
  'Active': true,
  'CreatedDate': '2013-01-20T00:00:00Z',
  'Roles': [
    'User',
    'Admin'
  ]
}";

Account account = JsonConvert.DeserializeObject<Account>(json);

Console.WriteLine(account.Email);

Source: https://www.newtonsoft.com/json/help/html/DeserializeObject.htm

like image 25
Atharva Avatar answered Sep 22 '22 14:09

Atharva


I don't see why you need Dictionary<int, UpdatesList> Updates, when you can easily just use List<Update> Updates, since your updates are in a JSON array.

I would model your classes like this:

public class Update
{
    public string Name { get; set; }
    public string Version { get; set; }
    public string ChangeLog { get; set; }
    public string Hash { get; set; }
}

public class RootObject
{
    public string UpdatePack { get; set; }
    public List<Update> Updates { get; set; }
}

You can then deserialize with:

 JsonConvert.DeserializeObject<RootObject>(json);

Try it out on dotnetfiddle.net

Note: To convert JSON to C# classes, you can go to Edit -> Paste Special -> Paste JSON as Classes inside Visual Studio. Make sure you have copied the JSON to your clipboard before using it. You will get classes similar to above.

like image 36
RoadRunner Avatar answered Sep 21 '22 14:09

RoadRunner