Search code examples
jsonserializationf#json.net

Serializing F# Discriminated union as strings with Json.NET


I'm trying to do a one way transform from F#'s discriminated union to strings upon serialization instead of the default `"Case": [value]". Being able to deserialize the value again is not an issue. Maybe possible with Json.NET?

// Fsharp 4.1.0
open Newtonsoft.Json // 10.0.3

type HowLame =
| PrettyLame
| SuperLame

type Lame = {
    howLame: HowLame;
}

[<EntryPoint>]
let main argv =
    let lame = { howLame = PrettyLame }
    let ser = JsonConvert.SerializeObject(lame)

    // {"soLame":{"Case":"PrettyLame"}} by default
    printfn "%s" ser

    // Desired
    assert (ser = """{"soLame":"PrettyLame"}""")
    0 // return an integer exit code

Solution

  • If you are willing to make the DU an enum (by specifying explicit values, which probably is OK since there is no 'payload'), you can use the standard StringEnumConverter:

    #r "../packages/Newtonsoft.Json/lib/net45/Newtonsoft.Json.dll"
    open Newtonsoft.Json
    
    type HowLame = PrettyLame=0 | SuperLame=1
    type Lame = { howLame: HowLame; }
    
    // in contrast to DUs, enums must be qualified, i.e. Enum.Value
    let lame = { howLame = HowLame.PrettyLame }
    
    let settings = JsonSerializerSettings()
    settings.Converters.Add(Converters.StringEnumConverter())
    
    let ser = JsonConvert.SerializeObject(lame, settings)
    // val ser : string = "{"howLame":"PrettyLame"}"