Skip to content
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

Address edge scenarios with JsonSerializer's property visibility #37720

Merged
merged 5 commits into from
Jun 17, 2020

Conversation

layomia
Copy link
Contributor

@layomia layomia commented Jun 10, 2020

Contributes to fixing #37640. Will leave the issue open until the fix is confirmed in app compat. cc @DotNetAppCompatFeiWang

#36936 made a change so that the serializer ignores virtual properties when a derived property that hid them is ignored (with [JsonIgnore]) and there's a JSON property name collision.

The failing scenario in #37640 makes it clear that we need to ignore virtual properties when a derived property that hid them is ignored, whether or not there's a property name collision. This is to avoid serializing content that the caller explicitly marked to be ignored.

@@ -261,8 +261,8 @@ public static void VeryLargeAmountOfEnumsToSerialize()
// Use multiple threads to perhaps go over the soft limit of 64, but not by more than a couple.
Parallel.For(0, 8, i => JsonSerializer.Serialize((MyEnum)(46 + i), options));

// Write the remaining enum values. We should not store any more values in
// the cache. If we do, we may throw OutOfMemoryException on some machines.
// Write the remaining enum values. The cache is capped to avoid
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following up on #37710 (comment).

@steveharter
Copy link
Member

Are the current semantics in this PR consistent with Newtonsoft?

@layomia layomia force-pushed the ignore_hidden_properties branch from d5b6fa0 to b121ea8 Compare June 15, 2020 22:21
@layomia layomia force-pushed the ignore_hidden_properties branch from b121ea8 to 766572f Compare June 15, 2020 22:50
@layomia
Copy link
Contributor Author

layomia commented Jun 15, 2020

Are the current semantics in this PR consistent with Newtonsoft?

With the latest commit, we are largely aligned with Newtonsoft.Json behavior.

  • If an override of a virtual property is [JsonIgnore]d, then the property is ignored as well.

string serialized = JsonSerializer.Serialize(new DerivedClass_With_IgnoredOverride());
Assert.Equal(@"{}", serialized);

  • If a property that hides a virtual or non-virtual property is [JsonIgnore]d, and there's no property name collision, then the hidden property is included for (de)serialization.

serialized = JsonSerializer.Serialize(new DerivedClass_With_Ignored_NewProperty());
Assert.Equal(@"{""MyProp"":false}", serialized);

  • If a property that hides a virtual or non-virtual property is [JsonIgnore]d, and there's a property name collision between a non-ignored property and the hidden property, then the hidden property is ignored, while the non-ignored property is included for (de)serialization

serialized = JsonSerializer.Serialize(new DerivedClass_With_NewProperty_And_ConflictingPropertyName());
Assert.Equal(@"{""MyProp"":null}", serialized);

wrt. how we differ - in Newtonsoft.Json, property name conflicts at different type-hierarchy levels that are not caused by deriving or the new keyword are allowed. So, properties on more derived types win. In System.Text.Json, property name conflicts are only valid when caused by deriving or the new keyword.

Assert.Throws<InvalidOperationException>(() => JsonSerializer.Serialize(new DerivedClass_WithConflictingPropertyName()));

@layomia layomia changed the title Ignore hidden properties that were JsonIgnore'd in a more derived type Address edge scenarios with JsonSerializer's property visibility Jun 15, 2020
@steveharter
Copy link
Member

wrt. how we differ - in Newtonsoft.Json, property name conflicts at different type-hierarchy levels that are not caused by deriving or the new keyword are allowed. So, properties on more derived types win. In System.Text.Json, property name conflicts are only valid when caused by deriving or the new keyword.

This means all CLR naming "conflicts" are OK, but naming conflicts through [JsonPropertyName] are not?

@@ -4,6 +4,7 @@

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary (I didn't see any use of nullability attributes)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No - will remove. I used a nullability attribute in a helper in an earlier iteration of this change.

@layomia
Copy link
Contributor Author

layomia commented Jun 16, 2020

This means all CLR naming "conflicts" are OK, but naming conflicts through [JsonPropertyName] are not?

Yes. [JsonPropertyName] and also JsonNamingPolicy.

@DotNetAppCompatFeiWang
Copy link

cc @dotnet-actwx-bot

@layomia layomia merged commit 644f32d into dotnet:master Jun 17, 2020
@layomia layomia deleted the ignore_hidden_properties branch June 17, 2020 13:29
@ghost ghost locked as resolved and limited conversation to collaborators Dec 8, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants