Make json_name take priority over name (fully) in C# parsing (#12262)

Fixes #11987

(testprotos.pb and UnittestIssues.pb.cs are both generated; no need to review.)

Closes #12262

COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/12262 from jskeet:json-mapping 95785247b7
PiperOrigin-RevId: 518186721
pull/12295/head
Jon Skeet 2 years ago committed by Copybara-Service
parent 38ab857472
commit 4326e0f852
  1. 64
      csharp/protos/unittest_issues.proto
  2. 12
      csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
  3. 6
      csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs

@ -33,24 +33,25 @@ syntax = "proto3";
// These proto descriptors have at one time been reported as an issue or defect. // These proto descriptors have at one time been reported as an issue or defect.
// They are kept here to replicate the issue, and continue to verify the fix. // They are kept here to replicate the issue, and continue to verify the fix.
// Issue: Non-"Google.Protobuffers" namespace will ensure that protobuffer library types are qualified // Issue: Non-"Google.Protobuffers" namespace will ensure that protobuffer
option csharp_namespace = "UnitTest.Issues.TestProtos"; // library types are qualified
package unittest_issues; package unittest_issues;
import "google/protobuf/struct.proto"; import "google/protobuf/struct.proto";
option csharp_namespace = "UnitTest.Issues.TestProtos";
// Issue 307: when generating doubly-nested types, any references // Issue 307: when generating doubly-nested types, any references
// should be of the form A.Types.B.Types.C. // should be of the form A.Types.B.Types.C.
message Issue307 { message Issue307 {
message NestedOnce { message NestedOnce {
message NestedTwice { message NestedTwice {}
}
} }
} }
// Old issue 13: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=13 // Old issue 13:
// New issue 309: https://github.com/protocolbuffers/protobuf/issues/309 // http://code.google.com/p/protobuf-csharp-port/issues/detail?id=13 New issue
// 309: https://github.com/protocolbuffers/protobuf/issues/309
// message A { // message A {
// optional int32 _A = 1; // optional int32 _A = 1;
@ -60,9 +61,9 @@ message Issue307 {
// optional int32 B_ = 1; // optional int32 B_ = 1;
// } // }
//message AB { // message AB {
// optional int32 a_b = 1; // optional int32 a_b = 1;
//} // }
// Similar issue with numeric names // Similar issue with numeric names
// Java code failed too, so probably best for this to be a restriction. // Java code failed too, so probably best for this to be a restriction.
@ -74,39 +75,40 @@ message Issue307 {
// issue 19 - negative enum values // issue 19 - negative enum values
enum NegativeEnum { enum NegativeEnum {
NEGATIVE_ENUM_ZERO = 0; NEGATIVE_ENUM_ZERO = 0;
FiveBelow = -5; FiveBelow = -5;
MinusOne = -1; MinusOne = -1;
} }
message NegativeEnumMessage { message NegativeEnumMessage {
NegativeEnum value = 1; NegativeEnum value = 1;
repeated NegativeEnum values = 2 [packed = false]; repeated NegativeEnum values = 2 [packed = false];
repeated NegativeEnum packed_values = 3 [packed=true]; repeated NegativeEnum packed_values = 3 [packed = true];
} }
// Issue 21: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=21 // Issue 21: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=21
// Decorate fields with [deprecated=true] as [System.Obsolete] // Decorate fields with [deprecated=true] as [System.Obsolete]
message DeprecatedChild { message DeprecatedChild {
option deprecated = true; option deprecated = true;
} }
enum DeprecatedEnum { enum DeprecatedEnum {
option deprecated = true; option deprecated = true;
DEPRECATED_ZERO = 0 [deprecated = true];
one = 1; DEPRECATED_ZERO = 0 [deprecated = true];
one = 1;
} }
message DeprecatedFieldsMessage { message DeprecatedFieldsMessage {
int32 PrimitiveValue = 1 [deprecated = true]; int32 PrimitiveValue = 1 [deprecated = true];
repeated int32 PrimitiveArray = 2 [deprecated = true]; repeated int32 PrimitiveArray = 2 [deprecated = true];
DeprecatedChild MessageValue = 3 [deprecated = true]; DeprecatedChild MessageValue = 3 [deprecated = true];
repeated DeprecatedChild MessageArray = 4 [deprecated = true]; repeated DeprecatedChild MessageArray = 4 [deprecated = true];
DeprecatedEnum EnumValue = 5 [deprecated = true]; DeprecatedEnum EnumValue = 5 [deprecated = true];
repeated DeprecatedEnum EnumArray = 6 [deprecated = true]; repeated DeprecatedEnum EnumArray = 6 [deprecated = true];
} }
// Issue 45: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=45 // Issue 45: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=45
@ -116,8 +118,7 @@ message ItemField {
message ReservedNames { message ReservedNames {
// Force a nested type called Types // Force a nested type called Types
message SomeNestedType { message SomeNestedType {}
}
int32 types = 1; int32 types = 1;
int32 descriptor = 2; int32 descriptor = 2;
@ -148,7 +149,6 @@ message TestJsonFieldOrdering {
int32 o2_int32 = 6; int32 o2_int32 = 6;
string o2_string = 3; string o2_string = 3;
} }
} }
message TestJsonName { message TestJsonName {
@ -218,3 +218,9 @@ message DisambiguateCommonMembers {
int32 on_construction = 11; int32 on_construction = 11;
int32 parser = 12; int32 parser = 12;
} }
message Issue11987Message {
int32 a = 1 [json_name = 'b'];
int32 b = 2 [json_name = 'a'];
int32 c = 3 [json_name = 'd'];
}

@ -630,6 +630,18 @@ namespace Google.Protobuf
Assert.AreEqual(expectedJson, JsonFormatter.Default.Format(populated)); Assert.AreEqual(expectedJson, JsonFormatter.Default.Format(populated));
} }
// See See https://github.com/protocolbuffers/protobuf/issues/11987
[Test]
public void JsonNamePriority()
{
// This tests both the formatter and the parser, but the issue was when parsing.
var original = new Issue11987Message { A = 10, B = 20, C = 30 };
var json = JsonFormatter.Default.Format(original);
AssertJson("{ 'b': 10, 'a': 20, 'd': 30 }", json);
var parsed = Issue11987Message.Parser.ParseJson(json);
Assert.AreEqual(original, parsed);
}
// Sanity tests for WriteValue. Not particularly comprehensive, as it's all covered above already, // Sanity tests for WriteValue. Not particularly comprehensive, as it's all covered above already,
// as FormatMessage uses WriteValue. // as FormatMessage uses WriteValue.

@ -117,9 +117,15 @@ namespace Google.Protobuf.Reflection
private static ReadOnlyDictionary<string, FieldDescriptor> CreateJsonFieldMap(IList<FieldDescriptor> fields) private static ReadOnlyDictionary<string, FieldDescriptor> CreateJsonFieldMap(IList<FieldDescriptor> fields)
{ {
var map = new Dictionary<string, FieldDescriptor>(); var map = new Dictionary<string, FieldDescriptor>();
// The ordering is important here: JsonName takes priority over Name,
// which means we need to put JsonName values in the map after *all*
// Name keys have been added. See https://github.com/protocolbuffers/protobuf/issues/11987
foreach (var field in fields) foreach (var field in fields)
{ {
map[field.Name] = field; map[field.Name] = field;
}
foreach (var field in fields)
{
map[field.JsonName] = field; map[field.JsonName] = field;
} }
return new ReadOnlyDictionary<string, FieldDescriptor>(map); return new ReadOnlyDictionary<string, FieldDescriptor>(map);

Loading…
Cancel
Save