diff options
author | timuratshin <timuratshin@yandex-team.com> | 2025-06-17 11:39:01 +0300 |
---|---|---|
committer | timuratshin <timuratshin@yandex-team.com> | 2025-06-17 12:07:27 +0300 |
commit | 280fed21e0058de0be049996f68b10a336b69370 (patch) | |
tree | e52d71481779eee394217fe9d67eb5326c6da071 /library/cpp/protobuf/json | |
parent | de699c5726b134d10b3311deb0628fc74e82e877 (diff) | |
download | ydb-280fed21e0058de0be049996f68b10a336b69370.tar.gz |
Support google::protobuf::Struct and google::protobuf::Value in Json2Proto
Добавляем поддержку парсинга TJsonValue в google::protobuf::Struct и google::protobuf::Value
Сериализация в пути…
commit_hash:0815499b09ba8eeaf77dbda5ab5aced91f1e2474
Diffstat (limited to 'library/cpp/protobuf/json')
-rw-r--r-- | library/cpp/protobuf/json/json2proto.cpp | 53 | ||||
-rw-r--r-- | library/cpp/protobuf/json/ut/json2proto_ut.cpp | 79 |
2 files changed, 132 insertions, 0 deletions
diff --git a/library/cpp/protobuf/json/json2proto.cpp b/library/cpp/protobuf/json/json2proto.cpp index 823c471b967..a1d7e862ef0 100644 --- a/library/cpp/protobuf/json/json2proto.cpp +++ b/library/cpp/protobuf/json/json2proto.cpp @@ -7,6 +7,8 @@ #include <google/protobuf/util/time_util.h> #include <google/protobuf/message.h> #include <google/protobuf/descriptor.h> +#include <google/protobuf/struct.pb.h> + #include <util/generic/hash.h> #include <util/generic/maybe.h> @@ -517,6 +519,57 @@ namespace NProtobufJson { const google::protobuf::Descriptor* descriptor = proto.GetDescriptor(); Y_ASSERT(!!descriptor); + + if (descriptor->well_known_type() == google::protobuf::Descriptor::WELLKNOWNTYPE_STRUCT) { + Y_ENSURE(json.IsMap(), "Failed to merge json to proto for message: " << descriptor->full_name() << ", expected json map."); + google::protobuf::Struct msg; + for (const auto& [key, value] : json.GetMap()) { + google::protobuf::Value valueMsg; + MergeJson2Proto(value, valueMsg, config); + (*msg.mutable_fields())[key] = std::move(valueMsg); + } + proto.GetReflection()->Swap(&proto, &msg); + return; + } else if (descriptor->well_known_type() == google::protobuf::Descriptor::WELLKNOWNTYPE_VALUE) { + google::protobuf::Value msg; + switch (json.GetType()) { + case NJson::JSON_UNDEFINED: + break; + case NJson::JSON_NULL: + msg.set_null_value({}); + break; + case NJson::JSON_BOOLEAN: + msg.set_bool_value(json.GetBoolean()); + break; + case NJson::JSON_INTEGER: + case NJson::JSON_DOUBLE: + case NJson::JSON_UINTEGER: + msg.set_number_value(json.GetDouble()); + break; + case NJson::JSON_STRING: + msg.set_string_value(json.GetString()); + break; + case NJson::JSON_MAP: + { + auto* structValue = msg.mutable_struct_value(); + MergeJson2Proto(json, *structValue, config); + break; + } + case NJson::JSON_ARRAY: + { + auto* arrayValue = msg.mutable_list_value(); + const auto& jsonArray = json.GetArray(); + arrayValue->mutable_values()->Reserve(jsonArray.size()); + for (const auto& item : jsonArray) { + MergeJson2Proto(item, *arrayValue->add_values(), config); + } + break; + } + } + + proto.GetReflection()->Swap(&proto, &msg); + return; + } Y_ENSURE(json.IsMap(), "Failed to merge json to proto for message: " << descriptor->full_name() << ", expected json map."); for (int f = 0, endF = descriptor->field_count(); f < endF; ++f) { diff --git a/library/cpp/protobuf/json/ut/json2proto_ut.cpp b/library/cpp/protobuf/json/ut/json2proto_ut.cpp index 7b3e829868e..1172b2b8db6 100644 --- a/library/cpp/protobuf/json/ut/json2proto_ut.cpp +++ b/library/cpp/protobuf/json/ut/json2proto_ut.cpp @@ -2,6 +2,8 @@ #include "proto.h" #include "proto2json.h" +#include <google/protobuf/struct.pb.h> + #include <library/cpp/protobuf/json/ut/test.pb.h> #include <library/cpp/json/json_value.h> @@ -1186,4 +1188,81 @@ Y_UNIT_TEST(TestSimplifiedTimestamp) { UNIT_ASSERT_EQUAL(NProtoInterop::CastFromProto(simpleTimestamp.GetTimestamp()), TInstant::ParseIso8601("2014-08-26T15:52:15Z")); } // TestSimplifiedTimestamp +Y_UNIT_TEST(TestValue) { + { + NJson::TJsonValue json = 100.0; + google::protobuf::Value value; + NProtobufJson::Json2Proto(json, value); + UNIT_ASSERT(value.has_number_value()); + UNIT_ASSERT_EQUAL(value.number_value(), 100.0); + } + { + NJson::TJsonValue json = 100LL; + google::protobuf::Value value; + NProtobufJson::Json2Proto(json, value); + UNIT_ASSERT(value.has_number_value()); + UNIT_ASSERT_EQUAL(value.number_value(), 100.0); + } + { + NJson::TJsonValue json = 100ULL; + google::protobuf::Value value; + NProtobufJson::Json2Proto(json, value); + UNIT_ASSERT(value.has_number_value()); + UNIT_ASSERT_EQUAL(value.number_value(), 100.0); + } + { + NJson::TJsonValue json = "TestString"; + google::protobuf::Value value; + NProtobufJson::Json2Proto(json, value); + UNIT_ASSERT(value.has_string_value()); + UNIT_ASSERT_EQUAL(value.string_value(), "TestString"); + } + { + NJson::TJsonValue json; + json.AppendValue("TestString"); + json.AppendValue(2); + google::protobuf::Value value; + NProtobufJson::Json2Proto(json, value); + UNIT_ASSERT(value.has_list_value()); + const auto& list = value.list_value().values(); + UNIT_ASSERT_EQUAL(list.size(), 2); + UNIT_ASSERT(list.Get(0).has_string_value()); + UNIT_ASSERT_EQUAL(list.Get(0).string_value(), "TestString"); + UNIT_ASSERT(list.Get(1).has_number_value()); + UNIT_ASSERT_EQUAL(list.Get(1).number_value(), 2.0); + } + { + NJson::TJsonValue json; + json["str"] = "TestString"; + json["int"] = 2; + google::protobuf::Value value; + NProtobufJson::Json2Proto(json, value); + UNIT_ASSERT(value.has_struct_value()); + const auto& fields = value.struct_value().fields(); + UNIT_ASSERT_EQUAL(fields.size(), 2); + + UNIT_ASSERT(fields.at("str").has_string_value()); + UNIT_ASSERT_EQUAL(fields.at("str").string_value(), "TestString"); + + UNIT_ASSERT(fields.at("int").has_number_value()); + UNIT_ASSERT_EQUAL(fields.at("int").number_value(), 2.0); + } +} // TestValue + +Y_UNIT_TEST(TestStruct) { + NJson::TJsonValue json; + json["str"] = "TestString"; + json["int"] = 2; + google::protobuf::Struct structProto; + NProtobufJson::Json2Proto(json, structProto); + + const auto& fields = structProto.fields(); + UNIT_ASSERT_EQUAL(fields.size(), 2); + UNIT_ASSERT(fields.at("str").has_string_value()); + UNIT_ASSERT_EQUAL(fields.at("str").string_value(), "TestString"); + + UNIT_ASSERT(fields.at("int").has_number_value()); + UNIT_ASSERT_EQUAL(fields.at("int").number_value(), 2.0); +} // TestStruct + } // TJson2ProtoTest |