PW.JSON Library Implementation in VB.NET

Implementazione della libreria PW.JSON in VB.NET (versione italiana)

In this post I'm trying to explain how I've developed the PW.JSON library for .NET. This Library can convert Objects to JSON strings and viceversa with the standard defined on www.json.org.

I've searched on links in www.json.org site but I've not found some axample in VB.NET. There is a VB 6 version, a  C# very complete and complex version but nothing else, so searching on the web I've found this sample at http://mikeoncode.blogspot.com/2007/05/json-re-visited-from.html.

Then I've modified the code of Mike Griffiths for managing double quoted strings instead of single quoted (the JSON standard is double quoted) and I've managed null properties aof the objects (properties set to Nothing).

The new code is this:

Imports System.Text

Friend Class NetJSON

#Region " Private Declarations"
Dim myName As String = ""
Dim myContent As New Hashtable
Const dblQuote As Char = Chr(34)
#End Region

#Region
" Enumerations"
Private Enum dataType
    dt_Nothing
    dt_Boolean
    dt_Decimal
    dt_Double
    dt_Integer
    dt_string
    dt_Array
    dt_NetJSON
End Enum
#End
Region

#Region
" Public Constructors, Methods and Properties"
Public Sub New()

End Sub

Public Sub New(ByVal nameString As String)
    myName = nameString
End Sub

Public Sub AddNameValue(ByVal nameString As String, ByVal Value As Object)
    StoreValue(nameString, Value)
End Sub

Public Overrides Function toString() As String
    Dim
Resp As New StringBuilder
   
Dim Firstcall As Boolean = True
    Dim
TailBrace As String = "}"

    If myName.Length > 0 Then
        Resp.Append("{" & dblQuote & myName & dblQuote & ": {")
        TailBrace &=
"}"
   
Else
        Resp.Append("{")
   
End If

    Dim myEnumerator As IDictionaryEnumerator = myContent.GetEnumerator()
   
While myEnumerator.MoveNext
        Resp.Append(IIf(Firstcall,
"", ", ") & dblQuote & myEnumerator.Key & dblQuote & ": " & MakeString(myEnumerator.Value))
        Firstcall =
False
    End
While

    Resp.Append(TailBrace)
   
Return Resp.ToString()
End Function

#End
Region

#Region
" Private Functions and Subroutines"
Private Function MakeString(ByVal ThisData As Object) As String
    Dim
ThisType As dataType = GetDataType(ThisData)

   
If ThisType = dataType.dt_Array Then
        Dim
TestArray(ThisData.length) As Object
        Dim
aLoop As Int16
       
Dim ArrayStruct As New StringBuilder("[")
       
Dim FirstCall As Boolean = True

        ThisType = GetDataType(ThisData(0))

       
For aLoop = 0 To ThisData.Length - 1
            ArrayStruct.Append(IIf(FirstCall,
"", ", ") & MakeElementString(ThisData(aLoop), ThisType))
            FirstCall =
False
        Next

        ArrayStruct.Append(
"]")
       
Return ArrayStruct.ToString()
   
Else
        Return
MakeElementString(ThisData, ThisType)
   
End If
End
Function

Private Function MakeElementString(ByVal ThisData As Object, ByVal ThisDataType As dataType)
   
Select Case ThisDataType
       
Case dataType.dt_Boolean
           
Return IIf(CBool(ThisData), "true", "false")
       
Case dataType.dt_Decimal
           
Return String.Format("{0}", ThisData).Replace(","c, "."c)
       
Case dataType.dt_string
           
