1

I'm trying to assign a Default value to my class, when I don't have the property listed in the JSON.

This is the class I'm using to deserialize JSON

Public Class cls_horarios

   
    Public Class Expediente

        Public Property expediente_opcao_domingo As ExpedienteOpcaoDomingo
        Public Property expediente_opcao_segunda As ExpedienteOpcaoSegunda
        Public Property expediente_opcao_terca As ExpedienteOpcaoTerca
        Public Property expediente_opcao_quarta As ExpedienteOpcaoQuarta
        Public Property expediente_opcao_quinta As ExpedienteOpcaoQuinta
        Public Property expediente_opcao_sexta As ExpedienteOpcaoSexta
        Public Property expediente_opcao_sabado As ExpedienteOpcaoSabado
        Public Property expediente_feriados As String
        Public Property expediente_bloqueio_pc As String
        Public Property expediente_bloqueio_tolerancia As String
    End Class

    Public Class ExpedienteOpcaoDomingo
        Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class

    Public Class ExpedienteOpcaoQuarta
     Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class

    Public Class ExpedienteOpcaoQuinta
        Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class

    Public Class ExpedienteOpcaoSegunda
        Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class

    Public Class ExpedienteOpcaoSexta
        Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class

    Public Class ExpedienteOpcaoTerca
        Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class
   
    Public Class Result
        Public Property expediente As List(Of Expediente)
    End Class

    Public Class Root
        Public Property result As Result
    End Class

This is the JSON I am trying to deserialize:

{
  "result": {
    "expediente": [{
      "expediente_opcao_domingo": {
        "isDiaUtil": 0,
        "hora_inicial": null,
        "hora_final": null
      },
      "expediente_opcao_segunda": {
        "isDiaUtil": 1,
        "hora_inicial": "09:00",
        "hora_final": "18:48"
      },
      "expediente_opcao_terca": {
        "isDiaUtil": 1,
        "hora_inicial": "09:00",
        "hora_final": "18:48"
      },
      "expediente_opcao_quarta":
      {
        "isDiaUtil": 1,
        "hora_inicial": "09:00",
        "hora_final": "18:48"
      },
      "expediente_opcao_sexta": {
        "isDiaUtil": 1,
        "hora_inicial": "09:00",
        "hora_final": "18:48"
      },
      "expediente_opcao_sabado": {
        "isDiaUtil": 0,
        "hora_inicial": null,
        "hora_final": null
      },
      "expediente_nome": "padr\u00e3o",
      "expediente_feriados": "0",
      "expediente_bloqueio_pc": 0,
      "expediente_bloqueio_tolerancia": "0"
    }],
     }
}

In this scenario, what I'm trying to do is assign a default value so that it doesn't have the properties in the JSON, the default value is set, so that it can be tested, just remove the line that is identified in the JSON

and this is the code I'm using to read the JSON

