Deserializing multiple Object Lists from a Json file

Connor Frayne 20 Reputation points
2024-08-07T17:49:05.51+00:00

Hello,
I've encountered an issue that I am stuck on. So I'm attempting to deserialize 2 object lists from a Json File, the first one comes out fine but on creating a new object in the list for the second object list, a full null object is sent through the new constructor of the object. I could handle it but I don't know the break statement equivalent for a constructor. There's a lot of parts to my code so I'll only send the most important parts, if you need more please ask.

Thank you,

Connor Frayne

Below is the Json file and code.

Public Class Form1
    Public Profiles As ProfilesList
    Public FIDs As FIDsList

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim JsonPath As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "SafeBox Config", "SBGUIElements.json")
        Try
            Dim jsonFromFile As String = System.IO.File.ReadAllText(JsonPath)
            Profiles = JsonConvert.DeserializeObject(Of ProfilesList)(jsonFromFile)
             
			jsonFromFile = System.IO.File.ReadAllText(JsonPath)
			FIDs = JsonConvert.DeserializeObject(Of FIDsList)(jsonFromFile)             
        Catch ex As Exception             
			Trace.WriteLine(ex.ToString)
		End Try 
'a Few other things
end sub
end class

Public Class FIDsList
    Public Property FIDs As List(Of FID)
End Class
Public Class ProfilesList
    Public Property Profiles As List(Of Profile)
End Class

Public Class Profile
    Public Property MasterNum As Integer
    Public Property Name As String
    <[JsonIgnore]> Public Property State As String
        Get
            Return _State
        End Get
        Set(ByVal value As String)
            If Not value Is State Then
                _State = value
            End If
        End Set
    End Property
    Private _State As String
    Public Property Location As String
    Public Property ProfInfo As String
    <[JsonIgnore]> Public Property FaultInfo As String
    <[JsonIgnore]> Public chk_chkbox As New CheckBox
    <[JsonIgnore]> Public InProfFIDHandler As EventHandler
    Public Sub New(ByVal new_MasterNum As Integer, ByVal new_Name As String, ByVal new_State As String,
        ByVal new_Location As String, ByVal new_ProfInfo As String, ByVal new_FaultInfo As String)
        MasterNum = new_MasterNum
        Name = new_Name
        State = new_State
        Location = new_Location
        ProfInfo = new_ProfInfo
        FaultInfo = new_FaultInfo
    End Sub
end class

Public Class FID
    Public Property Master As Profile
    Public Property FIDNum As Integer
    Public Property Name As String
    <[JsonIgnore]> Public Property State As String
        Get
            Return _State
        End Get
        Set(value As String)
            _State = value
            ‘FIDStateChanged()
        End Set
    End Property
    Private _State As String
    Public Property Location As String
    <[JsonIgnore]> Public InFIDHandler As EventHandler
    <[JsonIgnore]> Public Pic_FID As PictureBox
    Public Sub New(ByRef new_Master As Profile, ByVal new_FIDNum As Integer, ByVal new_Name As String,
        ByVal new_State As String, ByVal new_Location As String)
        Master = new_Master
        FIDNum = new_FIDNum
        Name = new_Name
        State = new_State
        Location = new_Location
        ‘AddHandler Pic_FID.Click, AddressOf FID_Click
    End Sub
