Skip to content

Commit 9d44553

Browse files
committed
PR feedback
1 parent 02cd7f7 commit 9d44553

File tree

3 files changed

+37
-39
lines changed

3 files changed

+37
-39
lines changed

src/Grpc/JsonTranscoding/src/Microsoft.AspNetCore.Grpc.JsonTranscoding/GrpcJsonSettings.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ public sealed class GrpcJsonSettings
5050
/// }
5151
/// </code>
5252
/// <para>
53-
/// When <see cref="RemoveEnumPrefix"/> is set to <see langword="true"/>, the enum values above
54-
/// will be read and written as <c>UNKNOWN</c> and <c>OK</c> instead of <c>STATUS_UNKNOWN</c>
53+
/// <c>STATUS</c> prefix is removed from enum values when <see cref="RemoveEnumPrefix"/> is set to <see langword="true"/>.
54+
/// The enum values above will be read and written as <c>UNKNOWN</c> and <c>OK</c> instead of <c>STATUS_UNKNOWN</c>
5555
/// and <c>STATUS_OK</c>.
5656
/// </para>
5757
/// </remarks>

src/Grpc/JsonTranscoding/src/Microsoft.AspNetCore.Grpc.JsonTranscoding/Internal/Json/EnumConverter.cs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,12 @@ public EnumConverter(JsonContext context) : base(context)
2020
switch (reader.TokenType)
2121
{
2222
case JsonTokenType.String:
23-
var enumDescriptor = (EnumDescriptor?)Context.DescriptorRegistry.FindDescriptorByType(typeToConvert);
24-
if (enumDescriptor == null)
25-
{
26-
throw new InvalidOperationException($"Unable to resolve descriptor for {typeToConvert}.");
27-
}
23+
var enumDescriptor = (EnumDescriptor?)Context.DescriptorRegistry.FindDescriptorByType(typeToConvert)
24+
?? throw new InvalidOperationException($"Unable to resolve descriptor for {typeToConvert}.");
2825

2926
var value = reader.GetString()!;
30-
var valueDescriptor = JsonNamingHelpers.GetEnumFieldReadValue(enumDescriptor, value, Context.Settings);
31-
if (valueDescriptor == null)
32-
{
33-
throw new InvalidOperationException(@$"Error converting value ""{value}"" to enum type {typeToConvert}.");
34-
}
27+
var valueDescriptor = JsonNamingHelpers.GetEnumFieldReadValue(enumDescriptor, value, Context.Settings)
28+
?? throw new InvalidOperationException(@$"Error converting value ""{value}"" to enum type {typeToConvert}.");
3529

3630
return ConvertFromInteger(valueDescriptor.Number);
3731
case JsonTokenType.Number:
@@ -51,11 +45,8 @@ public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOpt
5145
}
5246
else
5347
{
54-
var enumDescriptor = (EnumDescriptor?)Context.DescriptorRegistry.FindDescriptorByType(value.GetType());
55-
if (enumDescriptor == null)
56-
{
57-
throw new InvalidOperationException($"Unable to resolve descriptor for {value.GetType()}.");
58-
}
48+
var enumDescriptor = (EnumDescriptor?)Context.DescriptorRegistry.FindDescriptorByType(value.GetType())
49+
?? throw new InvalidOperationException($"Unable to resolve descriptor for {value.GetType()}.");
5950

6051
var name = JsonNamingHelpers.GetEnumFieldWriteName(enumDescriptor, value, Context.Settings);
6152
if (name != null)

src/Grpc/JsonTranscoding/src/Microsoft.AspNetCore.Grpc.JsonTranscoding/Internal/Json/EnumNameHelpers.cs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,44 +48,50 @@ internal static class JsonNamingHelpers
4848

4949
private static EnumMapping GetEnumMapping(EnumDescriptor enumDescriptor)
5050
{
51-
var enumType = enumDescriptor.ClrType;
52-
53-
EnumMapping? enumMapping;
54-
lock (_enumMappings)
55-
{
56-
if (!_enumMappings.TryGetValue(enumType, out enumMapping))
57-
{
58-
_enumMappings[enumType] = enumMapping = GetEnumMapping(enumDescriptor.Name, enumType);
59-
}
60-
}
61-
62-
return enumMapping;
51+
return _enumMappings.GetOrAdd(
52+
enumDescriptor.ClrType,
53+
static (t, descriptor) => GetEnumMapping(descriptor.Name, t),
54+
enumDescriptor);
6355
}
6456

6557
private static EnumMapping GetEnumMapping(string enumName, Type enumType)
6658
{
67-
var enumFields = enumType.GetTypeInfo().DeclaredFields
59+
var nameMappings = enumType.GetTypeInfo().DeclaredFields
6860
.Where(f => f.IsStatic)
6961
.Where(f => f.GetCustomAttributes<OriginalNameAttribute>().FirstOrDefault()?.PreferredAlias ?? true)
70-
.ToList();
71-
72-
var writeMapping = enumFields.ToDictionary(
73-
f => f.GetValue(null)!,
74-
f =>
62+
.Select(f =>
7563
{
7664
// If the attribute hasn't been applied, fall back to the name of the field.
7765
var fieldName = f.GetCustomAttributes<OriginalNameAttribute>().FirstOrDefault()?.Name ?? f.Name;
7866

7967
return new NameMapping
8068
{
69+
Value = f.GetValue(null)!,
8170
OriginalName = fieldName,
8271
RemoveEnumPrefixName = GetEnumValueName(enumName, fieldName)
8372
};
84-
});
73+
})
74+
.ToList();
8575

86-
var removeEnumPrefixMapping = writeMapping.Values.ToDictionary(
87-
m => m.RemoveEnumPrefixName,
88-
m => m.OriginalName);
76+
var writeMapping = nameMappings.ToDictionary(m => m.Value, m => m);
77+
78+
// Protobuf codegen prevents collision of enum names when the prefix is removed.
79+
// For example, the following enum will fail to build because both fields would resolve to "OK":
80+
//
81+
// enum Status {
82+
// STATUS_OK = 0;
83+
// OK = 1;
84+
// }
85+
//
86+
// Tooling error message:
87+
// ----------------------
88+
// Enum name OK has the same name as STATUS_OK if you ignore case and strip out the enum name prefix (if any).
89+
// (If you are using allow_alias, please assign the same number to each enum value name.)
90+
//
91+
// Just in case it does happen, map to the first value rather than error.
92+
var removeEnumPrefixMapping = nameMappings
93+
.GroupBy(m => m.RemoveEnumPrefixName)
94+
.ToDictionary(g => g.Key, g => g.First().OriginalName, StringComparer.Ordinal);
8995

9096
return new EnumMapping { WriteMapping = writeMapping, RemoveEnumPrefixMapping = removeEnumPrefixMapping };
9197
}
@@ -146,6 +152,7 @@ private sealed class EnumMapping
146152

147153
private sealed class NameMapping
148154
{
155+
public required object Value { get; init; }
149156
public required string OriginalName { get; init; }
150157
public required string RemoveEnumPrefixName { get; init; }
151158
}

0 commit comments

Comments
 (0)