Open dlyz opened 1 year ago
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis See info in area-owners.md if you want to be subscribed.
Author: | dlyz |
---|---|
Assignees: | - |
Labels: | `area-System.Text.Json` |
Milestone: | - |
We won't be able to change the default value as that would be a very impactful breaking change. I don't expect any PR/change to emerge from this issue but's worth taking another look, to re-assess/justify why different values are used in the internal converters.HandleNullOnWrite
is true
Know workarounds
Have you run into any concrete scenarios where these workarounds weren't sufficient?
We won't be able to change the default value as that would be a very impactful breaking change.
Yeah, I thought so, I've mentioned this option mostly to better explain the issue. Although at least documentation should be corrected because currently it states:
and this is correct for the framework behavior, but incorrect for actual HandleNull value.
Have you run into any concrete scenarios where these workarounds weren't sufficient?
In my specific case it was actually easier to use value of internal HandleNullOnRead property since my converters already use LINQ Expressions to build actual converter code. Totally not perfect, but it will work for the foreseeable future, and if/when it stops I probably go with JsonSerializer, it is suboptimal but sufficient.
Description
We have a custom JsonConverter (
OuterConverter
forOuterClass
) that use another JsonConverter directly to read/write its property (in our case of typeInnerStruct
that serializes usingInnerConverter
). The pattern is generally demonstrated in Sample factory pattern converter, but a little simplified in the repro below.OuterClass
is generic andOuterConverter
have to consider_innerConverter.HandleNull
value before calling_innerConverter.Read()/Write()
.InnerConverter
does not override itsHandleNull
property, so the defaults will be used. And this default value will beHandleNull == false
, but the framework does not use this value, it actually uses internal propertiesHandleNullOnRead
andHandleNullOnWrite
, and their values for value types (structs) aretrue
andfalse
respectively. This means that in theOuterConverter
we think, that the_innerConverter
can not read nulls (_innerConverter.HandleNull == false
), but the framework and theInnerConverter
's author expect, thatInnerConverter
must read nulls. And currently there is no way forOuterConverter
to know expectedHandleNullOnRead
behavior fromInnerConverter
.Reproduction Steps
Minimal repro is under the spoiler.
Minimal repro
```cs using System; using System.Diagnostics; using System.Text.Json; using System.Text.Json.Serialization; using Xunit; public class DefaultHandleNullTest { private class OuterConverter : JsonConverterFactory { public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) { var innerType = typeToConvert.GetGenericArguments()[0]; var innerConverter = options.GetConverter(innerType); return (JsonConverter)Activator.CreateInstance( typeof(Cvt<>).MakeGenericType(innerType), innerConverter )!; } public override bool CanConvert(Type typeToConvert) { return typeToConvert.IsGenericType && typeToConvert.GetGenericTypeDefinition() == typeof(OuterClass<>); } private class CvtExpected behavior
HandleNull == true
for value types by default, or public access toHandleNullOnRead
andHandleNullOnWrite
.Actual behavior
HandleNull == false
by default for value types.Regression?
No response
Known Workarounds
Configuration
In theory reproduces since the introduction of the HandleNull - from .NET 5. Tested on .NET 6.
Other information
No response