Skip to content

Commit ac780bc

Browse files
committed
feat: add WithOverrideMembers for union cases
1 parent 7ce136a commit ac780bc

File tree

2 files changed

+99
-2
lines changed

2 files changed

+99
-2
lines changed

src/FSharp.SystemTextJson/Union.fs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,18 @@ module private Case =
7474
(options: JsonSerializerOptions)
7575
(uci: UnionCaseInfo)
7676
=
77+
let getAttrs ty =
78+
match fsOptions.OverrideMembers.TryGetValue(uci.Name) with
79+
| true, attrs ->
80+
[| for attr in attrs do
81+
if attr.GetType().IsAssignableFrom(ty) then
82+
box attr |]
83+
| false, _ -> uci.GetCustomAttributes(ty)
7784
let names =
78-
match getJsonNames "case" uci.GetCustomAttributes with
85+
match getJsonNames "case" getAttrs with
7986
| ValueSome name -> name
8087
| ValueNone -> [| JsonName.String(convertName tagNamingPolicy uci.Name) |]
81-
let fieldNames = getJsonFieldNames uci.GetCustomAttributes
88+
let fieldNames = getJsonFieldNames getAttrs
8289
let fields =
8390
let fields = uci.GetFields()
8491
let usedFieldNames = Dictionary()

tests/FSharp.SystemTextJson.Tests/Test.Union.fs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,47 @@ module NonStruct =
14291429
let actual = JsonSerializer.Deserialize("""{"enum-a":1}""", options)
14301430
Assert.Equal<Map<_, _>>(Map [ EnumA, 1 ], actual)
14311431

1432+
let overrideCasesOptions =
1433+
JsonFSharpOptions
1434+
.Default()
1435+
.WithOverrides(fun o ->
1436+
dict
1437+
[ typedefof<Result<_, _>>,
1438+
o
1439+
.WithUnionInternalTag()
1440+
.WithUnionNamedFields()
1441+
.WithUnionTagName("isSuccess")
1442+
.WithOverrideMembers(
1443+
dict
1444+
[ nameof Ok,
1445+
[ JsonNameAttribute(true)
1446+
JsonNameAttribute("value", Field = "ResultValue") ]
1447+
nameof Error,
1448+
[ JsonNameAttribute(false)
1449+
JsonNameAttribute("error", Field = "ErrorValue") ] ]
1450+
) ]
1451+
)
1452+
.ToJsonSerializerOptions()
1453+
1454+
[<Fact>]
1455+
let ``serialize with OverrideMembers`` () =
1456+
let actual = JsonSerializer.Serialize(Ok 42, overrideCasesOptions)
1457+
Assert.Equal("""{"isSuccess":true,"value":42}""", actual)
1458+
let actual = JsonSerializer.Serialize(Error "failed :(", overrideCasesOptions)
1459+
Assert.Equal("""{"isSuccess":false,"error":"failed :("}""", actual)
1460+
1461+
[<Fact>]
1462+
let ``deserialize with OverrideMembers`` () =
1463+
let actual =
1464+
JsonSerializer.Deserialize<Result<int, string>>("""{"isSuccess":true,"value":42}""", overrideCasesOptions)
1465+
Assert.Equal(Ok 42, actual)
1466+
let actual =
1467+
JsonSerializer.Deserialize<Result<int, string>>(
1468+
"""{"isSuccess":false,"error":"failed :("}""",
1469+
overrideCasesOptions
1470+
)
1471+
Assert.Equal(Error "failed :(", actual)
1472+
14321473
module Struct =
14331474

14341475
[<Struct; JsonFSharpConverter>]
@@ -2789,3 +2830,52 @@ module Struct =
27892830
enumLikeOptions().WithUnionTagNamingPolicy(JsonNamingPolicy.KebabCaseLower).ToJsonSerializerOptions()
27902831
let actual = JsonSerializer.Deserialize("""{"enum-a":1}""", options)
27912832
Assert.Equal<Map<_, _>>(Map [ EnumA, 1 ], actual)
2833+
2834+
[<Struct>]
2835+
type CustomResult<'TOk, 'TError> =
2836+
| Ok of ResultValue: 'TOk
2837+
| Error of ErrorValue: 'TError
2838+
2839+
let overrideCasesOptions =
2840+
JsonFSharpOptions
2841+
.Default()
2842+
.WithOverrides(fun o ->
2843+
dict
2844+
[ typedefof<CustomResult<_, _>>,
2845+
o
2846+
.WithUnionInternalTag()
2847+
.WithUnionNamedFields()
2848+
.WithUnionTagName("isSuccess")
2849+
.WithOverrideMembers(
2850+
dict
2851+
[ nameof Ok,
2852+
[ JsonNameAttribute(true)
2853+
JsonNameAttribute("value", Field = "ResultValue") ]
2854+
nameof Error,
2855+
[ JsonNameAttribute(false)
2856+
JsonNameAttribute("error", Field = "ErrorValue") ] ]
2857+
) ]
2858+
)
2859+
.ToJsonSerializerOptions()
2860+
2861+
[<Fact>]
2862+
let ``serialize with OverrideMembers`` () =
2863+
let actual = JsonSerializer.Serialize(Ok 42, overrideCasesOptions)
2864+
Assert.Equal("""{"isSuccess":true,"value":42}""", actual)
2865+
let actual = JsonSerializer.Serialize(Error "failed :(", overrideCasesOptions)
2866+
Assert.Equal("""{"isSuccess":false,"error":"failed :("}""", actual)
2867+
2868+
[<Fact>]
2869+
let ``deserialize with OverrideMembers`` () =
2870+
let actual =
2871+
JsonSerializer.Deserialize<CustomResult<int, string>>(
2872+
"""{"isSuccess":true,"value":42}""",
2873+
overrideCasesOptions
2874+
)
2875+
Assert.Equal(Ok 42, actual)
2876+
let actual =
2877+
JsonSerializer.Deserialize<CustomResult<int, string>>(
2878+
"""{"isSuccess":false,"error":"failed :("}""",
2879+
overrideCasesOptions
2880+
)
2881+
Assert.Equal(Error "failed :(", actual)

0 commit comments

Comments
 (0)