浏览代码

protostream_objectwriter: fix bug when Any is directly embedded in a map.

This came up when trying to round-trip the JSON<->proto3 conversion for
Envoy's envoy.admin.v2alpha.ConfigDump
(https://github.com/envoyproxy/envoy/blob/b903c1dc984593f8e95e0569c1503dc5d85fbe34/api/envoy/admin/v2alpha/config_dump.proto#L29).

Validated fix on the Envoy code base and via the provided unit test.

Signed-off-by: Harvey Tuch <htuch@google.com>
Harvey Tuch 7 年之前
父节点
当前提交
2d31d0c706

+ 1 - 1
src/google/protobuf/util/internal/protostream_objectwriter.cc

@@ -534,7 +534,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
     Push("", Item::MESSAGE, false, false);
     Push("", Item::MESSAGE, false, false);
     ProtoWriter::RenderDataPiece("key",
     ProtoWriter::RenderDataPiece("key",
                                  DataPiece(name, use_strict_base64_decoding()));
                                  DataPiece(name, use_strict_base64_decoding()));
-    Push("value", Item::MESSAGE, true, false);
+    Push("value", IsAny(*Lookup("value")) ? Item::ANY : Item::MESSAGE, true, false);
 
 
     // Make sure we are valid so far after starting map fields.
     // Make sure we are valid so far after starting map fields.
     if (invalid_depth() > 0) return this;
     if (invalid_depth() > 0) return this;

+ 16 - 0
src/google/protobuf/util/internal/protostream_objectwriter_test.cc

@@ -1679,6 +1679,22 @@ TEST_P(ProtoStreamObjectWriterMapTest, RepeatedMapKeyTest) {
       ->EndObject();
       ->EndObject();
 }
 }
 
 
+TEST_P(ProtoStreamObjectWriterMapTest, AnyInMap) {
+  MapIn mm;
+  google::protobuf::DoubleValue d;
+  d.set_value(40.2);
+  (*mm.mutable_map_any())["foo"].PackFrom(d);
+  ow_->StartObject("")
+      ->StartObject("map_any")
+      ->StartObject("foo")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.DoubleValue")
+      ->RenderDouble("value", 40.2)
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(mm);
+}
+
 class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest {
 class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest {
  protected:
  protected:
   ProtoStreamObjectWriterAnyTest() {
   ProtoStreamObjectWriterAnyTest() {

+ 3 - 0
src/google/protobuf/util/internal/testdata/maps.proto

@@ -32,6 +32,8 @@ syntax = "proto3";
 
 
 package google.protobuf.testing;
 package google.protobuf.testing;
 
 
+import "google/protobuf/any.proto";
+
 // Top-level test cases proto used by MarshallingTest. See description
 // Top-level test cases proto used by MarshallingTest. See description
 // at the top of the class MarshallingTest for details on how to write
 // at the top of the class MarshallingTest for details on how to write
 // test cases.
 // test cases.
@@ -103,6 +105,7 @@ message MapIn {
   string other = 1;
   string other = 1;
   repeated string things = 2;
   repeated string things = 2;
   map<string, string> map_input = 3;
   map<string, string> map_input = 3;
+  map<string, google.protobuf.Any> map_any = 4;
 }
 }
 
 
 message MapOut {
 message MapOut {

+ 1 - 1
src/google/protobuf/util/json_util_test.cc

@@ -284,7 +284,7 @@ TEST_F(JsonUtilTest, ParsePrimitiveMapIn) {
   JsonPrintOptions print_options;
   JsonPrintOptions print_options;
   print_options.always_print_primitive_fields = true;
   print_options.always_print_primitive_fields = true;
   JsonParseOptions parse_options;
   JsonParseOptions parse_options;
-  EXPECT_EQ("{\"other\":\"\",\"things\":[],\"mapInput\":{}}",
+  EXPECT_EQ("{\"other\":\"\",\"things\":[],\"mapInput\":{},\"mapAny\":{}}",
             ToJson(message, print_options));
             ToJson(message, print_options));
   MapIn other;
   MapIn other;
   ASSERT_TRUE(FromJson(ToJson(message, print_options), &other, parse_options));
   ASSERT_TRUE(FromJson(ToJson(message, print_options), &other, parse_options));