Skip to content

Address edge scenarios with JsonSerializer's property visibility - #37720

Merged
layomia merged 5 commits into
dotnet:masterfrom
layomia:ignore_hidden_properties
Jun 17, 2020
Merged

Address edge scenarios with JsonSerializer's property visibility#37720
layomia merged 5 commits into
dotnet:masterfrom
layomia:ignore_hidden_properties

Conversation

@layomia

@layomialayomia commented Jun 10, 2020

Copy link
Copy Markdown
Contributor

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.


// 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
Copy Markdown
ContributorAuthor

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
Copy Markdown
Contributor

Are the current semantics in this PR consistent with Newtonsoft?

@layomia
layomiaforce-pushed the ignore_hidden_properties branch from d5b6fa0 to b121ea8CompareJune 15, 2020 22:21
@layomia
layomiaforce-pushed the ignore_hidden_properties branch from b121ea8 to 766572fCompareJune 15, 2020 22:50
@layomia

Copy link
Copy Markdown
ContributorAuthor

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.

stringserialized=JsonSerializer.Serialize(newDerivedClass_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(newDerivedClass_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(newDerivedClass_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(newDerivedClass_WithConflictingPropertyName()));

@layomialayomia changed the title Ignore hidden properties that were JsonIgnore'd in a more derived typeAddress edge scenarios with JsonSerializer's property visibilityJun 15, 2020
@steveharter

Copy link
Copy Markdown
Contributor

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?


using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

Copy link
Copy Markdown
Contributor

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
Copy Markdown
ContributorAuthor

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
Copy Markdown
ContributorAuthor

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

Yes. [JsonPropertyName] and also JsonNamingPolicy.

@DotNetAppCompatFeiWang

Copy link
Copy Markdown

cc @dotnet-actwx-bot

@layomia
layomia merged commit 644f32d into dotnet:masterJun 17, 2020
@layomia
layomia deleted the ignore_hidden_properties branch June 17, 2020 13:29
@ghostghost locked as resolved and limited conversation to collaborators Dec 8, 2020
Sign up for freeto 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

@layomia@steveharter@DotNetAppCompatFeiWang