Results 1 to 5 of 5

Thread: Custom JSON Font Serialization

  1. #1

    Thread Starter
    Fanatic Member clarkgriswald's Avatar
    Join Date
    Feb 2000
    Location
    USA
    Posts
    799

    Custom JSON Font Serialization

    I am currently using the Newtonsoft JSON library to serialize/deserialize my object, which works great except for one issue. Font properties are serialized into a single string that must be parsed in order to acquire the appropriate values, which is a bit messy. Has anyone customized the serializer to serialize the font into an object like:

    "TitleFont": {
    "Name": "Arial",
    "Size": 10,
    "Bold": true,
    "Italic": true,
    "Underline": false
    }

    This format would be much easier to work with. Anyone have anything here? Same with deserialzation; getting the new object back into the font (assuming modifying the ReadJson event).

  2. #2
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Custom JSON Font Serialization

    It's pretty easy once you see how to do it. You have a couple of choices.

    One approach involves writing a type derived from JsonConverter that can serialize and deserialize the type. This is intended extensibility, but I don't personally like it because you end up having to use JsonWriter and JsonReader and I find that API clunky.

    Another approach involves making a proxy object that can convert to and from a Font. I'm going to demonstrate this approach.

    Here's a proxy object for Fonts:
    Code:
    Public Class JsonFont
    
        Public Property Name As String
        Public Property Size As Integer
        Public Property Bold As Boolean
        Public Property Italic As Boolean
        Public Property Underline As Boolean
    
        Public Sub New()
        End Sub
    
        Public Shared Function FromFont(ByVal theFont As Font) As JsonFont
            Dim result As New JsonFont()
            result.Name = theFont.FontFamily.Name
            result.Size = theFont.Size
    
            result.Bold = HasStyle(theFont, FontStyle.Bold)
            result.Italic = HasStyle(theFont, FontStyle.Italic)
            result.Underline = HasStyle(theFont, FontStyle.Underline)
    
            Return result
        End Function
    
        Public Function ToFont() As Font
            Dim style As FontStyle
            If Bold Then
                style = style Or FontStyle.Bold
            End If
    
            If Italic Then
                style = style Or FontStyle.Italic
            End If
    
            If Underline Then
                style = style Or FontStyle.Underline
            End If
    
            Dim f As New Font(Name, Size, style)
            Return f
        End Function
    
        Private Shared Function HasStyle(ByVal f As Font, ByVal style As FontStyle) As Boolean
            Return f.Style And style <> 0
        End Function
    
    End Class
    To make this work, your serialization type would need to use a JsonFont property instead of a Font property, but you can sort of fudge that if it's an object you wrote. Maybe you don't like it. This proxy object's still useful if you want to go the JsonConverter route.

    We could do like this:
    Code:
    Public Class FontConverter
        Inherits JsonConverter
        Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
            Dim fontProxy = JsonFont.FromFont(CType(value, Font))
    
            writer.WriteStartObject()
    
            EmitProperty(writer, "Name", fontProxy.Name)
            EmitProperty(writer, "Size", fontProxy.Size)
            EmitProperty(writer, "Bold", fontProxy.Bold)
            EmitProperty(writer, "Italic", fontProxy.Italic)
            EmitProperty(writer, "Underline", fontProxy.Underline)
    
            writer.WriteEndObject()
        End Sub
    
        Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
            Dim fontProxy As New JsonFont()
    
            While reader.Read()
                Select Case reader.TokenType
                    Case JsonToken.PropertyName
                        ReadProperty(reader, fontProxy)
                    Case JsonToken.EndObject
                        Exit While
                End Select
            End While
    
            Return fontProxy.ToFont()
        End Function
    
        Public Overrides Function CanConvert(objectType As Type) As Boolean
            Return objectType = GetType(Font)
        End Function
    
        Private Sub EmitProperty(Of T)(ByVal writer As JsonWriter, ByVal name As String, ByVal value As T)
            writer.WritePropertyName(name)
            writer.WriteValue(value)
        End Sub
    
        Private Sub ReadProperty(ByVal reader As JsonReader, ByVal proxy As JsonFont)
            Select Case reader.Value
                Case "Name"
                    proxy.Name = reader.ReadAsString()
                Case "Size"
                    proxy.Size = reader.ReadAsInt32()
                Case "Bold"
                    proxy.Bold = reader.ReadAsBoolean()
                Case "Italic"
                    proxy.Italic = reader.ReadAsBoolean()
                Case "Underline"
                    proxy.Underline = reader.ReadAsBoolean()
            End Select
        End Sub
    
    End Class
    The trick there is now you have to make a JsonSerializerSettings that knows about FontConverter and remember to use that when serializing/deserializing. Here's a quick demo:
    Code:
    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim settings As New JsonSerializerSettings()
            settings.Converters.Add(New FontConverter())
    
            Dim serialized = JsonConvert.SerializeObject(Me.Font, settings)
            Debug.WriteLine(serialized)
    
            Dim deserialized As Font = JsonConvert.DeserializeObject(Of Font)(serialized, settings)
            Debug.WriteLine(deserialized)
        End Sub
    
    End Class
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  3. #3

    Thread Starter
    Fanatic Member clarkgriswald's Avatar
    Join Date
    Feb 2000
    Location
    USA
    Posts
    799

    Re: Custom JSON Font Serialization

    This was a HUGE help, thanks! Last question for you...how would I handle deserializing legacy JSON that would contain the old format (single font string)?

  4. #4
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Custom JSON Font Serialization

    That'd be different deserialization code. With some work, you could make the converter try to figure out what it has. I'd have to see the actual string to get a feel for how those modifications might look.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  5. #5

    Thread Starter
    Fanatic Member clarkgriswald's Avatar
    Join Date
    Feb 2000
    Location
    USA
    Posts
    799

    Re: Custom JSON Font Serialization

    Ok, I am working on that now - it really needs to fall back to the original serializer if it is not in the updated format.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width