Deserialize JSON which can have different objects under same property name

偶尔善良 提交于 2021-02-09 11:05:56

问题


I'm using JSON.NET to deserialize JSON responses from HTTP queries, but I'm stuck with an issue. That's because the response can send two types of object under same property, as shown below:

1st case sample (most common):

{
  "type": "myType",
  "tid": 4,
  "action": "myAction",
  "method": "myMethod",
  "result": {
    "success": true,
    "total": 4,
    "records": [
      {
        "id": 4,
        "nome": "PRIMEIRO NOME",
        "sigla": "PN"
      },
      {
        "id": 1974,
        "nome": "SEGUNDO NOME",
        "sigla": "SN"
      },
      {
        "id": 2584,
        "nome": "TERCEIRO NOME",
        "sigla": "TN"
      },
      {
        "id": 1170,
        "nome": "QUARTO NOME",
        "sigla": "QN"
      }
    ]
  }
}

2nd case sample (rare):

{
  "type": "myType",
  "tid": 3,
  "action": "myAction",
  "method": "myMethod",
  "result": [
    {
      "id": 4,
      "nome": "PRIMEIRO NOME",
      "sigla": "PN"
    },
    {
      "id": 1974,
      "nome": "SEGUNDO NOME",
      "sigla": "SN"
    },
    {
      "id": 2584,
      "nome": "TERCEIRO NOME",
      "sigla": "TN"
    },
    {
      "id": 1170,
      "nome": "QUARTO NOME",
      "sigla": "QN"
    }
  ]
}

I've been using these classes to receive data for the 1st case:

Public Class Record
    Public Property id As Integer
    Public Property nome As String
    Public Property sigla As String
End Class

Public Class Result
    Public Property success As Boolean
    Public Property total As Integer
    Public Property records As Record()
End Class

Public Class Response
    Public Property type As String
    Public Property tid As Integer
    Public Property action As String
    Public Property method As String
    Public Property result As Result
End Class

So it worked well upon deserialization of 1st case JSON, with this statement:

Dim myResponse = JsonConvert.DeserializeObject(Of Response)(myJsonString)

However, when receiving 2nd case JSON, it creates object of type Response, stores in its property result an object of type Result whose properties remain empty, and the data which I needed to retrieve vanishes for it is stored nowhere.

I thought that I should modify the class Response so it has place for that different set of data, this way:

Public Class Response
    Public Property type As String
    Public Property tid As Integer
    Public Property action As String
    Public Property method As String
    Public Property result As Result
    Public Property resultRecords As Record()
End Class

The question, then, is this: how can I tell JsonConvert whether to store data in property Response.result when it fits its type (1st sample case above), or in Response.resultRecords in 2nd case?

Thank you!


回答1:


Since the format of the JSON can vary for the same property, you will need a custom JsonConverter to handle it. The converter can read the JSON for the affected property, determine its format and then populate your objects appropriately. Here is the code you would need:

Public Class ResultConverter
    Inherits JsonConverter

    Public Overrides Function CanConvert(objectType As Type) As Boolean
        Return objectType = GetType(Result)
    End Function

    Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
        Dim token As JToken = JToken.Load(reader)
        Dim result As Result = New Result
        If token.Type = JTokenType.Array Then
            result.records = token.ToObject(Of Record())(serializer)
            result.total = result.records.Length
            result.success = True
        Else
            serializer.Populate(token.CreateReader(), result)
        End If
        Return result
    End Function

    Public Overrides ReadOnly Property CanWrite As Boolean
        Get
            Return False
        End Get
    End Property

    Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
        Throw New NotImplementedException
    End Sub
End Class

To use the converter, add a <JsonConverter> attribute to the result property in your Response class:

Public Class Response
    Public Property type As String
    Public Property tid As Integer
    Public Property action As String
    Public Property method As String
    <JsonConverter(GetType(ResultConverter))>
    Public Property result As Result
End Class

Here is a working fiddle to show that this converter will allow both JSON formats to be deserialized into the same classes: https://dotnetfiddle.net/NFbQ2Q



来源:https://stackoverflow.com/questions/37054003/deserialize-json-which-can-have-different-objects-under-same-property-name

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!