@@ -46,7 +46,12 @@ type JsonUnionConverter<'T>
4646 let namedFields = fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.NamedFields
4747 let unwrapFieldlessTags = fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.UnwrapFieldlessTags
4848
49- let ty = typeof< 'T>
49+ static let unionType = typeof< 'T>
50+
51+ static let hasOnSerializing = unionType.IsAssignableFrom( typeof< IJsonOnSerializing>)
52+ static let hasOnSerialized = unionType.IsAssignableFrom( typeof< IJsonOnSerialized>)
53+ static let hasOnDeserializing = unionType.IsAssignableFrom( typeof< IJsonOnDeserializing>)
54+ static let hasOnDeserialized = unionType.IsAssignableFrom( typeof< IJsonOnDeserialized>)
5055
5156 let cases =
5257 cases
@@ -116,7 +121,7 @@ type JsonUnionConverter<'T>
116121 MinExpectedFieldCount = fields |> Seq.filter ( fun f -> f.MustBePresent) |> Seq.length
117122 })
118123
119- let tagReader = FSharpValue.PreComputeUnionTagReader( ty , true )
124+ let tagReader = FSharpValue.PreComputeUnionTagReader( unionType , true )
120125
121126 let hasDistinctFieldNames , fieldlessCase , allFields =
122127 let mutable fieldlessCase = ValueNone
@@ -185,7 +190,7 @@ type JsonUnionConverter<'T>
185190 | false , _ -> ValueNone
186191 match found with
187192 | ValueNone ->
188- raise ( JsonException( " Unknown case for union type " + ty .FullName + " : " + reader.GetString()))
193+ raise ( JsonException( " Unknown case for union type " + unionType .FullName + " : " + reader.GetString()))
189194 | ValueSome case ->
190195 case
191196
@@ -208,7 +213,7 @@ type JsonUnionConverter<'T>
208213 | false , _ -> ValueNone
209214 match found with
210215 | ValueNone ->
211- raise ( JsonException( " Unknown case for union type " + ty .FullName + " : " + tag))
216+ raise ( JsonException( " Unknown case for union type " + unionType .FullName + " : " + tag))
212217 | ValueSome case ->
213218 case
214219
@@ -231,7 +236,7 @@ type JsonUnionConverter<'T>
231236 | false , _ -> ValueNone
232237 match found with
233238 | ValueNone ->
234- raise ( JsonException( " Unknown case for union type " + ty .FullName + " due to unknown field: " + reader.GetString()))
239+ raise ( JsonException( " Unknown case for union type " + unionType .FullName + " due to unknown field: " + reader.GetString()))
235240 | ValueSome case ->
236241 case
237242
@@ -255,7 +260,7 @@ type JsonUnionConverter<'T>
255260 let readField ( reader : byref < Utf8JsonReader >) ( case : Case ) ( f : Field ) ( options : JsonSerializerOptions ) =
256261 reader.Read() |> ignore
257262 if f.MustBeNonNull && reader.TokenType = JsonTokenType.Null then
258- 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
263+ 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
259264 raise ( JsonException msg)
260265 else
261266 JsonSerializer.Deserialize(& reader, f.Type, options)
@@ -265,11 +270,11 @@ type JsonUnionConverter<'T>
265270 let fields = Array.copy case.DefaultFields
266271 for i in 0 .. fieldCount-1 do
267272 fields[ i] <- readField & reader case case.Fields[ i] options
268- readExpecting JsonTokenType.EndArray " end of array" & reader ty
273+ readExpecting JsonTokenType.EndArray " end of array" & reader unionType
269274 case.Ctor fields :?> 'T
270275
271276 let readFieldsAsArray ( reader : byref < Utf8JsonReader >) ( case : Case ) ( options : JsonSerializerOptions ) =
272- readExpecting JsonTokenType.StartArray " array" & reader ty
277+ readExpecting JsonTokenType.StartArray " array" & reader unionType
273278 readFieldsAsRestOfArray & reader case options
274279
275280 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 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 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 ( box v :?> IJsonOnDeserializing) .OnDeserializing()
488+ if hasOnDeserialized then ( box v :?> IJsonOnDeserialized) .OnDeserialized()
489+ v
481490
482491 override _.Write ( writer , value , options ) =
492+ if hasOnSerializing then ( box value :?> IJsonOnSerializing) .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 ( box value :?> IJsonOnSerialized) .OnSerialized()
497509
498510type JsonSkippableConverter < 'T >() =
499511 inherit JsonConverter< Skippable< 'T>>()
0 commit comments