I am trying to convert a JSON returned from a third party API, into VB.NET class object. The problem is that the JSON sometimes returns a node as an Array of objects and sometimes the same node as an single Object. So, while trying to convert when it receives Array of objects, the code throws exception.
{
"correlation_id": "228.9219622269229",
"Error": {
"messages": [
{
"code": "401",
"description": "Unauthorized"
}
]
},
"transaction_status": "Not Processed"
}
As you can see, there is an array of Error messages under Error->messages node. But sometimes, the JSON returned is simpy and object of Error messages something like
{
"correlation_id": "228.9219622269229",
"Error": {
"messages": {
"code": "401",
"description": "Unauthorized"
}
},
"transaction_status": "Not Processed"
}
I try to deserialize this JSON to the following class
Public Class PayeezyRefundResponse
Public correlation_id As String
Public transaction_status As String
Public validation_status As String
Public transaction_type As String
Public transaction_id As String
Public transaction_tag As String
Public bank_resp_code As String
Public bank_message As String
Public [Error] As PayeezyError
End Class
Public Class PayeezyError
Public messages As PayeezyErrorMessages()
End Class
Public Class PayeezyErrorMessages
Public code As String
Public description As String
End Class
But when the JSON returns Error message as single object, the code throws exception on PayeezyError class. How can I convert the JSON to this class so that it works in both the cases (i.e. with Array of objects and with single Object) ?
You can build a custom converter that can handle both cases as a List(Of PayeezyErrorMessage)
.
This converter always returns a List(Of PayeezyErrorMessage)
, even when the JSON contains a single object.
Note: in code, PayeezyErrorMessages
, plural, has been renamed to PayeezyErrorMessage
, single, since this class generates a single object.
The custom converter is added to the property as an attribute:
<JsonConverter(GetType(PayeezyErrorsConverter(Of PayeezyErrorMessage)))>
Public Messages As List(Of PayeezyErrorMessage)
Refactored code:
Public Class PayeezyRefundResponse
' [...]
<JsonProperty("Error")>
Public Errors As PayeezyErrors
End Class
Public Class PayeezyErrors
<JsonProperty("messages")>
<JsonConverter(GetType(PayeezyErrorsConverter(Of PayeezyErrorMessage)))>
Public Messages As List(Of PayeezyErrorMessage)
End Class
Public Class PayeezyErrorMessage
Public code As String
Public description As String
End Class
Custom converter:
► The writer part is not implemented, since you probably won't need to send back this JSON
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Public Class PayeezyErrorsConverter(Of T)
Inherits JsonConverter
Public Overrides Function CanConvert(objectType As Type) As Boolean
Return (objectType = GetType(List(Of T)))
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)
If token.Type = JTokenType.Array Then
Return token.ToObject(Of List(Of T))()
End If
Return New List(Of T)() From {
token.ToObject(Of T)()
}
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