aboutsummaryrefslogtreecommitdiffhomepage
path: root/csharp/src/Google.Protobuf/JsonFormatter.cs
diff options
context:
space:
mode:
authorGravatar Jon Skeet <jonskeet@google.com>2016-04-08 13:22:42 +0100
committerGravatar Jon Skeet <jonskeet@google.com>2016-04-20 03:46:02 +0100
commit790f4c8e3743c28c30e6f052cb3f5535490c87e4 (patch)
tree8a24a46e7db71355c2ba56c3fd9cc9088a83aca5 /csharp/src/Google.Protobuf/JsonFormatter.cs
parent84ea2c7a81c69ce675d025074d6891a32ea3f629 (diff)
Use the original name in JSON formatting.
(JSON parsing already does the right thing.)
Diffstat (limited to 'csharp/src/Google.Protobuf/JsonFormatter.cs')
-rw-r--r--csharp/src/Google.Protobuf/JsonFormatter.cs45
1 files changed, 43 insertions, 2 deletions
diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs
index cbd9366c..73a4f64b 100644
--- a/csharp/src/Google.Protobuf/JsonFormatter.cs
+++ b/csharp/src/Google.Protobuf/JsonFormatter.cs
@@ -39,6 +39,7 @@ using Google.Protobuf.WellKnownTypes;
using System.IO;
using System.Linq;
using System.Collections.Generic;
+using System.Reflection;
namespace Google.Protobuf
{
@@ -420,9 +421,10 @@ namespace Google.Protobuf
}
else if (value is System.Enum)
{
- if (System.Enum.IsDefined(value.GetType(), value))
+ string name = OriginalEnumValueHelper.GetOriginalName(value);
+ if (name != null)
{
- WriteString(writer, value.ToString());
+ WriteString(writer, name);
}
else
{
@@ -877,5 +879,44 @@ namespace Google.Protobuf
TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry));
}
}
+
+ // Effectively a cache of mapping from enum values to the original name as specified in the proto file,
+ // fetched by reflection.
+ // The need for this is unfortunate, as is its unbounded size, but realistically it shouldn't cause issues.
+ private static class OriginalEnumValueHelper
+ {
+ // TODO: In the future we might want to use ConcurrentDictionary, at the point where all
+ // the platforms we target have it.
+ private static readonly Dictionary<System.Type, Dictionary<object, string>> dictionaries
+ = new Dictionary<System.Type, Dictionary<object, string>>();
+
+ internal static string GetOriginalName(object value)
+ {
+ var enumType = value.GetType();
+ Dictionary<object, string> nameMapping;
+ lock (dictionaries)
+ {
+ if (!dictionaries.TryGetValue(enumType, out nameMapping))
+ {
+ nameMapping = GetNameMapping(enumType);
+ dictionaries[enumType] = nameMapping;
+ }
+ }
+
+ string originalName;
+ // If this returns false, originalName will be null, which is what we want.
+ nameMapping.TryGetValue(value, out originalName);
+ return originalName;
+ }
+
+ private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
+ enumType.GetTypeInfo().DeclaredFields
+ .Where(f => f.IsStatic)
+ .ToDictionary(f => f.GetValue(null),
+ f => f.GetCustomAttributes<OriginalNameAttribute>()
+ .FirstOrDefault()
+ // If the attribute hasn't been applied, fall back to the name of the field.
+ ?.Name ?? f.Name);
+ }
}
}