Tarmil / FSharp.SystemTextJson

System.Text.Json extensions for F# types
MIT License
323 stars 44 forks source link

[#89] Add JsonName attribute for union cases with int or bool tags #127

Closed Tarmil closed 1 year ago

Tarmil commented 1 year ago
bartelink commented 1 year ago

The first one is used for serialization

I dont believe order is guaranteed to be preserved when you load?

Support JsonNameAttribute on union cases to specify the name of a union field.

Is this in addition to using it directly on the field? Or as a workaround for that not being possible? (My instinct is that this is a pretty baroque design even though it will help source legibility)

Tarmil commented 1 year ago

I dont believe order is guaranteed to be preserved when you load?

Well spotted! I think we can make JsonName take a [<ParamArray>] otherNames: obj[] instead of using multiple attributes. This way the order is guaranteed.

type MyUnion =
    | [<JsonName(1, "a")>] One of string
    | [<JsonName 2>] Two of string

An alternative would be to add an optional parameter eg isMain: bool, but that feels too verbose.

Is this in addition to using it directly on the field? Or as a workaround for that not being possible? (My instinct is that this is a pretty baroque design even though it will help source legibility)

Unfortunately there is no syntax in F# to put an attribute directly on a union field. The following doesn't compile:

type MyUnion =
    | One of [<JsonName "theName">] name: string

So my proposal above is the only way I can think of to support using JsonName for a union field.

Tarmil commented 1 year ago

I realized that we can't have both an optional argument for the union field name and a ParamArray for alternate names. I think I'll make the union field name a mutable property instead, so that the syntax would be:

type MyUnion =
    | [<JsonName 1>]
      [<JsonName("theName", "theOtherName", Field = "name")>]
      One of name: string

// eg: One "value" --> {"Case":1,"Fields":{"theName":"value"}}
//                  or {"Case":1,"Fields":{"theOtherName":"value"}}