11namespace FsCodec.SystemTextJson
22
33open System
4- open System.Linq .Expressions
54open System.Text .Json
65open System.Text .Json .Serialization
76
87type RejectNullConverter < 'T >() =
98 inherit System.Text.Json.Serialization.JsonConverter< 'T>()
109
11- static let defaultConverter = JsonSerializerOptions.Default.GetConverter( typeof< 'T>) :?> JsonConverter< 'T>
10+ let defaultConverter = JsonSerializerOptions.Default.GetConverter( typeof< 'T>) :?> JsonConverter< 'T>
1211 let msg () = sprintf " Expected value, got null. When rejectNull is true you must explicitly wrap optional %s values in an 'option'" typeof< 'T>. Name
1312
1413 override _.HandleNull = true
1514
1615 override _.Read ( reader , typeToConvert , options ) =
1716 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
1821 defaultConverter.Read(& reader, typeToConvert, options)
1922 // Pretty sure the above is the correct approach (and this unsurprisingly loops, blowing the stack)
2023 // JsonSerializer.Deserialize(&reader, typeToConvert, options) :?> 'T
@@ -26,17 +29,8 @@ type RejectNullConverter<'T>() =
2629
2730type RejectNullConverterFactory ( predicate ) =
2831 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)
4034
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