-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add JSON type hierarchies #67961
Add JSON type hierarchies #67961
Conversation
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsThis PR implements polymorphism for System.Text.Json as a preview feature. Walkthrough of Changes
Contributes to #63747.
|
src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
Outdated
Show resolved
Hide resolved
...s/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonPolymorphicAttribute.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ConfigurationList.cs
Show resolved
Hide resolved
...ext.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonCollectionConverter.cs
Show resolved
Hide resolved
...ests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets
Show resolved
Hide resolved
...s/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonDerivedTypeAttribute.cs
Show resolved
Hide resolved
...s/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonDerivedTypeAttribute.cs
Show resolved
Hide resolved
Please share the benchmarks and analysis of that. |
Is it feasible in 7.0 to add a new converter model that supports this polymorphic feature (and the host of all the other requests?). |
Is it feasible in 7.0 to support this polymorphic feature with source-gen? |
...s/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonPolymorphicAttribute.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj
Outdated
Show resolved
Hide resolved
...xt.Json/tests/System.Text.Json.Tests/Serialization/PolymorphicTests.CustomTypeHierarchies.cs
Show resolved
Hide resolved
Yes, this is included in the acceptance criteria for the contract mode (#63686)
This PR incorporates support for metadata-based source-gen. |
...raries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.MetadataHandling.cs
Show resolved
Hide resolved
Current.PolymorphicJsonTypeInfo = Current.JsonTypeInfo; | ||
Current.JsonTypeInfo = derivedJsonTypeInfo.PropertyInfoForTypeInfo.JsonTypeInfo; | ||
Current.JsonPropertyInfo = Current.JsonTypeInfo.PropertyInfoForTypeInfo; | ||
Current.NumberHandling ??= Current.JsonPropertyInfo.NumberHandling; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't this mean the base type will take precedence over derived type? should this be something like:
Current.NumberHandling = Current.JsonPropertyInfo.NumberHandling ?? Current.NumberHandling;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or just simply Current.NumberHandling = Current.JsonPropertyInfo.EffectiveNumberHandling
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, but that probably needs to consult the parent number handling as happens in the Push
operation:
Current.NumberHandling = Parent.NumberHandling ?? Current.JsonPropertyInfo.EffectiveNumberHandling;
Strange, I thought I had changed this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Current.JsonPropertyInfo.NumberHandling ?? parent.EffectiveNumberHandling
- note that EffectiveNumberHandling already takes options, declaring type etc into consideration
Debug.Assert(Current.PolymorphicSerializationState == PolymorphicSerializationState.PolymorphicReEntrySuspended); | ||
|
||
// Swap out the two values as we resume the polymorphic converter | ||
(Current.JsonTypeInfo, Current.PolymorphicJsonTypeInfo) = (Current.PolymorphicJsonTypeInfo, Current.JsonTypeInfo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does that mean the PolymorphicJsonTypeInfo
changes semantic meaning to OriginalJsonTypeInfo
here? can you add a comment why we do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Motivation is minimizing the amount of additional reference type fields we're adding to the stackframe struct. Doing this without swapping would require two additional pointers, which would contribute to the further bloating of the struct. The concern is that this would make the Push()
and Pop()
operations more expensive in a non pay-for-play way. I'll see if I can add a comment explaining this.
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/WriteStack.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/WriteStack.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs
Show resolved
Hide resolved
[InlineData(typeof(Interface))] | ||
[InlineData(typeof(Class))] | ||
[InlineData(typeof(GenericClass<int>))] | ||
public static void SupportedBaseTypeArgument_ShouldSucced(Type baseType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Succeed
...xt.Json/tests/System.Text.Json.Tests/Serialization/PolymorphicTests.CustomTypeHierarchies.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm conditionally approving this:
- mostly looks good, I've put feedback on whatever I feel might cause any issues but that won't affect functionality and can be addressed later
- couple of nits
- please file issue for anything remaining and make sure to address it after snap
{ | ||
JsonEncodedText jsonEncodedName = JsonEncodedText.Encode(customPropertyName, options.Encoder); | ||
|
||
// Check if the property name conflicts with other metadata property names |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we opening ourselves up to breaking user apps in the future if they use a custom metadata tag that's unused in STJ
now but then used in future releases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't think so, this particular code path is only exercised for types that have explicitly opted into polymorphism which is new functionality.
Understood now, we might need to be careful about how to deal with that should new metadata names be added in the future. We might want to relax that check so that it only throws for conflicts in metadata properties that are opted in for the particular type.
* Add JSON type hierarchies as a preview feature. * fix incorrect preview features configuration in ref project * Add check for conflicting custom type discriminator property names. * Add null checks & tests to public APIs * fix typo in constant name * fix file ordering * address feedback * Remove preview features annotation from new APIs
@eiriktsarpalis do you expect any perf impact from this? It's possible the regression we see here is related: dotnet/perf-autofiling-issues#4894. Also regression seen in
Note we may be duplicate filing some of these. |
Performance regressions as a result of this change are likely (and potentially unavoidable), particularly on the deserialization side of things. When running benchmarks locally I wasn't able to isolate any clear-cut regressions, but I'll investigate this and any other reports coming from the autofiler. |
This might be the cause of some more regressions on all configs (see details). System.Text.Json.Tests.Perf_Get.GetBoolean
|
It's unlikely that these changes would impact the specific microbenchmarks, since they're measuring the |
That's always a possibility, so let's dig in a bit. Recent history for The first of these on 4/19 corresponds to 544f720...4881a63 Looking over that list again there seem to be two JSON related changes; none of the others seem relevant. The second regression on 4/26-27 is harder to pin down, it looks like we didn't have great perf coverage and so there is a wide commit range: a077f27...9342649 If we look at other platforms to see if they also regressed, we see Unix x64 -- similar pattern but missing data around the point of the first regression Ubuntu arm64 probably too noisy to tell, also an outage Windows arm64 sees the first regression, commit range f1e10a5...6c7ce85 overlaps with windows x64, and contains both those JSON changes So it sure seems like it's one of those two changes causing that first regression. The second one I'm not sure about. |
I very much agree that this PR is most probably responsible for some of the regressions in the |
Ah, ok. Let's look at that case.
Looking at the auto-filing report, I see that it's actually measuring Mono perf and not CoreCLR. So nothing to worry about from this second issue. Sorry for the false alarm. |
This PR implements polymorphism for System.Text.Json as a preview feature.
Walkthrough of Changes
JsonDerivedTypeAttribute
andJsonPolymorphicAttribute
types for configuring polymorphism using attributes.JsonPolymorphicTypeConfiguration
class for configuring polymorphism without attributes.JsonSerializerOptions.PolymorphicTypeConfiguration
property. Used as a temporary configuration entry point until Developers can customize the JSON serialization contracts of their types #63686 has been implemented.System.Object
types to arbitrary classes and interfaces (cf.JsonConverter.MetadataHandling.cs
,WriteStack.cs
).ObjectDefaultConverter
,ObjectWithParameterizedConstructorConverter
,JsonCollectionConverter
andJsonDictionaryConverter
.PolymorphicTypeResolver.cs
validates polymorphic type configuration and provides an entrypoint for mapping runtime types/type discriminators to derivedJsonTypeInfo
metadata.JsonSerializerContext
and a diagnostic warning is emitted forJsonSourceGenerationMode.Serialization
.Contributes to #63747.