mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-09 17:44:48 +09:00
[release/9.0-staging] Fix case-insensitive JSON deserialization of enum member names (#112057)
* Fix case-insensitive deserialization of default enum values * renaming * Update comment --------- Co-authored-by: Pranav Senthilnathan <pranas@microsoft.com>
This commit is contained in:
parent
e08ac0ec15
commit
33a063585d
2 changed files with 74 additions and 3 deletions
|
@ -601,9 +601,9 @@ namespace System.Text.Json.Serialization.Converters
|
|||
{
|
||||
Debug.Assert(JsonName.Equals(other.JsonName, StringComparison.OrdinalIgnoreCase), "The conflicting entry must be equal up to case insensitivity.");
|
||||
|
||||
if (Kind is EnumFieldNameKind.Default || JsonName.Equals(other.JsonName, StringComparison.Ordinal))
|
||||
if (ConflictsWith(this, other))
|
||||
{
|
||||
// Silently discard if the preceding entry is the default or has identical name.
|
||||
// Silently discard if the new entry conflicts with the preceding entry
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -612,13 +612,34 @@ namespace System.Text.Json.Serialization.Converters
|
|||
// Walk the existing list to ensure we do not add duplicates.
|
||||
foreach (EnumFieldInfo conflictingField in conflictingFields)
|
||||
{
|
||||
if (conflictingField.Kind is EnumFieldNameKind.Default || conflictingField.JsonName.Equals(other.JsonName, StringComparison.Ordinal))
|
||||
if (ConflictsWith(conflictingField, other))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
conflictingFields.Add(other);
|
||||
|
||||
// Determines whether the first field info matches everything that the second field info matches,
|
||||
// in which case the second field info is redundant and doesn't need to be added to the list.
|
||||
static bool ConflictsWith(EnumFieldInfo current, EnumFieldInfo other)
|
||||
{
|
||||
// The default name matches everything case-insensitively.
|
||||
if (current.Kind is EnumFieldNameKind.Default)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// current matches case-sensitively since it's not the default name.
|
||||
// other matches case-insensitively, so it matches more than current.
|
||||
if (other.Kind is EnumFieldNameKind.Default)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both are case-sensitive so they need to be identical.
|
||||
return current.JsonName.Equals(other.JsonName, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
public EnumFieldInfo? GetMatchingField(ReadOnlySpan<char> input)
|
||||
|
|
|
@ -1207,5 +1207,55 @@ namespace System.Text.Json.Serialization.Tests
|
|||
[JsonStringEnumMemberName("Comma separators not allowed, in flags enums")]
|
||||
Value
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.SnakeCaseUpper)]
|
||||
[InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.SnakeCaseLower)]
|
||||
[InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.KebabCaseUpper)]
|
||||
[InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.KebabCaseLower)]
|
||||
[InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.SnakeCaseUpper)]
|
||||
[InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.SnakeCaseLower)]
|
||||
[InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.KebabCaseUpper)]
|
||||
[InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.KebabCaseLower)]
|
||||
[InlineData("\"sNaKe_CaSe_UpPeR\"", EnumWithVaryingNamingPolicies.SNAKE_CASE_UPPER, JsonKnownNamingPolicy.SnakeCaseUpper)]
|
||||
[InlineData("\"sNaKe_CaSe_LoWeR\"", EnumWithVaryingNamingPolicies.snake_case_lower, JsonKnownNamingPolicy.SnakeCaseLower)]
|
||||
[InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.CamelCase)]
|
||||
[InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.CamelCase)]
|
||||
[InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.SnakeCaseUpper)]
|
||||
[InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.SnakeCaseLower)]
|
||||
[InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.KebabCaseUpper)]
|
||||
[InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.KebabCaseLower)]
|
||||
[InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.CamelCase)]
|
||||
[InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.SnakeCaseUpper)]
|
||||
[InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.SnakeCaseLower)]
|
||||
[InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.KebabCaseUpper)]
|
||||
[InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.KebabCaseLower)]
|
||||
public static void StringConverterWithNamingPolicyIsCaseInsensitive(string json, EnumWithVaryingNamingPolicies expectedValue, JsonKnownNamingPolicy namingPolicy)
|
||||
{
|
||||
JsonNamingPolicy policy = namingPolicy switch
|
||||
{
|
||||
JsonKnownNamingPolicy.CamelCase => JsonNamingPolicy.CamelCase,
|
||||
JsonKnownNamingPolicy.SnakeCaseLower => JsonNamingPolicy.SnakeCaseLower,
|
||||
JsonKnownNamingPolicy.SnakeCaseUpper => JsonNamingPolicy.SnakeCaseUpper,
|
||||
JsonKnownNamingPolicy.KebabCaseLower => JsonNamingPolicy.KebabCaseLower,
|
||||
JsonKnownNamingPolicy.KebabCaseUpper => JsonNamingPolicy.KebabCaseUpper,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(namingPolicy)),
|
||||
};
|
||||
|
||||
JsonSerializerOptions options = new() { Converters = { new JsonStringEnumConverter(policy) } };
|
||||
|
||||
EnumWithVaryingNamingPolicies value = JsonSerializer.Deserialize<EnumWithVaryingNamingPolicies>(json, options);
|
||||
Assert.Equal(expectedValue, value);
|
||||
}
|
||||
|
||||
public enum EnumWithVaryingNamingPolicies
|
||||
{
|
||||
SNAKE_CASE_UPPER,
|
||||
snake_case_lower,
|
||||
camelCase,
|
||||
PascalCase,
|
||||
A,
|
||||
b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue