Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
like image 411
wegry Avatar asked Nov 12 '17 09:11

wegry


People also ask

What does serializing mean in coding?

Serialization is the process of converting an object into a stream of bytes to store the object or transmit it to memory, a database, or a file. Its main purpose is to save the state of an object in order to be able to recreate it when needed.

What does serializing mean in Python?

Serialization refers to the process of converting a data object (e.g., Python objects, Tensorflow models) into a format that allows us to store or transmit the data and then recreate the object when needed using the reverse process of deserialization.

What does serializing mean Java?

To serialize an object means to convert its state to a byte stream so that the byte stream can be reverted back into a copy of the object. A Java object is serializable if its class or any of its superclasses implements either the java. io. Serializable interface or its subinterface, java. io.

What is serializing in JSON?

Json namespace provides functionality for serializing to and deserializing from JavaScript Object Notation (JSON). Serialization is the process of converting the state of an object, that is, the values of its properties, into a form that can be stored or transmitted.


2 Answers

Creating a custom Json.NET JsonConverter and using it to decorate the discriminated union ("enum style") was enough to get this working the way I wanted. A good chunk of this is transliterated from @Brian Rogers answer in C# https://stackoverflow.com/a/22355712/1924257

open System
open Newtonsoft.Json // 10.0.3
open Newtonsoft.Json.Converters

type ToStringJsonConverter () =
    inherit JsonConverter()
    override this.CanConvert objectType = true;

    override this.WriteJson (writer: JsonWriter, value: obj, serializer: JsonSerializer): unit = 
        writer.WriteValue(value.ToString())

    override this.CanRead = false

    override this.ReadJson (reader: JsonReader, objectType: Type, existingValue: obj, serializer: JsonSerializer) : obj =
        raise (new NotImplementedException());

[<JsonConverter(typeof<ToStringJsonConverter>)>]
type HowLame =
| PrettyLame
| SuperLame

type Lame = {
    howLame: HowLame
}

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

    // {"howLame":"PrettyLame"}
    printfn "%s" ser

    0 // return an integer exit code
like image 167
wegry Avatar answered Oct 02 '22 18:10

wegry


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"}"
like image 25
CaringDev Avatar answered Oct 02 '22 18:10

CaringDev