@@ -45,7 +45,12 @@ type JsonUnionConverter<'T>
45
45
let namedFields = fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.NamedFields
46
46
let unwrapFieldlessTags = fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.UnwrapFieldlessTags
47
47
48
- let ty = typeof< 'T>
48
+ static let unionType = typeof< 'T>
49
+
50
+ static let hasOnSerializing = unionType.IsAssignableFrom( typeof< IJsonOnSerializing>)
51
+ static let hasOnSerialized = unionType.IsAssignableFrom( typeof< IJsonOnSerialized>)
52
+ static let hasOnDeserializing = unionType.IsAssignableFrom( typeof< IJsonOnDeserializing>)
53
+ static let hasOnDeserialized = unionType.IsAssignableFrom( typeof< IJsonOnDeserialized>)
49
54
50
55
let cases =
51
56
cases
@@ -115,7 +120,7 @@ type JsonUnionConverter<'T>
115
120
MinExpectedFieldCount = fields |> Seq.filter ( fun f -> f.MustBePresent) |> Seq.length
116
121
})
117
122
118
- let tagReader = FSharpValue.PreComputeUnionTagReader( ty , true )
123
+ let tagReader = FSharpValue.PreComputeUnionTagReader( unionType , true )
119
124
120
125
let hasDistinctFieldNames , fieldlessCase , allFields =
121
126
let mutable fieldlessCase = ValueNone
@@ -184,7 +189,7 @@ type JsonUnionConverter<'T>
184
189
| false , _ -> ValueNone
185
190
match found with
186
191
| ValueNone ->
187
- raise ( JsonException( " Unknown case for union type " + ty .FullName + " : " + reader.GetString()))
192
+ raise ( JsonException( " Unknown case for union type " + unionType .FullName + " : " + reader.GetString()))
188
193
| ValueSome case ->
189
194
case
190
195
@@ -207,7 +212,7 @@ type JsonUnionConverter<'T>
207
212
| false , _ -> ValueNone
208
213
match found with
209
214
| ValueNone ->
210
- raise ( JsonException( " Unknown case for union type " + ty .FullName + " : " + tag))
215
+ raise ( JsonException( " Unknown case for union type " + unionType .FullName + " : " + tag))
211
216
| ValueSome case ->
212
217
case
213
218
@@ -230,7 +235,7 @@ type JsonUnionConverter<'T>
230
235
| false , _ -> ValueNone
231
236
match found with
232
237
| ValueNone ->
233
- raise ( JsonException( " Unknown case for union type " + ty .FullName + " due to unknown field: " + reader.GetString()))
238
+ raise ( JsonException( " Unknown case for union type " + unionType .FullName + " due to unknown field: " + reader.GetString()))
234
239
| ValueSome case ->
235
240
case
236
241
@@ -254,7 +259,7 @@ type JsonUnionConverter<'T>
254
259
let readField ( reader : byref < Utf8JsonReader >) ( case : Case ) ( f : Field ) ( options : JsonSerializerOptions ) =
255
260
reader.Read() |> ignore
256
261
if f.MustBeNonNull && reader.TokenType = JsonTokenType.Null then
257
- let msg = sprintf " %s .%s (%s ) was expected to be of type %s , but was null." ty .Name case.Name f.Name f.Type.Name
262
+ let msg = sprintf " %s .%s (%s ) was expected to be of type %s , but was null." unionType .Name case.Name f.Name f.Type.Name
258
263
raise ( JsonException msg)
259
264
else
260
265
JsonSerializer.Deserialize(& reader, f.Type, options)
@@ -264,11 +269,11 @@ type JsonUnionConverter<'T>
264
269
let fields = Array.copy case.DefaultFields
265
270
for i in 0 .. fieldCount-1 do
266
271
fields.[ i] <- readField & reader case case.Fields.[ i] options
267
- readExpecting JsonTokenType.EndArray " end of array" & reader ty
272
+ readExpecting JsonTokenType.EndArray " end of array" & reader unionType
268
273
case.Ctor fields :?> 'T
269
274
270
275
let readFieldsAsArray ( reader : byref < Utf8JsonReader >) ( case : Case ) ( options : JsonSerializerOptions ) =
271
- readExpecting JsonTokenType.StartArray " array" & reader ty
276
+ readExpecting JsonTokenType.StartArray " array" & reader unionType
272
277
readFieldsAsRestOfArray & reader case options
273
278
274
279
let coreReadFieldsAsRestOfObject ( reader : byref < Utf8JsonReader >) ( case : Case ) ( skipFirstRead : bool ) ( options : JsonSerializerOptions ) =
@@ -292,7 +297,7 @@ type JsonUnionConverter<'T>
292
297
| _ -> ()
293
298
294
299
if fieldsFound < case.MinExpectedFieldCount && not options.IgnoreNullValues then
295
- raise ( JsonException( " Missing field for union type " + ty .FullName))
300
+ raise ( JsonException( " Missing field for union type " + unionType .FullName))
296
301
case.Ctor fields :?> 'T
297
302
298
303
let readFieldsAsRestOfObject ( reader : byref < Utf8JsonReader >) ( case : Case ) ( skipFirstRead : bool ) ( options : JsonSerializerOptions ) =
@@ -304,7 +309,7 @@ type JsonUnionConverter<'T>
304
309
coreReadFieldsAsRestOfObject & reader case skipFirstRead options
305
310
306
311
let readFieldsAsObject ( reader : byref < Utf8JsonReader >) ( case : Case ) ( options : JsonSerializerOptions ) =
307
- readExpecting JsonTokenType.StartObject " object" & reader ty
312
+ readExpecting JsonTokenType.StartObject " object" & reader unionType
308
313
readFieldsAsRestOfObject & reader case false options
309
314
310
315
let readFields ( reader : byref < Utf8JsonReader >) case options =
@@ -327,60 +332,60 @@ type JsonUnionConverter<'T>
327
332
match document.RootElement.TryGetProperty fsOptions.UnionTagName with
328
333
| true , element -> getCaseByTagString ( element.GetString())
329
334
| false , _ ->
330
- sprintf " Failed to find union case field for %s : expected %s " ty .FullName fsOptions.UnionTagName
335
+ sprintf " Failed to find union case field for %s : expected %s " unionType .FullName fsOptions.UnionTagName
331
336
|> JsonException
332
337
|> raise
333
338
334
339
let getCase ( reader : byref < Utf8JsonReader >) =
335
340
let mutable snapshot = reader
336
- if readIsExpectingPropertyNamed fsOptions.UnionTagName & snapshot ty then
337
- readExpectingPropertyNamed fsOptions.UnionTagName & reader ty
338
- readExpecting JsonTokenType.String " case name" & reader ty
341
+ if readIsExpectingPropertyNamed fsOptions.UnionTagName & snapshot unionType then
342
+ readExpectingPropertyNamed fsOptions.UnionTagName & reader unionType
343
+ readExpecting JsonTokenType.String " case name" & reader unionType
339
344
struct ( getCaseByTagReader & reader, false )
340
345
elif fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.AllowUnorderedTag then
341
346
struct ( getCaseFromDocument reader, true )
342
347
else
343
- sprintf " Failed to find union case field for %s : expected %s " ty .FullName fsOptions.UnionTagName
348
+ sprintf " Failed to find union case field for %s : expected %s " unionType .FullName fsOptions.UnionTagName
344
349
|> JsonException
345
350
|> raise
346
351
347
352
let readAdjacentTag ( reader : byref < Utf8JsonReader >) ( options : JsonSerializerOptions ) =
348
- expectAlreadyRead JsonTokenType.StartObject " object" & reader ty
353
+ expectAlreadyRead JsonTokenType.StartObject " object" & reader unionType
349
354
let struct ( case , usedDocument ) = getCase & reader
350
355
let res =
351
356
if case.Fields.Length > 0 then
352
- readExpectingPropertyNamed fsOptions.UnionFieldsName & reader ty
357
+ readExpectingPropertyNamed fsOptions.UnionFieldsName & reader unionType
353
358
readFields & reader case options
354
359
else
355
360
case.Ctor [||] :?> 'T
356
361
if usedDocument then
357
362
reader.Read() |> ignore
358
363
reader.Skip()
359
- readExpecting JsonTokenType.EndObject " end of object" & reader ty
364
+ readExpecting JsonTokenType.EndObject " end of object" & reader unionType
360
365
res
361
366
362
367
let readExternalTag ( reader : byref < Utf8JsonReader >) ( options : JsonSerializerOptions ) =
363
- expectAlreadyRead JsonTokenType.StartObject " object" & reader ty
364
- readExpecting JsonTokenType.PropertyName " case name" & reader ty
368
+ expectAlreadyRead JsonTokenType.StartObject " object" & reader unionType
369
+ readExpecting JsonTokenType.PropertyName " case name" & reader unionType
365
370
let case = getCaseByTagReader & reader
366
371
let res = readFields & reader case options
367
- readExpecting JsonTokenType.EndObject " end of object" & reader ty
372
+ readExpecting JsonTokenType.EndObject " end of object" & reader unionType
368
373
res
369
374
370
375
let readInternalTag ( reader : byref < Utf8JsonReader >) ( options : JsonSerializerOptions ) =
371
376
if namedFields then
372
- expectAlreadyRead JsonTokenType.StartObject " object" & reader ty
377
+ expectAlreadyRead JsonTokenType.StartObject " object" & reader unionType
373
378
let mutable snapshot = reader
374
379
let struct ( case , _usedDocument ) = getCase & snapshot
375
380
readFieldsAsRestOfObject & reader case false options
376
381
else
377
- expectAlreadyRead JsonTokenType.StartArray " array" & reader ty
378
- readExpecting JsonTokenType.String " case name" & reader ty
382
+ expectAlreadyRead JsonTokenType.StartArray " array" & reader unionType
383
+ readExpecting JsonTokenType.String " case name" & reader unionType
379
384
let case = getCaseByTagReader & reader
380
385
readFieldsAsRestOfArray & reader case options
381
386
382
387
let readUntagged ( reader : byref < Utf8JsonReader >) ( options : JsonSerializerOptions ) =
383
- expectAlreadyRead JsonTokenType.StartObject " object" & reader ty
388
+ expectAlreadyRead JsonTokenType.StartObject " object" & reader unionType
384
389
reader.Read() |> ignore
385
390
match reader.TokenType with
386
391
| JsonTokenType.PropertyName ->
@@ -389,9 +394,9 @@ type JsonUnionConverter<'T>
389
394
| JsonTokenType.EndObject ->
390
395
match fieldlessCase with
391
396
| ValueSome case -> case.Ctor [||] :?> 'T
392
- | ValueNone -> fail " case field" & reader ty
397
+ | ValueNone -> fail " case field" & reader unionType
393
398
| _ ->
394
- fail " case field" & reader ty
399
+ fail " case field" & reader unionType
395
400
396
401
let writeFieldsAsRestOfArray ( writer : Utf8JsonWriter ) ( case : Case ) ( value : obj ) ( options : JsonSerializerOptions ) =
397
402
let fields = case.Fields
@@ -462,38 +467,45 @@ type JsonUnionConverter<'T>
462
467
writeFieldsAsObject writer case value options
463
468
464
469
override _.Read ( reader , _typeToConvert , options ) =
465
- match reader.TokenType with
466
- | JsonTokenType.Null when Helpers.isNullableUnion ty ->
467
- ( null : obj) :?> 'T
468
- | JsonTokenType.String when unwrapFieldlessTags ->
469
- let case = getCaseByTagReader & reader
470
- case.Ctor [||] :?> 'T
471
- | _ ->
472
- match baseFormat with
473
- | JsonUnionEncoding.AdjacentTag -> readAdjacentTag & reader options
474
- | JsonUnionEncoding.ExternalTag -> readExternalTag & reader options
475
- | JsonUnionEncoding.InternalTag -> readInternalTag & reader options
476
- | UntaggedBit ->
477
- if not hasDistinctFieldNames then
478
- raise ( JsonException( sprintf " Union %s can't be deserialized as Untagged because it has duplicate field names across unions" ty.FullName))
479
- readUntagged & reader options
480
- | _ -> raise ( JsonException( " Invalid union encoding: " + string fsOptions.UnionEncoding))
470
+ let v =
471
+ match reader.TokenType with
472
+ | JsonTokenType.Null when Helpers.isNullableUnion unionType ->
473
+ ( null : obj) :?> 'T
474
+ | JsonTokenType.String when unwrapFieldlessTags ->
475
+ let case = getCaseByTagReader & reader
476
+ case.Ctor [||] :?> 'T
477
+ | _ ->
478
+ match baseFormat with
479
+ | JsonUnionEncoding.AdjacentTag -> readAdjacentTag & reader options
480
+ | JsonUnionEncoding.ExternalTag -> readExternalTag & reader options
481
+ | JsonUnionEncoding.InternalTag -> readInternalTag & reader options
482
+ | UntaggedBit ->
483
+ if not hasDistinctFieldNames then
484
+ raise ( JsonException( sprintf " Union %s can't be deserialized as Untagged because it has duplicate field names across unions" unionType.FullName))
485
+ readUntagged & reader options
486
+ | _ -> raise ( JsonException( " Invalid union encoding: " + string fsOptions.UnionEncoding))
487
+ if hasOnDeserializing then ( unbox< IJsonOnDeserializing> v) .OnDeserializing()
488
+ if hasOnDeserialized then ( unbox< IJsonOnDeserialized> v) .OnDeserialized()
489
+ v
481
490
482
491
override _.Write ( writer , value , options ) =
492
+ if hasOnSerializing then ( unbox< IJsonOnSerializing> value) .OnSerializing()
483
493
let value = box value
484
- if isNull value then writer.WriteNullValue() else
485
-
486
- let tag = tagReader value
487
- let case = cases.[ tag]
488
- if unwrapFieldlessTags && case.Fields.Length = 0 then
489
- writer.WriteStringValue( case.Name)
494
+ if isNull value then
495
+ writer.WriteNullValue()
490
496
else
491
- match baseFormat with
492
- | JsonUnionEncoding.AdjacentTag -> writeAdjacentTag writer case value options
493
- | JsonUnionEncoding.ExternalTag -> writeExternalTag writer case value options
494
- | JsonUnionEncoding.InternalTag -> writeInternalTag writer case value options
495
- | UntaggedBit -> writeUntagged writer case value options
496
- | _ -> raise ( JsonException( " Invalid union encoding: " + string fsOptions.UnionEncoding))
497
+ let tag = tagReader value
498
+ let case = cases.[ tag]
499
+ if unwrapFieldlessTags && case.Fields.Length = 0 then
500
+ writer.WriteStringValue( case.Name)
501
+ else
502
+ match baseFormat with
503
+ | JsonUnionEncoding.AdjacentTag -> writeAdjacentTag writer case value options
504
+ | JsonUnionEncoding.ExternalTag -> writeExternalTag writer case value options
505
+ | JsonUnionEncoding.InternalTag -> writeInternalTag writer case value options
506
+ | UntaggedBit -> writeUntagged writer case value options
507
+ | _ -> raise ( JsonException( " Invalid union encoding: " + string fsOptions.UnionEncoding))
508
+ if hasOnSerialized then ( unbox< IJsonOnSerialized> value) .OnSerialized()
497
509
498
510
type JsonSkippableConverter < 'T >() =
499
511
inherit JsonConverter< Skippable< 'T>>()
0 commit comments