Tarmil / FSharp.SystemTextJson

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

[#151] Add option to deserialize both null and missing as None #184

Closed Tarmil closed 3 months ago

Tarmil commented 3 months ago

Add optional argument deserializeNullAsNone: bool to option .WithSkippableOptionFields(SkippableOptionFields).

let options =
    JsonFSharpOptions.Default()
        .WithSkippableOptionFields(SkippableOptionFields.Always, deserializeNullAsNone = true)
        .ToJsonSerializerOptions()

JsonSerializer.Deserialize<{| x: int option|}>("""{}""", options)
// --> {| x = None |}

JsonSerializer.Deserialize<{| x: int option|}>("""{"x":null}""", options)
// --> {| x = None |}

Compare with the current, and now default false behavior:

let options =
    JsonFSharpOptions.Default()
        .WithSkippableOptionFields(SkippableOptionFields.Always)
        .ToJsonSerializerOptions()

JsonSerializer.Deserialize<{| x: int option|}>("""{}""", options)
// --> {| x = None |}

JsonSerializer.Deserialize<{| x: int option|}>("""{"x":null}""", options)
// JsonException: The JSON value could not be converted to System.Int32.

Fixes #151, #176, #182.

Note: I have changed my mind since this comment, in that this setting only affect option and voption, but not Skippable. The reason is that Skippable exists precisely for fields that must be skipped, and so that Skippable<T option> can be used to explicitly distinguish between missing and null. This ability should be usable alongside option values that can be deserialized from either null or missing.