|
-
Jan 17th, 2018, 08:31 AM
#1
Thread Starter
Fanatic Member
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).
-
Jan 17th, 2018, 12:09 PM
#2
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.
-
Jan 17th, 2018, 12:32 PM
#3
Thread Starter
Fanatic Member
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)?
-
Jan 17th, 2018, 12:51 PM
#4
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.
-
Jan 17th, 2018, 12:54 PM
#5
Thread Starter
Fanatic Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|