-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Honor naming policy for string enum deserialization #73348
Conversation
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsFixes #31619. Only the first 64 values of a given enum are supported. Flags are not supported.
|
src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
// todo: optimize implementation here by leveraging https://github.com/dotnet/runtime/issues/934. | ||
string[] enumValues = enumString.Split( | ||
#if BUILDING_INBOX_LIBRARY | ||
ValueSeparator |
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.
FWIW it is possible for enum identifiers to contain commas in IL, but the good news is that not even the Enum parser is able to handle that:
We might want to store a flag indicating that the enum contains commas and fail early, rather than attempt to pass bogus tokens into the naming policy. (FWIW this is a very niche use case)
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.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.
LGTM other than a few pending issues.
/// <summary> | ||
/// Holds a mapping from enum value to text that might be formatted with <see cref="_namingPolicy" />. | ||
/// </summary> | ||
private readonly ConcurrentDictionary<ulong, JsonEncodedText> _nameCacheForWriting; |
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.
is converter the right place for this? could converter be potentially re-used in place with different naming policy? Would it make sense to move this to JsonTypeInfo and cache all possible values beforehand (i.e. in Configure method) and then use regular Dictionary since I believe just lookup is thread-safe?
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.
could converter be potentially re-used in place with different naming policy?
I don't believe so.
Would it make sense to move this to JsonTypeInfo and cache all possible values beforehand
The enum converter might be applied to enum types or specific properties. Placing on enum JsonTypeInfo
s would satisfy only the former.
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.
Might be good to still pre-cache all values in the constructor since that won't require to use concurrent dictionary but consider this feedback optional
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.
also another alternative to put the caching both on JsonPropertyInfo and JsonTypeInfo but if JsonPropertyInfo uses JsonTypeInfo's dictionary then you can re-use the same dictionary but assuming JsonConverter is unique per JsonTypeInfo/JsonPropertyInfo consider this optional
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.
hmm.. seems prepopulating might not work due to combinations of flags
feeb953
to
7fa3ce9
Compare
|
||
private static string[] SplitFlagsEnum(string value) | ||
{ | ||
// todo: optimize implementation here by leveraging https://github.com/dotnet/runtime/issues/934. |
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.
consider adding [ActiveIssue("https://github.com/dotnet/runtime/issues/934")]
in the comment for easier grepping
""static"": 2 | ||
}"; | ||
|
||
JsonTestHelper.AssertJsonEqual(expected, JsonSerializer.Serialize(dict, options)); |
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.
you might want to validate deserialization behavior here as well (throw or roundtrip)
} | ||
|
||
[Fact] | ||
public static void EnumDictionaryKeyDeserialization() |
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'd just joing those two tests (this and below) into one since they test the same concept and are mostly the same
} | ||
|
||
[Fact] | ||
public static void EnumDictionaryKeySerialization() |
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.
add a test where enum converter (set through options) and properties have different naming policy and make sure both scenarios serialize/deserialize correctly when using same options
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.
Sounds good. It's essentially a test that the converter precedence rules hold (property-level converter wins over type-level), but the redundancy is good.
}; | ||
|
||
string expected = @"{ | ||
""public, non_public"": 1, |
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.
curious is ", "
considered something user might want to customize? should we create issue to customize serparator? or possibly some enum specific option on naming policy
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.
It's an interesting idea but I haven't seen anyone ask or any precedent for it. I wouldn't it pursue without a customer ask.
/// <see cref="ulong"/> is as the key used rather than <typeparamref name="T"/> given measurements that | ||
/// show private memory savings when a single type is used https://github.com/dotnet/runtime/pull/36726#discussion_r428868336. | ||
/// </summary> | ||
private readonly ConcurrentDictionary<ulong, JsonEncodedText> _nameCacheForWriting; |
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.
consider renaming:
_nameToEnumValueCache
_enumValueToNameCache
@krwq I'll get this fix in & address test feedback in a follow up. |
@layomia Thank you for your hard work on this! |
Fixes #31619.