diff options
author | lavv17 <lavv17@yandex-team.com> | 2024-02-15 13:16:43 +0300 |
---|---|---|
committer | lavv17 <lavv17@yandex-team.com> | 2024-02-15 13:36:35 +0300 |
commit | 524319c9b011a50744ee1c873e7292b615052cd6 (patch) | |
tree | a7c52f035a4a86d558881e918a9526b37c405b8a | |
parent | cbb28d478883b8acc82a4f6e3f816eae1da92887 (diff) | |
download | ydb-524319c9b011a50744ee1c873e7292b615052cd6.tar.gz |
support Any in Proto2Json
31e18f04efdf8642428d4ab8ec8c87b4101f5ff2
-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 eee047e155..d17ac7b15b 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 b2426f395a..bf0f9eb60d 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 a127819386..360e66ad2f 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 80dae6f01d..9b74e73752 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 1f8487521b..0e40f1e469 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; +} |