-
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
System.Text.Json: JsonStringEnumConverter ignores its JsonNamingPolicy during deserialization. #31619
Comments
Anyone looking for a workaround I have a JsonConverter named JsonStringEnumMemberConverter in Macross.Json.Extensions package which fixes this issue and then adds in support for EnumMemberAttribute & Nullable enums. A modified version of dotnet/corefx#41648, basically. |
Thanks a lot! I was stumbling against deserialization. |
I don't see how this can be addressed with the current API shape, as JsonNamingPolicy.ConvertName is potentially a one-way function. For instance, if you chose HashFunction(name) as the implementation, it's not possible to convert it back. The only way to support this would be to define something like WPF does with converters, where you have Convert and ConvertBack, but that seems to be functionality outside the scope of what System.Text.Json should do. |
|
Maybe create cache with source enum value names? And restore source name if exist namingPolicy? |
* Upgrade projects to the new "SDK style" csproj format * Remove the packages directory and packages.config file * Remove `AssemblyInfo.cs` files (replaced with equivalent csproj properties) * Remove `*.vsmdi` and `*.testsettings` files * Run tests on .NET Framework 4.7.2 + .NET Core 3.1 + .NET 5.0 * Update test dependencies to their latest version * Microsoft.NET.Test.Sdk → 16.9.4 * Moq → 4.16.1 * MSTest.TestAdapter → 2.2.3 * MSTest.TestFramework → 2.2.3 * Use `System.Text.Json` instead of `System.Web.Script.Serialization` * Use `JsonPropertyNameAttribute` instead of `FieldAttribute` * Make properties `{ get; init; }` instead of `{ get; internal set; }` with the help of the `IsExternalInit` NuGet package to support .NET Standard 2.0 * Define `EnumMember` attributes for all enums and use `JsonStringEnumMemberConverter` from the `Macross.Json.Extensions` NuGet package to workaround [issues in JsonStringEnumConverter](dotnet/runtime#31619) Fixes emmettnicholas#11
* Upgrade projects to the new "SDK style" csproj format * Remove the packages directory and packages.config file * Remove `AssemblyInfo.cs` files (replaced with equivalent csproj properties) * Remove `*.vsmdi` and `*.testsettings` files * Run tests on .NET Framework 4.7.2 + .NET Core 3.1 + .NET 5.0 * Update test dependencies to their latest version * Microsoft.NET.Test.Sdk → 16.9.4 * Moq → 4.16.1 * MSTest.TestAdapter → 2.2.3 * MSTest.TestFramework → 2.2.3 * Use `System.Text.Json` instead of `System.Web.Script.Serialization` * Use `JsonPropertyNameAttribute` instead of `FieldAttribute` * Make properties `{ get; init; }` instead of `{ get; internal set; }` with the help of the `IsExternalInit` NuGet package to support .NET Standard 2.0 * Define `JsonPropertyName` attributes for all enums and use `JsonStringEnumMemberConverter` from the `Macross.Json.Extensions` NuGet package to workaround [issues in JsonStringEnumConverter](dotnet/runtime#31619) Fixes emmettnicholas#11
For enums, you could actually convert back even with a one-way function. You would need to convert all possible enum values to their serialized form using JsonNamingPolicy.ConvertName and could then simply look up the value you want to deserialize. The only limitation is that the naming policy actually assigns distinct names to all enum values. |
Triage: per my comments in #42302 (review) I do not believe this feature is feasible. We'll close this issue. As a workaround, users can write custom converters for enums that can support a close set of naming-policy-transformed enum names and honor them on deserialization. @tdykstra let's consider providing an example in the JSON docs. |
Although I realize there are no good answers, I personally think the current solution of ignoring the naming convention for deserialization is more harmful and confusing than poor/missing Flags support. Again without numbers to back me up, I would expect it is relatively rare for a web APIs to use Flags encoding. That being said, I realize people are using STJ to store and retrieve locally generated data that might need Flags more commonly. Perhaps a compromise, provide Flags support with the performance fallback, but hidden behind a experimental/preview environment variable until a better solution can be found? Also, perhaps the limited space cache can be improved by switching to a simple LRU style cache that will avoid a performance "cliff" when the cache overflows. This might amortize the pain somewhat |
If I run the Main method of the sample and instead of using the custom converter I use the built-in JsonStringEnumConverter with JsonNamingPolicy.CamelCase, everything works correctly. What am I missing that the custom converter is required for?
|
@tdykstra I think it's working because we have logic trying case-insensitive matching for enum string values, which works well with PascalCase -> camelCase transformations. Can you try your repro using a policy such as snake_case - runtime/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.cs Lines 1887 to 1893 in 66ca474
|
That explains it, thanks! Snake case test cases work only with the custom converter. I'll update the docs. |
@layomia I am assuming there is a 0% chance of a fix for this making it into .NET 6. Is that assumption correct? |
Will this feature be in .Net6 sooner or later? |
We didn't get around to fixing this in time for .NET 6. It will be considered for .NET 7. |
* Upgrade projects to the new "SDK style" csproj format * Remove the packages directory and packages.config file * Remove `AssemblyInfo.cs` files (replaced with equivalent csproj properties) * Remove `*.vsmdi` and `*.testsettings` files * Run tests on .NET Framework 4.7.2 + .NET Core 3.1 + .NET 6.0 * Update test dependencies to their latest version * Microsoft.NET.Test.Sdk → 17.1.0 * Moq → 4.16.1 * MSTest.TestAdapter → 2.2.8 * MSTest.TestFramework → 2.2.8 * Use `System.Text.Json` instead of `System.Web.Script.Serialization` * Use `JsonPropertyNameAttribute` instead of `FieldAttribute` * Make properties `{ get; init; }` instead of `{ get; internal set; }` with the help of the `IsExternalInit` NuGet package to support .NET Standard 2.0 * Define `JsonPropertyName` attributes for all enums and use `JsonStringEnumMemberConverter` from the `Macross.Json.Extensions` NuGet package to workaround [issues in JsonStringEnumConverter](dotnet/runtime#31619) Fixes emmettnicholas#11
I also need this functionality. Seems silly to me that a naming policy would only apply on serialization and not deserialization. Seems like a massive oversight. Please fix this. |
In
System.Text.Json
in .Net Core 3.1, I can serialize an enum using a naming policy, however when I attempt to deserialize the same enum with a naming policy, the policy is ignored and an exception is thrown when the naming policy does anything beyond modifying the case of the enum value names.The issue can be reproduced as follows. Define the following simple snake case naming policy:
And the following enum:
Then attempting to round-trip values of
TestEnum
will fail during deserialization:The enum values are serialized with the naming policy successfully:
But deserialization throws this exception:
The problem seems to be that
JsonConverterEnum<T>.Read()
completely ignores the specified_namingPolicy
and simply callsEnum.TryParse()
:A close reading of the documentation here seems to imply that this is an intended limitation:
However the inconsistency and inability to round-trip with the same settings is an odd and unexpected restriction. Newtonsoft does not have this limitation -- it can round-trip enum values even when using
SnakeCaseNamingStrategy
.Demo fiddle here showing that Json.NET can round-trip enums using
SnakeCaseNamingStrategy
while System.Text.Json cannot do so withSnakeCaseNamingPolicy
.The text was updated successfully, but these errors were encountered: