diff options
| author | lavv17 <[email protected]> | 2024-02-15 13:16:43 +0300 | 
|---|---|---|
| committer | lavv17 <[email protected]> | 2024-02-15 13:36:35 +0300 | 
| commit | 524319c9b011a50744ee1c873e7292b615052cd6 (patch) | |
| tree | a7c52f035a4a86d558881e918a9526b37c405b8a /library/cpp/protobuf/json | |
| parent | cbb28d478883b8acc82a4f6e3f816eae1da92887 (diff) | |
support Any in Proto2Json
31e18f04efdf8642428d4ab8ec8c87b4101f5ff2
Diffstat (limited to 'library/cpp/protobuf/json')
| -rw-r--r-- | library/cpp/protobuf/json/config.h | 8 | ||||
| -rw-r--r-- | library/cpp/protobuf/json/proto2json_printer.cpp | 51 | ||||
| -rw-r--r-- | library/cpp/protobuf/json/proto2json_printer.h | 3 | ||||
| -rw-r--r-- | library/cpp/protobuf/json/ut/proto2json_ut.cpp | 16 | ||||
| -rw-r--r-- | library/cpp/protobuf/json/ut/test.proto | 5 | 
5 files changed, 79 insertions, 4 deletions
diff --git a/library/cpp/protobuf/json/config.h b/library/cpp/protobuf/json/config.h index eee047e155a..d17ac7b15b8 100644 --- a/library/cpp/protobuf/json/config.h +++ b/library/cpp/protobuf/json/config.h @@ -95,6 +95,9 @@ namespace NProtobufJson {          };          EStringifyNumbersMode StringifyNumbers = StringifyLongNumbersNever; +        /// Decode Any fields content +        bool ConvertAny = false; +          /// Custom field names generator.          TNameGenerator NameGenerator = {}; @@ -202,6 +205,11 @@ namespace NProtobufJson {              WriteNanAsString = value;              return *this;          } + +        TSelf& SetConvertAny(bool value) { +            ConvertAny = value; +            return *this; +        }      };  } diff --git a/library/cpp/protobuf/json/proto2json_printer.cpp b/library/cpp/protobuf/json/proto2json_printer.cpp index b2426f395a0..bf0f9eb60d4 100644 --- a/library/cpp/protobuf/json/proto2json_printer.cpp +++ b/library/cpp/protobuf/json/proto2json_printer.cpp @@ -2,6 +2,8 @@  #include "config.h"  #include "util.h" +#include <google/protobuf/any.pb.h> +#include <google/protobuf/dynamic_message.h>  #include <google/protobuf/util/time_util.h>  #include <library/cpp/protobuf/json/proto/enum_options.pb.h> @@ -210,6 +212,39 @@ namespace NProtobufJson {          return false;      } +    bool TProto2JsonPrinter::TryPrintAny(const Message& proto, IJsonOutput& json) { +        using namespace google::protobuf; + +        const FieldDescriptor* typeUrlField; +        const FieldDescriptor* valueField; +        if (!Any::GetAnyFieldDescriptors(proto, &typeUrlField, &valueField)) { +            return false; +        } +        const Reflection* const reflection = proto.GetReflection(); +        const TString& typeUrl = reflection->GetString(proto, typeUrlField); +        TString fullTypeName; +        if (!Any::ParseAnyTypeUrl(typeUrl, &fullTypeName)) { +            return false; +        } +        const Descriptor* const valueDesc = proto.GetDescriptor()->file()->pool()->FindMessageTypeByName(fullTypeName); +        if (!valueDesc) { +            return false; +        } +        DynamicMessageFactory factory; +        const THolder<Message> valueMessage{factory.GetPrototype(valueDesc)->New()}; +        const TString& serializedValue = reflection->GetString(proto, valueField); +        if (!valueMessage->ParseFromString(serializedValue)) { +            return false; +        } + +        json.BeginObject(); +        json.WriteKey("@type").Write(typeUrl); +        PrintFields(*valueMessage, json); +        json.EndObject(); + +        return true; +    } +      void TProto2JsonPrinter::PrintSingleField(const Message& proto,                                                const FieldDescriptor& field,                                                IJsonOutput& json, @@ -267,7 +302,11 @@ namespace NProtobufJson {                      if (Config.ConvertTimeAsString && HandleTimeConversion(reflection->GetMessage(proto, &field), json)) {                          break;                      } -                    Print(reflection->GetMessage(proto, &field), json); +                    const Message& msg = reflection->GetMessage(proto, &field); +                    if (Config.ConvertAny && TryPrintAny(msg, json)) { +                        break; +                    } +                    Print(msg, json);                      break;                  } @@ -487,12 +526,10 @@ namespace NProtobufJson {              PrintSingleField(proto, field, json, key);      } -    void TProto2JsonPrinter::Print(const Message& proto, IJsonOutput& json, bool closeMap) { +    void TProto2JsonPrinter::PrintFields(const Message& proto, IJsonOutput& json) {          const Descriptor* descriptor = proto.GetDescriptor();          Y_ASSERT(descriptor); -        json.BeginObject(); -          // Iterate over all non-extension fields          for (int f = 0, endF = descriptor->field_count(); f < endF; ++f) {              const FieldDescriptor* field = descriptor->field(f); @@ -518,6 +555,12 @@ namespace NProtobufJson {                  }              }          } +    } + +    void TProto2JsonPrinter::Print(const Message& proto, IJsonOutput& json, bool closeMap) { +        json.BeginObject(); + +        PrintFields(proto, json);          if (closeMap) {              json.EndObject(); diff --git a/library/cpp/protobuf/json/proto2json_printer.h b/library/cpp/protobuf/json/proto2json_printer.h index a1278193869..360e66ad2f6 100644 --- a/library/cpp/protobuf/json/proto2json_printer.h +++ b/library/cpp/protobuf/json/proto2json_printer.h @@ -60,6 +60,9 @@ namespace NProtobufJson {          template <class T>          bool NeedStringifyNumber(T value) const; +        bool TryPrintAny(const NProtoBuf::Message& proto, IJsonOutput& json); +        void PrintFields(const NProtoBuf::Message& proto, IJsonOutput& json); +      protected:          const TProto2JsonConfig& Config;          TString TmpBuf; diff --git a/library/cpp/protobuf/json/ut/proto2json_ut.cpp b/library/cpp/protobuf/json/ut/proto2json_ut.cpp index 80dae6f01d8..9b74e737523 100644 --- a/library/cpp/protobuf/json/ut/proto2json_ut.cpp +++ b/library/cpp/protobuf/json/ut/proto2json_ut.cpp @@ -1143,4 +1143,20 @@ Y_UNIT_TEST(TestFloatToString) {  #undef TEST_SINGLE  } // TestFloatToString +Y_UNIT_TEST(TestAny) { +    TProto2JsonConfig config; +    config.SetConvertAny(true); + +    TString modelStr(R"_({"Any":{"@type":"type.googleapis.com/NProtobufJsonTest.TFlatOptional","String":"value\""}})_"); + +    TFlatOptional proto; +    proto.SetString(R"_(value")_"); +    TContainsAny protoWithAny; +    protoWithAny.MutableAny()->PackFrom(proto); + +    TStringStream jsonStr; +    UNIT_ASSERT_NO_EXCEPTION(Proto2Json(protoWithAny, jsonStr, config)); +    UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr); +} +  } // TProto2JsonTest diff --git a/library/cpp/protobuf/json/ut/test.proto b/library/cpp/protobuf/json/ut/test.proto index 1f8487521be..0e40f1e4690 100644 --- a/library/cpp/protobuf/json/ut/test.proto +++ b/library/cpp/protobuf/json/ut/test.proto @@ -1,5 +1,6 @@  package NProtobufJsonTest; +import "google/protobuf/any.proto";  import "google/protobuf/duration.proto";  import "google/protobuf/timestamp.proto"; @@ -230,3 +231,7 @@ message TCustomJsonEnumValue {  extend TExtensionField {    optional int32 bar = 123;  } + +message TContainsAny { +    optional google.protobuf.Any Any = 1; +}  | 
