How to use F# Union types with Servicestack JSON serialization?
Asked Answered
B

1

7

I guess it is too much I am asking from a framework. But just wondering if it is possible at all. Or what will be work around for this.

JSON.Net with new release started supporting F# union types. What is the work around for that, means if I am using servicestack.text, then how can I flatten union types to support serialization.

Here is code sample for both.

type Shape =
    | Rectangle of width : float * length : float
    | Circle of radius : float
    | Empty


[<EntryPoint>]
let main argv = 
//    printfn "%A" argv
    let shape1 = Rectangle(1.3, 10.0)

    let json = JsonConvert.SerializeObject(shape1) //JSON.net
    printfn "%A" json
    // {
    //   "Case": "Rectangle",
    //   "Fields": [
    //     1.3,
    //     10.0
    //   ]
    // }

    let shape2 = JsonConvert.DeserializeObject<Shape>(json) //JSON.Net
    printfn "%A" (shape2 = shape1) //true

    let sJson = JsonSerializer.SerializeToString shape1 //SS.Text
    printfn "%A" sJson

    let sShape2 = JsonSerializer.DeserializeFromString sJson //SS.Text
    printfn "%A" (sShape2 = shape1) //false

    Console.Read() |> ignore
    0 // return an integer exit code

Deserialization using servicestack is returning false. And also generated json string is quite complicated in compare to JSON.net.

How to achieve proper serialization for Union types?

Bellda answered 13/3, 2014 at 5:59 Comment(0)
T
2

You'll have to give ServiceStack a custom serializer. It would like this, using a smaller Shape type for brevity:

open ServiceStack.Text

type Shape =
    | Circle of float
    | Empty

JsConfig<Shape>.SerializeFn 
    <- Func<_,_> (function
                  | Circle r -> sprintf "C %f" r
                  | Empty -> sprintf "E")

JsConfig<Shape>.DeSerializeFn 
    <- Func<_,_> (fun s ->    
                    match s.Split [| |] with
                    | [| "C"; r |] -> Circle (float r)
                    | [| "E" |] -> Empty)

let shapes = [| Circle 8.0 |]
let json = JsonSerializer.SerializeToString(shapes)
let shapes1 = JsonSerializer.DeserializeFromString<Shape[]>(json)
let is_ok = shapes = shapes1

This code does not have proper exception-propagation in the deserializer: you'd want to handle the match not matching, and float might raise a System.FormatException.

Tsarina answered 13/3, 2014 at 11:19 Comment(1)
It works. I have discussed the topic over groups. And I come to know about Fleece. It will be great if you can update the answer also with a sample of it, too. I guess that will solve the issue about serializing union type to JSON.Bellda

© 2022 - 2024 — McMap. All rights reserved.