1
1
namespace FsCodec.SystemTextJson
2
2
3
3
open System
4
- open System.Linq .Expressions
5
4
open System.Text .Json
6
5
open System.Text .Json .Serialization
7
6
8
7
type RejectNullConverter < 'T >() =
9
8
inherit System.Text.Json.Serialization.JsonConverter< 'T>()
10
9
11
- static let defaultConverter = JsonSerializerOptions.Default.GetConverter( typeof< 'T>) :?> JsonConverter< 'T>
10
+ let defaultConverter = JsonSerializerOptions.Default.GetConverter( typeof< 'T>) :?> JsonConverter< 'T>
12
11
let msg () = sprintf " Expected value, got null. When rejectNull is true you must explicitly wrap optional %s values in an 'option'" typeof< 'T>. Name
13
12
14
13
override _.HandleNull = true
15
14
16
15
override _.Read ( reader , typeToConvert , options ) =
17
16
if reader.TokenType = JsonTokenType.Null then msg () |> nullArg else
17
+ // PROBLEM: Fails with NRE when RejectNullConverter delegates to Default list<int> Converter
18
+ // System.NullReferenceException
19
+ // at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
20
+ // https://github.com/dotnet/runtime/issues/50205 via https://github.com/jet/FsCodec/pull/112#issuecomment-1907633798
18
21
defaultConverter.Read(& reader, typeToConvert, options)
19
22
// Pretty sure the above is the correct approach (and this unsurprisingly loops, blowing the stack)
20
23
// JsonSerializer.Deserialize(&reader, typeToConvert, options) :?> 'T
@@ -26,17 +29,8 @@ type RejectNullConverter<'T>() =
26
29
27
30
type RejectNullConverterFactory ( predicate ) =
28
31
inherit JsonConverterFactory()
29
- new () =
30
- RejectNullConverterFactory( fun ( t : Type ) ->
31
- t.IsGenericType
32
- && let gtd = t.GetGenericTypeDefinition() in gtd = typedefof< Set<_>> || gtd = typedefof< list<_>>)
33
- override _.CanConvert ( t : Type ) = predicate t
34
-
35
- override _.CreateConverter ( t , _options ) =
36
- let openConverterType = typedefof< RejectNullConverter<_>>
37
- let constructor = openConverterType.MakeGenericType( t) .GetConstructors() |> Array.head
38
- let newExpression = Expression.New( constructor)
39
- let lambda = Expression.Lambda( typeof< ConverterActivator>, newExpression)
32
+ static let isListOrSet ( t : Type ) = t.IsGenericType && let g = t.GetGenericTypeDefinition() in g = typedefof< Set<_>> || g = typedefof< list<_>>
33
+ new () = RejectNullConverterFactory( isListOrSet)
40
34
41
- let activator = lambda.Compile () :?> ConverterActivator
42
- activator.Invoke ()
35
+ override _.CanConvert ( t : Type ) = predicate t
36
+ override _.CreateConverter ( t , _options ) = typedefof < RejectNullConverter <_>>. MakeGenericType ( t ) .GetConstructors ().[ 0 ]. Invoke [||] :?> _
0 commit comments