@@ -45,7 +45,12 @@ type JsonUnionConverter<'T>
4545 let namedFields = fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.NamedFields
4646 let unwrapFieldlessTags = fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.UnwrapFieldlessTags
4747
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>)
4954
5055 let cases =
5156 cases
@@ -115,7 +120,7 @@ type JsonUnionConverter<'T>
115120 MinExpectedFieldCount = fields |> Seq.filter ( fun f -> f.MustBePresent) |> Seq.length
116121 })
117122
118- let tagReader = FSharpValue.PreComputeUnionTagReader( ty , true )
123+ let tagReader = FSharpValue.PreComputeUnionTagReader( unionType , true )
119124
120125 let hasDistinctFieldNames , fieldlessCase , allFields =
121126 let mutable fieldlessCase = ValueNone
@@ -184,7 +189,7 @@ type JsonUnionConverter<'T>
184189 | false , _ -> ValueNone
185190 match found with
186191 | 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()))
188193 | ValueSome case ->
189194 case
190195
@@ -207,7 +212,7 @@ type JsonUnionConverter<'T>
207212 | false , _ -> ValueNone
208213 match found with
209214 | ValueNone ->
210- raise ( JsonException( " Unknown case for union type " + ty .FullName + " : " + tag))
215+ raise ( JsonException( " Unknown case for union type " + unionType .FullName + " : " + tag))
211216 | ValueSome case ->
212217 case
213218
@@ -230,7 +235,7 @@ type JsonUnionConverter<'T>
230235 | false , _ -> ValueNone
231236 match found with
232237 | 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()))
234239 | ValueSome case ->
235240 case
236241
@@ -254,7 +259,7 @@ type JsonUnionConverter<'T>
254259 let readField ( reader : byref < Utf8JsonReader >) ( case : Case ) ( f : Field ) ( options : JsonSerializerOptions ) =
255260 reader.Read() |> ignore
256261 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
258263 raise ( JsonException msg)
259264 else
260265 JsonSerializer.Deserialize(& reader, f.Type, options)
@@ -264,11 +269,11 @@ type JsonUnionConverter<'T>
264269 let fields = Array.copy case.DefaultFields
265270 for i in 0 .. fieldCount-1 do
266271 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
268273 case.Ctor fields :?> 'T
269274
270275 let readFieldsAsArray ( reader : byref < Utf8JsonReader >) ( case : Case ) ( options : JsonSerializerOptions ) =
271- readExpecting JsonTokenType.StartArray " array" & reader ty
276+ readExpecting JsonTokenType.StartArray " array" & reader unionType
272277 readFieldsAsRestOfArray & reader case options
273278
274279 let coreReadFieldsAsRestOfObject ( reader : byref < Utf8JsonReader >) ( case : Case ) ( skipFirstRead : bool ) ( options : JsonSerializerOptions ) =
@@ -292,7 +297,7 @@ type JsonUnionConverter<'T>
292297 | _ -> ()
293298
294299 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))
296301 case.Ctor fields :?> 'T
297302
298303 let readFieldsAsRestOfObject ( reader : byref < Utf8JsonReader >) ( case : Case ) ( skipFirstRead : bool ) ( options : JsonSerializerOptions ) =
@@ -304,7 +309,7 @@ type JsonUnionConverter<'T>
304309 coreReadFieldsAsRestOfObject & reader case skipFirstRead options
305310
306311 let readFieldsAsObject ( reader : byref < Utf8JsonReader >) ( case : Case ) ( options : JsonSerializerOptions ) =
307- readExpecting JsonTokenType.StartObject " object" & reader ty
312+ readExpecting JsonTokenType.StartObject " object" & reader unionType
308313 readFieldsAsRestOfObject & reader case false options
309314
310315 let readFields ( reader : byref < Utf8JsonReader >) case options =
@@ -327,60 +332,60 @@ type JsonUnionConverter<'T>
327332 match document.RootElement.TryGetProperty fsOptions.UnionTagName with
328333 | true , element -> getCaseByTagString ( element.GetString())
329334 | 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
331336 |> JsonException
332337 |> raise
333338
334339 let getCase ( reader : byref < Utf8JsonReader >) =
335340 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
339344 struct ( getCaseByTagReader & reader, false )
340345 elif fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.AllowUnorderedTag then
341346 struct ( getCaseFromDocument reader, true )
342347 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
344349 |> JsonException
345350 |> raise
346351
347352 let readAdjacentTag ( reader : byref < Utf8JsonReader >) ( options : JsonSerializerOptions ) =
348- expectAlreadyRead JsonTokenType.StartObject " object" & reader ty
353+ expectAlreadyRead JsonTokenType.StartObject " object" & reader unionType
349354 let struct ( case , usedDocument ) = getCase & reader
350355 let res =
351356 if case.Fields.Length > 0 then
352- readExpectingPropertyNamed fsOptions.UnionFieldsName & reader ty
357+ readExpectingPropertyNamed fsOptions.UnionFieldsName & reader unionType
353358 readFields & reader case options
354359 else
355360 case.Ctor [||] :?> 'T
356361 if usedDocument then
357362 reader.Read() |> ignore
358363 reader.Skip()
359- readExpecting JsonTokenType.EndObject " end of object" & reader ty
364+ readExpecting JsonTokenType.EndObject " end of object" & reader unionType
360365 res
361366
362367 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
365370 let case = getCaseByTagReader & reader
366371 let res = readFields & reader case options
367- readExpecting JsonTokenType.EndObject " end of object" & reader ty
372+ readExpecting JsonTokenType.EndObject " end of object" & reader unionType
368373 res
369374
370375 let readInternalTag ( reader : byref < Utf8JsonReader >) ( options : JsonSerializerOptions ) =
371376 if namedFields then
372- expectAlreadyRead JsonTokenType.StartObject " object" & reader ty
377+ expectAlreadyRead JsonTokenType.StartObject " object" & reader unionType
373378 let mutable snapshot = reader
374379 let struct ( case , _usedDocument ) = getCase & snapshot
375380 readFieldsAsRestOfObject & reader case false options
376381 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
379384 let case = getCaseByTagReader & reader
380385 readFieldsAsRestOfArray & reader case options
381386
382387 let readUntagged ( reader : byref < Utf8JsonReader >) ( options : JsonSerializerOptions ) =
383- expectAlreadyRead JsonTokenType.StartObject " object" & reader ty
388+ expectAlreadyRead JsonTokenType.StartObject " object" & reader unionType
384389 reader.Read() |> ignore
385390 match reader.TokenType with
386391 | JsonTokenType.PropertyName ->
@@ -389,9 +394,9 @@ type JsonUnionConverter<'T>
389394 | JsonTokenType.EndObject ->
390395 match fieldlessCase with
391396 | ValueSome case -> case.Ctor [||] :?> 'T
392- | ValueNone -> fail " case field" & reader ty
397+ | ValueNone -> fail " case field" & reader unionType
393398 | _ ->
394- fail " case field" & reader ty
399+ fail " case field" & reader unionType
395400
396401 let writeFieldsAsRestOfArray ( writer : Utf8JsonWriter ) ( case : Case ) ( value : obj ) ( options : JsonSerializerOptions ) =
397402 let fields = case.Fields
@@ -462,38 +467,45 @@ type JsonUnionConverter<'T>
462467 writeFieldsAsObject writer case value options
463468
464469 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
481490
482491 override _.Write ( writer , value , options ) =
492+ if hasOnSerializing then ( unbox< IJsonOnSerializing> value) .OnSerializing()
483493 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()
490496 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()
497509
498510type JsonSkippableConverter < 'T >() =
499511 inherit JsonConverter< Skippable< 'T>>()
0 commit comments