Public Sub PreencheConfiguracoesColaborador(ByVal dados As String)

        '//INICIO EXPEDIENTE DO COLABORADOR


        Dim horarioColab As cls_horarios.Root = JsonConvert.DeserializeObject(Of cls_horarios.Root)(dados)
        expediente_colab_quantidade = 0

        
        Try
            For Each item As Expediente In horarioColab.result.expediente

                expediente_colab_feriado = item.expediente_feriados
                expediente_colab_bloqueio_pc = item.expediente_bloqueio_pc
                expediente_colab_bloqueio_tolerancia = item.expediente_bloqueio_tolerancia

                expediente_colab_domingo = item.expediente_opcao_domingo.isDiaUtil
                expediente_colab_domingo_hora_entrada = FormatDateTime(item.expediente_opcao_domingo.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_domingo_hora_saida = FormatDateTime(item.expediente_opcao_domingo.hora_final.ToString, DateFormat.LongTime)

                expediente_colab_segunda = item.expediente_opcao_segunda.isDiaUtil
                expediente_colab_segunda_hora_entrada = FormatDateTime(item.expediente_opcao_segunda.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_segunda_hora_saida = FormatDateTime(item.expediente_opcao_segunda.hora_final.ToString, DateFormat.LongTime)

                expediente_colab_terca = item.expediente_opcao_terca.isDiaUtil
                expediente_colab_terca_hora_entrada = FormatDateTime(item.expediente_opcao_terca.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_terca_hora_saida = FormatDateTime(item.expediente_opcao_terca.hora_final.ToString, DateFormat.LongTime)


                expediente_colab_quarta = item.expediente_opcao_quarta.isDiaUtil
                expediente_colab_quarta_hora_entrada = FormatDateTime(item.expediente_opcao_quarta.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_quarta_hora_saida = FormatDateTime(item.expediente_opcao_quarta.hora_final.ToString, DateFormat.LongTime)

                expediente_colab_quinta = item.expediente_opcao_quinta.isDiaUtil
                expediente_colab_quinta_hora_entrada = FormatDateTime(item.expediente_opcao_quinta.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_quinta_hora_saida = FormatDateTime(item.expediente_opcao_quinta.hora_final.ToString, DateFormat.LongTime)

                expediente_colab_sexta = item.expediente_opcao_sexta.isDiaUtil
                expediente_colab_sexta_hora_entrada = FormatDateTime(item.expediente_opcao_sexta.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_sexta_hora_saida = FormatDateTime(item.expediente_opcao_sexta.hora_final.ToString, DateFormat.LongTime)

                expediente_colab_sabado = item.expediente_opcao_sabado.isDiaUtil
                expediente_colab_sabado_hora_entrada = FormatDateTime(item.expediente_opcao_sabado.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_sabado_hora_saida = FormatDateTime(item.expediente_opcao_sabado.hora_final.ToString, DateFormat.LongTime)


                'expediente_colab_expediente_nome = item.expediente_nome
                expediente_colab_quantidade += 1
                Console.WriteLine("Feriado: " & expediente_colab_feriado & " Bloqueio Pc: " & expediente_colab_bloqueio_pc & " Bloqueio Tolerancia: " & expediente_colab_bloqueio_tolerancia & " Expediente Nome: " & expediente_colab_expediente_nome)

            Next

        Catch ex As Exception
            writeExeption(ex, False)
            Console.WriteLine("Erro Expediente: " & ex.Message)
        End Try

    End Sub

I have already tried the following proposed solutions right here on SO:

Default value for missing properties with JSON.net

Why when I deserialize with JSON.NET ignores my default value?

But all without success.

What I need is to set the default value when the JSON properties are missing, so I ask for everyone's help to resolve this issue.

dbc
  • 104,963
  • 20
  • 228
  • 340
Luiz
  • 13
  • 4
  • Might you please [edit] your question and try to simplify it a little bit -- i.e. share a [mcve]? As it is you have a lot of code but it isn't exactly clear where you are struggling. – dbc Jul 27 '23 at 17:38
  • Also, you wrote that you tried the answers from [Default value for missing properties with JSON.net](https://stackoverflow.com/q/29611445/3744182) without success. Might you please [edit] your question to demonstrate? I believe that adding e.g. ` Public Property isDiaUtil As Integer` should give `isDiaUtil` a default value of `1` when deserializing. – dbc Jul 27 '23 at 17:40
  • Finally, why not just assign your default values in your class constructors? Do you want the default values set only when deserializing, and not when constructing in memory? – dbc Jul 27 '23 at 17:42
  • @dbc, I tried to put my entire code to help in the demonstration, because my class has several properties, and I believe that if I get the solution I need, it will be easy to apply it to the rest. – Luiz Jul 27 '23 at 18:12
  • @dbc this solution, Public Property isDiaUtil As Integer, doesn't give me the default value, it gives me a System.NullReferenceException: 'Object reference not set to an instance of an object.' qtservices.cls_horarios.Expediente.expediente_opcao_quinta.get returned Nothing since there is no property expediente_opcao_quinta in my Json, I can't set the Default value – Luiz Jul 27 '23 at 18:16
  • @dbc how can i assign default values directly in my class constructors? could you give me an example of how to do it? – Luiz Jul 27 '23 at 18:18
  • See e.g. [this answer](https://stackoverflow.com/a/45826590) by ShieldOfSalvation to [How to implement class constructor in Visual Basic?](https://stackoverflow.com/q/3279106). Do `Public Sub New() isDiaUtil = 1 End Sub` (with proper indenting of course). – dbc Jul 27 '23 at 18:20
  • @dbc I just made your example and unfortunately it didn't work, it still returns as Nothing.... the System.NullReferenceException is coming from this call "Public Property expediente_opcao_quinta As ExpedienteOpcaoQuinta" – Luiz Jul 27 '23 at 18:48
  • @dbc I will try to reduce the code of both the class and the one that reads the JSON – Luiz Jul 27 '23 at 18:49
  • @dbc I just edited my question by reducing my codes, please see if this makes it better to understand – Luiz Jul 27 '23 at 18:57
  • I tried copying your code into a https://dotnetfiddle.net/ fiddle, and I got lots of compilation errors, see https://dotnetfiddle.net/LUEJkq. If you could please [edit] your question to share a **compilable** [mcve] as suggested in [ask], it's much more likely that we can help. – dbc Jul 27 '23 at 19:01
  • I don't see any C# in this question. Are you willing to see C#-only answers to it? That would be the only other reason to include that tag on the question. If you are not, please [edit] your question and remove the tag. – Heretic Monkey Jul 27 '23 at 19:04
  • OK, I simplified your code and attempted to deserialize the JSON `{}` to `ExpedienteOpcaoDomingo`. As shown in [this answer](https://stackoverflow.com/a/29611577/3744182) by somdoron to [Default value for missing properties with JSON.net](https://stackoverflow.com/q/29611445/3744182), you must add both `` and `` to `isDiaUtil` to make Json.NET set the default value automatically, see https://dotnetfiddle.net/M7yvXg. Does that answer your question? – dbc Jul 27 '23 at 19:15
  • Or as mentioned, you could set the default values in the constructor as shown in [How to implement class constructor in Visual Basic?](https://stackoverflow.com/q/3279106/3744182), see https://dotnetfiddle.net/WkoNp8. Does that answer your question? – dbc Jul 27 '23 at 19:20
  • @dbc I edited the code https://dotnetfiddle.net/GA20Ag and now it doesn't show the errors anymore, if you want to take a look – Luiz Jul 27 '23 at 19:37
  • In your fiddle you have a Try/Catch that ignores all errors. You shouldn't do that, it's bad practice. If I remove it, it's clear you have a null reference exception, https://dotnetfiddle.net/HmcxBP. A bit of debugging shows it's the `dim expediente_colab_domingo_hora_entrada = item.expediente_opcao_domingo.hora_inicial.ToString` line, see https://dotnetfiddle.net/TCRWH8. Specifically `hora_inicial` is null. And that's because, in the JSON, the value is actually null: `"hora_inicial": null,` Setting a default value won't prevent a null reference exception when the JSON has a null value. – dbc Jul 27 '23 at 19:49
  • So what do you want to do when the JSON explicitly contains a null value? – dbc Jul 27 '23 at 19:50
  • @dbc As for the null value that is in the JSON, this has already been dealt with, my biggest issue is with the properties that are not in the JSON and count in my class, which I end up receiving the System.NullReferenceException – Luiz Jul 27 '23 at 19:56
  • @dbc I put together a new example with the class I use and it includes your suggestion for the default values, https://dotnetfiddle.net/iJdKwB but it still has an error, but the null values have already been resolved – Luiz Jul 27 '23 at 20:03
  • The remaining null reference is caused by the fact that the property `"expediente_opcao_quarta"` is missing from the JSON. – dbc Jul 27 '23 at 20:06
  • @dbc that's right..... what I need is to add a default value when the property is missing in the JSON...... – Luiz Jul 27 '23 at 20:09

1 Answers1

0

You have a few problems here:

  1. There is no value for the property "expediente_opcao_quinta" in the JSON, thus Expediente.expediente_opcao_quinta is null.

  2. There are several string whose values in the JSON is explicitly null, e.g. "result[0].expediente.expediente_opcao_sabado".

  3. There are also missing string-valued properties whose values default to null.

The easiest way to resolve these problems is to automatically initialize your properties to non-null values when constructed as shown in Initializing an Auto-Implemented Property, and apply <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> to any property that should never be null to force Json.NET to ignore null values when deserializing and serializing.

Thus your data model should look like:

Public Class Expediente
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_domingo As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_segunda As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_terca As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_quarta As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_quinta As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_sexta As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_sabado As ExpedienteOpcao = New ExpedienteOpcao()

    Public Property expediente_feriados As String
    Public Property expediente_bloqueio_pc As String
    Public Property expediente_bloqueio_tolerancia As String
End Class

Public Class ExpedienteOpcao
    Public Property isDiaUtil As Integer
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property hora_inicial As String = ""
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property hora_final As String = ""
End Class

Public Class Result
    Public Property expediente As List(Of Expediente)
End Class

Public Class Root
    Public Property result As Result
End Class

Notes:

  • You have a seven of identical classes with names like ExpedienteOpcaoDomingo and ExpedienteOpcaoQuarta that seem to correspond to days of the week. I am guessing you created these classes with some code generation tool. Code generation tools will sometimes fail to detect and combine identical types, but since in this case it seems they should be identical, I made them such in my answer.

  • In your question you catch and ignore all exceptions. This is generally a bad idea as you lose all information about the cause of the problem, and your code may proceed forward using corrupt data. See e.g. Is catching general exceptions really a bad thing? for some additional discussion.

  • While you could use the answers from Default value for missing properties with JSON.net to use DefaultValueAttribute to provide default values for missing properties with primitive values, you cannot use DefaultValueAttribute to provide a default value for a complex property value such as ExpedienteOpcao due to limitations on attribute parameter types built into the CLR.

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • Thank you very much for your help, it worked perfectly...... As for generating the code, yes it was done by an automatic class generator.... I will try to improve my coding..... once again, thank you very much for your help help..... – Luiz Jul 27 '23 at 20:33