Return Chr(34) & CType(ThisData, String).Replace("\", "\\").Replace("/", "\/").Replace(vbCrLf, "\n").Replace(vbTab, "\t").Replace(Chr(34), "\" & Chr(34)) & Chr(34)
       
Case dataType.dt_Nothing
           
Return "null"
        Case dataType.dt_NetJSON
           
Return ThisData.ToString()
       
Case Else
            Return
""
    End Select
End
Function

Private Function GetDataType(ByVal Value As Object) As dataType
   
If TypeOf Value Is Array Then
        Return
dataType.dt_Array
   
ElseIf TypeOf Value Is Single Or TypeOf Value Is Double Then
        Return
dataType.dt_Double
   
ElseIf TypeOf Value Is Decimal Then
        Return
dataType.dt_Decimal
   
ElseIf TypeOf Value Is Boolean Then
        Return
dataType.dt_Boolean
   
ElseIf TypeOf Value Is String Then
        Return
dataType.dt_string
   
ElseIf TypeOf Value Is Integer Or TypeOf Value Is Int16 Or TypeOf Value Is Int32 Or TypeOf Value Is Int64 Then
        Return
dataType.dt_Integer
   
ElseIf TypeOf Value Is NetJSON Then
        Return
dataType.dt_NetJSON
   
ElseIf Value Is Nothing Then
        Return
dataType.dt_Nothing
   
End If
End
Function


Private Sub StoreValue(ByVal nameString As String, ByVal Value As Object)
   
Select Case GetDataType(Value)
       
Case dataType.dt_Array
           
Dim copyArray(Value.length - 1) As Object
            For
aLoop As Int16 = 0 To Value.length - 1
                copyArray(aLoop) = Value(aLoop)
           
Next
            myContent.Add(nameString, copyArray)

       
Case dataType.dt_Boolean
           
Dim wrkBoolean As Boolean = CBool(Value)
            myContent.Add(nameString, wrkBoolean)

        Case dataType.dt_Double, dataType.dt_Integer, dataType.dt_Decimal
           
Dim wrkDecimal As Decimal = CDec(Value)
            myContent.Add(nameString, wrkDecimal)

       
Case dataType.dt_string
           
Dim wrkString As String = CStr(Value)
            myContent.Add(nameString, wrkString)

        
Case dataType.dt_NetJSON
            myContent.Add(nameString, Value)

        
Case dataType.dt_Nothing
            myContent.Add(nameString,
Nothing)

   
End Select
End
Sub

#End
Region

End
Class

The NetJSON class help us on creating JSON strings but we must think in terms of name/value properties. I'll convert any type of object in JSON strings, so I've developed The JSONHelper class below:

Imports System.Reflection

Public Class JSONHelper

#Region "Gestione Object via Reflection"

Public Shared Function ObjectToString(ByVal Obj As Object) As String
    If Obj Is Nothing Then Return ""
    Dim _t As Type = Obj.GetType()
    Return ConvertSubObjectToNetJSON("", Obj).toString
End Function

Private Shared Function ConvertSubObjectToNetJSON(ByVal Name As String, ByRef Obj As Object) As NetJSON
    If Obj Is Nothing Then Return Nothing
    Dim _t As Type = Obj.GetType()
    Dim result As New NetJSON(Name)
    For Each _p As PropertyInfo In _t.GetProperties()
        If _p.PropertyType.IsPrimitive Then
           result.AddNameValue(_p.Name, _p.GetValue(Obj, Nothing))
        ElseIf _p.PropertyType.IsArray Then
           result.AddNameValue(_p.Name, _p.GetValue(Obj, Nothing))
        ElseIf _p.PropertyType.IsClass AndAlso _p.PropertyType.Name <> GetType(String).Name Then
           result.AddNameValue(_p.Name, ConvertSubObjectToNetJSON("", _p.GetValue(Obj, Nothing)))
        ElseIf _p.PropertyType.Name = GetType(String).Name Then
           result.AddNameValue(_p.Name, _p.GetValue(Obj, Nothing))
        Else
           ThrowNew NotImplementedException("Property Type '" & _p.PropertyType.Name & "' not yet implemented")
        End If
    Next
    Return result
End Function

Public Shared Function StringToObject(ByVal JSONString As String, ByVal ClassType As Type) As Object
    Dim ojson As New JSON.JSONObject
    Return ojson.parse(JSONString, ClassType)
End Function

#End Region

End Class

 

Using the PropertyInfo calss of System.Reflection namespace I convert each object peoprerty in a Name/Value property of NetJSON class.

Note that if a property is of Date type, the code will raise a NotImplementedException. This is correct because the JSON standard don't define date data type.

This is how to use ObjectToString method:

Imports PW.JSON

Module Module1

  Class Prova

    Private _id As Integer
    Private _name As String
    Private _valido As Boolean
    Private _subObject As Prova
    Private _numero As Integer
    Private _numeroDec As Double
    Private _array() As String

    Public Property ID() As Integer
      Get
        Return _id
      End Get
      Set(ByVal value As Integer)
        _id = value
      End Set
    End Property

    Public Property Name() As String
      Get
        Return _name
      End Get
      Set(ByVal value As String)
        _name = value
      End Set
    End Property

    Public Property Valido() As Boolean
      Get
        Return _valido
      End Get
      Set(ByVal value As Boolean)
        _valido = value
      End Set
    End Property

    Public Property SubObject() As Prova
      Get
        Return _subObject
      End Get
      Set(ByVal value As Prova)
        _subObject = value
      End Set
    End Property

    Public Property NumeroDec() As Double
      Get
        Return _numeroDec
      End Get
      Set(ByVal value As Double)
        _numeroDec = value
      End Set
    End Property

    Public Property Array() As String()
      Get
        Return _array
      End Get
      Set(ByVal value As String())
        _array = value
      End Set
    End Property

    Public Sub New(ByVal ID As Integer, ByVal Name As String)
      _id = ID
      _name = Name
    End Sub

    Public Function SomeMethod() As String
      Return "Method: " & _id
    End Function

  End Class

Sub Main()
    Dim objprova As New Prova(1, "Nome Object")
    objprova.Array = Split(
"A E I O U")
    objprova.NumeroDec = 100.34
    objprova.SubObject =
New Prova(2, "Nome - SubObject")
    objprova.Valido =
True
    Console.WriteLine(PW.JSON.JSONHelper.ObjectToString(objprova))
    Console.ReadLine()
 
End Sub
End Module


 

The resulting JSON string is:

{"NumeroDec": 100.34, "Name": "Nome Object", "Array": ["A", "E", "I", "O", "U"], "SubObject": {"NumeroDec": 0, "Name": "Nome - SubObject", "Array": null, "SubObject": null, "Valido": false, "ID": 2}, "Valido": true, "ID": 1}

Now we can see the StringToObject method that convert JSON string in Object. We can use the output of the previous example:

Sub Main()

Dim strJSON As String = "{""NumeroDec"": 100.34, ""Name"": ""Nome Object"", " & _
                        " ""Array"": [""A"", ""E"", ""I"", ""O"", ""U""], " & _
                        " ""SubObject"": {""NumeroDec"": 0, ""Name"": ""Nome - SubObject"", " & _
                        " ""Array"": null, ""SubObject"": null, ""Valido"": false, ""ID"": 2}, " & _
                        " ""Valido"": true, ""ID"": 1}"

Dim objprova As Prova
objprova = PW.JSON.JSONHelper.StringToObject(strJSON,
GetType(Prova))

Console.WriteLine(objprova.Name)
Console.WriteLine(objprova.SubObject.Name)
Console.ReadLine()
 
End Sub

The result is:

Nome Object
Nome - SubObject

If you want to see all the source code, or download the PW.JSON library (PW.JSON.dll) and you are a registered user, click here