‘Some other things
End class
{
  "Profiles": [
    {
      "MasterNum": 1,
      "Name": "Master1",
      "Location": "Floor - 1",
      "ProfInfo": "Master for FID 1, 2, 3, 6."
    },
    {
      "MasterNum": 2,
      "Name": "Master2",
      "Location": "Floor - 2",
      "ProfInfo": "Master for FID 4, 5."
    },
    {
      "MasterNum": 3,
      "Name": "MMMMMMMMMMMMMMM",
      "Location": "Floor - 1",
      "ProfInfo": "Master for FID 7"
    },
    {
      "MasterNum": 4,
      "Name": "Master4",
      "Location": "Floor - 2",
      "ProfInfo": "Master for FID 8"
    },
    {
      "MasterNum": 5,
      "Name": "Master5",
      "Location": "Floor - 1",
      "ProfInfo": "Master for FID 9"
    },
    {
      "MasterNum": 6,
      "Name": "Master6",
      "Location": "Floor - 2",
      "ProfInfo": "Master for FID 10, 11, 12"
    }
  ],
  "FIDs": [
    {
      "Master": {
        "MasterNum": 1,
        "Name": "Master1",
        "Location": "Floor - 1",
        "ProfInfo": "Master for FID 1, 2, 3, 6."
      },
      "FIDNum": 1,
      "Name": "FID1",
      "Location": "Floor - 1"
    },
    {
      "Master": {
        "MasterNum": 1,
        "Name": "Master1",
        "Location": "Floor - 1",
        "ProfInfo": "Master for FID 1, 2, 3, 6."
      },
      "FIDNum": 2,
      "Name": "FID2",
      "Location": "Floor - 1"
    },
    {
      "Master": {
        "MasterNum": 1,
        "Name": "Master1",
        "Location": "Floor - 1",
        "ProfInfo": "Master for FID 1, 2, 3, 6."
      },
      "FIDNum": 3,
      "Name": "FID3",
      "Location": "Floor - 1"
    },
    {
      "Master": {
        "MasterNum": 2,
        "Name": "Master2",
        "Location": "Floor - 2",
        "ProfInfo": "Master for FID 4, 5."
      },
      "FIDNum": 4,
      "Name": "FID4",
      "Location": "Floor - 2"
    },
    {
      "Master": {
        "MasterNum": 2,
        "Name": "Master2",
        "Location": "Floor - 2",
        "ProfInfo": "Master for FID 4, 5."
      },
      "FIDNum": 5,
      "Name": "FID5",
      "Location": "Floor - 2"
    },
    {
      "Master": {
        "MasterNum": 1,
        "Name": "Master1",
        "Location": "Floor - 1",
        "ProfInfo": "Master for FID 1, 2, 3, 6."
      },
      "FIDNum": 6,
      "Name": "FID6",
      "Location": "Floor - 2"
    },
    {
      "Master": {
        "MasterNum": 3,
        "Name": "MMMMMMMMMMMMMMM",
        "Location": "Floor - 1",
        "ProfInfo": "Master for FID 7"
      },
      "FIDNum": 7,
      "Name": "FID7",
      "Location": "Floor - 1"
    },
    {
      "Master": {
        "MasterNum": 4,
        "Name": "Master4",
        "Location": "Floor - 2",
        "ProfInfo": "Master for FID 8"
      },
      "FIDNum": 8,
      "Name": "FID8",
      "Location": "Floor - 2"
    },
    {
      "Master": {
        "MasterNum": 5,
        "Name": "Master5",
        "Location": "Floor - 1",
        "ProfInfo": "Master for FID 9"
      },
      "FIDNum": 9,
      "Name": "FID9",
      "Location": "Floor - 1"
    },
    {
      "Master": {
        "MasterNum": 6,
        "Name": "Master6",
        "Location": "Floor - 2",
        "ProfInfo": "Master for FID 10, 11, 12"
      },
      "FIDNum": 10,
      "Name": "FID10",
      "Location": "Floor - 2"
    },
    {
      "Master": {
        "MasterNum": 6,
        "Name": "Master6",
        "Location": "Floor - 2",
        "ProfInfo": "Master for FID 10, 11, 12"
      },
      "FIDNum": 11,
      "Name": "FID11",
      "Location": "Floor - 2"
    },
    {
      "Master": {
        "MasterNum": 6,
        "Name": "Master6",
        "Location": "Floor - 2",
        "ProfInfo": "Master for FID 10, 11, 12"
      },
      "FIDNum": 12,
      "Name": "FID12",
      "Location": "Floor - 2"
    }
  ]
} 
.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,808 questions
Visual Studio
Visual Studio
A family of Microsoft suites of integrated development tools for building applications for Windows, the web and mobile devices.
5,059 questions
VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,715 questions
Visual Studio Extensions
Visual Studio Extensions
Visual Studio: A family of Microsoft suites of integrated development tools for building applications for Windows, the web and mobile devices.Extensions: A program or program module that adds functionality to or extends the effectiveness of a program.
212 questions
{count} votes

Accepted answer
  1. Michael Taylor 53,971 Reputation points
    2024-08-07T19:15:05.0033333+00:00

    JSON deserialization only use default constructors. Any constructors you define on a type will not be used, by design. In general JSON is being used to transfer data so it is a DTO with no logic, including complex constructors. Your business classes should take the DTO data and build out an instance that the app needs. Problems generally arise when you fail to follow this process. For very simple cases you can use a DTO as your business object but you have to understand that to JSON it is just raw data points.

    Therefore, problem 1 is that your constructor(s) won't get called. That's the way it works and you should not rely on that behavior. If you need that behavior then you need to create wrapper business types that are set from the JSON data you get back.

    Problem 2, to me, is that you're wasting time reading the JSON twice. If you don't need the logically grouped data then create a dummy type that contains just the JSON elements you want to read and then deserialize to that type. Then grab the subset of data you care about.

    Public Class Data
        Public Property FIDs As List(Of FID)
    
        Public Property Profiles As List(Of Profile)
    End Class
    
    Function LoadData(filename As String) As Data
    
        Dim json = System.IO.File.ReadAllText(filename)
        Dim data = JsonConvert.DeserializeObject(Of Data)(json)
    
        Return data
    End Function
    

    Now you have access to both sets of objects and can process them however you want. With the above code I'm able to read in your entire JSON file with all the content set properly.

    Problem 3, I suspect, is that you have a hierarchy here that isn't correctly represented in the JSON. Your FID type contains a Profile object. Yet profile data is also stored as separate objects. Just given your JSON file there appears to be no reason to actually load the Profile array because your FID objects have the corresponding Profile data already captured. If a Profile can be associated with only 1 FID then separating them out isn't useful. If Profile and FID are distinct and a FID can be associated with a Profile then ideally the only thing that should be stored in the FID JSON data is a reference to the Profile ID and the post-serialization code can fix this up (yet another reason why you shouldn't combine DTO and business types).

    In general JSON has no support for objects referencing each other so FID Profile 1 and Profile 1 may be the same to your app but they are 2 different Profile objects to JSON and ultimately your code. If you need to have these be the same object then, again, your business layer should handle that. Technically you can do some "reference tracking" in some JSON parsers but this is generally not recommended and probably doesn't work right. Simply storing the Profile ID in the FID object would be sufficient.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 64,486 Reputation points
    2024-08-07T18:03:55.98+00:00

    your json classes should have a parameters constructor added:

    Public Sub New()
    End Sub
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.